@pirireis/webglobeplugins 0.12.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 (68) 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-cdf-points.js +0 -2
  5. package/Math/circle.js +35 -16
  6. package/Math/templete-shapes/grid-visually-equal.js +66 -0
  7. package/altitude-locator/plugin.js +3 -2
  8. package/bearing-line/plugin.js +1 -2
  9. package/circle-line-chain/plugin.js +4 -7
  10. package/compass-rose/compass-rose-padding-flat.js +12 -0
  11. package/package.json +1 -1
  12. package/programs/line-on-globe/degree-padding-around-circle-3d.js +1 -1
  13. package/programs/line-on-globe/linestrip/data.js +4 -0
  14. package/programs/line-on-globe/{linestrip.js → linestrip/linestrip.js} +37 -35
  15. package/programs/line-on-globe/naive-accurate-flexible.js +23 -16
  16. package/programs/picking/pickable-renderer.js +1 -2
  17. package/programs/rings/distancering/circleflatprogram.js +116 -120
  18. package/programs/rings/distancering/circlepaddingfreeangleprogram.js +1 -1
  19. package/programs/rings/distancering/circlepaddysharedbuffer.js +368 -354
  20. package/programs/rings/distancering/index.js +6 -5
  21. package/programs/rings/distancering/paddyflatprogram.js +127 -136
  22. package/programs/rings/distancering/paddyflatprogram2d.js +129 -138
  23. package/programs/rings/distancering/paddyflatprogram3d.js +128 -136
  24. package/programs/rings/partial-ring/piece-of-pie copy.js +286 -0
  25. package/programs/rings/partial-ring/piece-of-pie.js +26 -13
  26. package/programs/totems/camerauniformblock.js +1 -1
  27. package/programs/totems/index.js +1 -1
  28. package/programs/vectorfields/logics/pixelbased.js +5 -21
  29. package/range-tools-on-terrain/bearing-line/adapters.js +111 -0
  30. package/range-tools-on-terrain/bearing-line/plugin.js +360 -0
  31. package/range-tools-on-terrain/bearing-line/types.js +1 -0
  32. package/range-tools-on-terrain/circle-line-chain/adapters.js +83 -0
  33. package/range-tools-on-terrain/circle-line-chain/chain-list-map.js +351 -0
  34. package/range-tools-on-terrain/circle-line-chain/plugin.js +389 -0
  35. package/range-tools-on-terrain/circle-line-chain/types.js +1 -0
  36. package/range-tools-on-terrain/range-ring/adapters.js +25 -0
  37. package/range-tools-on-terrain/range-ring/plugin.js +31 -0
  38. package/range-tools-on-terrain/range-ring/types.js +1 -0
  39. package/rangerings/plugin.js +7 -11
  40. package/semiplugins/lightweight/line-plugin.js +195 -0
  41. package/semiplugins/lightweight/piece-of-pie-plugin.js +175 -0
  42. package/semiplugins/shape-on-terrain/arc-plugin.js +368 -0
  43. package/{shape-on-terrain/circle/plugin.js → semiplugins/shape-on-terrain/circle-plugin.js} +129 -68
  44. package/semiplugins/shape-on-terrain/derived/padding-plugin.js +96 -0
  45. package/semiplugins/type.js +1 -0
  46. package/types.js +0 -11
  47. package/util/account/create-buffermap-orchastration.js +39 -0
  48. package/util/account/index.js +2 -2
  49. package/util/account/single-attribute-buffer-management/buffer-manager.js +2 -3
  50. package/util/account/single-attribute-buffer-management/buffer-orchestrator.js +14 -3
  51. package/util/build-strategy/static-dynamic.js +1 -1
  52. package/util/check/typecheck.js +15 -1
  53. package/util/geometry/index.js +3 -2
  54. package/util/gl-util/buffer/attribute-loader.js +2 -5
  55. package/util/gl-util/draw-options/methods.js +4 -5
  56. package/util/webglobjectbuilders.js +4 -9
  57. package/write-text/context-text3.js +17 -0
  58. package/write-text/context-text3old.js +152 -0
  59. package/programs/line-on-globe/circle-accurate.js +0 -175
  60. package/programs/line-on-globe/circle.js +0 -164
  61. package/programs/line-on-globe/to-the-surface.js +0 -109
  62. package/programs/rings/distancering/shader.js +0 -1
  63. package/programs/totems/canvas-webglobe-info1.js +0 -106
  64. package/shape-on-terrain/arc/naive/plugin.js +0 -205
  65. package/util/check/get.js +0 -14
  66. package/util/gl-util/buffer/types.js +0 -1
  67. package/util/gl-util/draw-options/types.js +0 -15
  68. package/util/webglobjectbuilders1.js +0 -219
@@ -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
- import { LineStripProgramCache } from "../../programs/line-on-globe/linestrip";
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,6 +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);
55
+ const _colorArray = new Float32Array(4 * CIRCLE_POINTS_COUNT); // Used to store the color for each circle
53
56
  export class CircleOnTerrainPlugin {
54
57
  id;
55
58
  globe = null;
@@ -65,18 +68,120 @@ export class CircleOnTerrainPlugin {
65
68
  _vao = null;
66
69
  _dobuild = true; // This is used to trigger the build of circles when the camera position changes.
67
70
  _staticDynamicStrategy = null;
68
- constructor(id) {
71
+ _styleOptions = {
72
+ variativeColorsOn: false,
73
+ defaultColor: [0.1, 0.1, 0.1, 1], // Default color in RGBA format
74
+ defaultHeightFromGroundIn3D: 30.0
75
+ };
76
+ constructor(id, styleOptions = {}) {
69
77
  this.id = id;
78
+ this._styleOptions = { ...this._styleOptions, ...styleOptions };
79
+ this._styleOptions.defaultColor = new Float32Array(this._styleOptions.defaultColor);
70
80
  }
81
+ init(globe, gl) {
82
+ this.globe = globe;
83
+ this.gl = gl;
84
+ // Initialize the program cache for line strip rendering.
85
+ this._staticDynamicStrategy = new StaticDynamicStrategy(globe, ACTIVATE_DYNAMIC_STRATEGY_AT_LEVEL);
86
+ this.lineProgram = LineStripProgramCache.get(globe);
87
+ // const g3D = globe3Dcoordinates(globe, 30);
88
+ const g2D = globe2Dcoordinates(globe);
89
+ // Initialize with a reasonable initial capacity to prevent buffer size issues
90
+ const initialCapacity = 100; // Start with capacity for 100 circles
91
+ this.bufferManagerMap.set("position3d", {
92
+ bufferManager: new BufferManager(gl, (CIRCLE_POINTS_COUNT + 1) * 3, { initialCapacity }), // plus 1 is for butting linestrips
93
+ adaptor: (item) => {
94
+ const { longLatArr, height = this._styleOptions.defaultHeightFromGroundIn3D } = item;
95
+ const result = globe3Dcoordinates(globe, height)(longLatArr, { paddingCount: 1, paddingValue: NaN });
96
+ return result;
97
+ }
98
+ });
99
+ this.bufferManagerMap.set("position2d", {
100
+ bufferManager: new BufferManager(gl, (CIRCLE_POINTS_COUNT + 1) * 2, { initialCapacity }),
101
+ adaptor: (item) => {
102
+ const { longLatArr } = item;
103
+ const result = g2D(longLatArr, { paddingCount: 1, paddingValue: NaN });
104
+ return result;
105
+ }
106
+ });
107
+ if (this._styleOptions.variativeColorsOn) {
108
+ this.bufferManagerMap.set("color", {
109
+ bufferManager: new BufferManager(gl, (CIRCLE_POINTS_COUNT + 1) * 4, { initialCapacity }),
110
+ adaptor: (item) => {
111
+ if (item.color) {
112
+ for (let i = 0; i < CIRCLE_POINTS_COUNT; i++) {
113
+ _colorArray.set(item.color, i * 4);
114
+ }
115
+ }
116
+ else {
117
+ for (let i = 0; i < CIRCLE_POINTS_COUNT; i++) {
118
+ _colorArray.set(this._styleOptions.defaultColor, i * 4);
119
+ }
120
+ }
121
+ return _colorArray;
122
+ }
123
+ });
124
+ }
125
+ this._vao = this.lineProgram.createVAO(createBufferAndReadInfo(this.bufferManagerMap.get("position3d")?.bufferManager.buffer), createBufferAndReadInfo(this.bufferManagerMap.get("position2d")?.bufferManager.buffer), this._styleOptions.variativeColorsOn ?
126
+ createBufferAndReadInfo(this.bufferManagerMap.get("color")?.bufferManager.buffer) : null);
127
+ this._circleUBOHandler = this.lineProgram.createUBO();
128
+ this._cameraUniformBlock = CameraUniformBlockTotemCache.get(globe);
129
+ }
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
+ }
150
+ }
151
+ this.__buildStaticCircles(fillStaticKeys);
152
+ this.globe.DrawRender();
153
+ }
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);
162
+ for (const key of keys) {
163
+ if (this.circleMap.has(key)) {
164
+ this.circleMap.delete(key);
165
+ }
166
+ else {
167
+ console.warn(`CircleOnTerrainPlugin: Circle ${key} not found in circleMap. Cannot delete.`);
168
+ }
169
+ }
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();
179
+ }
180
+ // IMPLICIT METHODS
71
181
  _buildCircles() {
72
- //
73
182
  // @ts-ignore
74
- this.__buildCircles();
75
- return;
76
183
  this._staticDynamicStrategy?.updateState();
77
184
  const state = this._staticDynamicStrategy?.getState();
78
- if (state === StaticDynamicState.TO_STATIC)
79
- console.log("state", state);
80
185
  if (state === StaticDynamicState.TO_STATIC) {
81
186
  this.__buildStaticCircles();
82
187
  }
@@ -90,11 +195,12 @@ export class CircleOnTerrainPlugin {
90
195
  !bufferOrchestrator || !bufferManagerMap || !circleMap)
91
196
  throw new Error("Plugin not initialized properly");
92
197
  // unoptimized.. resets all circles.
93
- bufferOrchestrator.resetWithCapacity(bufferManagerMap, circleMap.size);
198
+ // bufferOrchestrator.resetWithCapacity(bufferManagerMap, circleMap.size);
94
199
  // Prepare the data for the buffers
95
200
  const data = [{
96
201
  key: "",
97
- longLatArr: []
202
+ longLatArr: [],
203
+ height: null
98
204
  }];
99
205
  const lookAtPosition = _cameraUniformBlock.getLookAtVector();
100
206
  const cameraPosition = _cameraUniformBlock.getNormalizedCameraVector();
@@ -102,13 +208,11 @@ export class CircleOnTerrainPlugin {
102
208
  vec3.add(cameraPosition, cameraPosition, lookAtPosition);
103
209
  vec3.normalize(cameraPosition, cameraPosition);
104
210
  const currentLOD = globe.api_GetCurrentLODWithDecimal();
105
- // const currentGeom = globe.api_GetCurrentGeometry();
106
211
  const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
107
212
  for (const [key, circle] of this.circleMap.entries()) {
108
- const [{ radius, center }, circleForAzimuthCalc] = circle;
213
+ const [{ radius, center, height = null }, circleForAzimuthCalc] = circle;
109
214
  const closestAzimuthAngle = CircleMethods.closestAzimuthAngle(circleForAzimuthCalc, cameraPosition);
110
215
  const stregthLevel = defineStregthLevel(currentLOD, radius);
111
- // console.log('DrawStregthLevel', stregthLevel, currentLOD, radius);
112
216
  if (stregthLevel < 0) {
113
217
  console.warn(`CircleOnTerrainPlugin: Circle ${key} has too small radius for current LOD ${currentLOD}. Skipping., radius: ${radius}, stregthLevel: ${stregthLevel}`);
114
218
  continue;
@@ -117,8 +221,9 @@ export class CircleOnTerrainPlugin {
117
221
  CircleCDF.globeFindPointByPolarHalfCircle(circlePointsLongLat, globe, center[0], center[1], radius, closestAzimuthAngle, templateAngles);
118
222
  data[0].key = key;
119
223
  data[0].longLatArr = circlePointsLongLat;
224
+ data[0].height = height;
120
225
  // Add to buffer orchestrator
121
- this.bufferOrchestrator.insertBulk(data, bufferManagerMap);
226
+ this.bufferOrchestrator.insertBulk(data, bufferManagerMap, ["position3d", "position2d"]);
122
227
  }
123
228
  }
124
229
  // this will be used to build static circles, which are not affected by camera position or LOD.
@@ -130,7 +235,9 @@ export class CircleOnTerrainPlugin {
130
235
  throw new Error("Plugin not initialized properly");
131
236
  const data = [{
132
237
  key: "",
133
- longLatArr: []
238
+ longLatArr: [],
239
+ height: null,
240
+ color: [1, 1, 1, 1]
134
241
  }];
135
242
  // ensure buffer orchestrotrator have enough capacity
136
243
  // all circles are build with even sampling, AttractionLevel = 0
@@ -140,10 +247,12 @@ export class CircleOnTerrainPlugin {
140
247
  const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
141
248
  bufferOrchestrator.resetWithCapacity(bufferManagerMap, circleMap.size);
142
249
  for (const [key, circle] of this.circleMap.entries()) {
143
- const [{ radius, center }, _] = circle;
250
+ const [{ radius, center, height = null, color = null }, _] = circle;
144
251
  CircleCDF.globeFindPointByPolarHalfCircle(circlePointsLongLat, globe, center[0], center[1], radius, zeroRotation, templateAngles);
145
252
  data[0].key = key;
146
253
  data[0].longLatArr = circlePointsLongLat;
254
+ data[0].height = height;
255
+ data[0].color = color || this._styleOptions.defaultColor;
147
256
  this.bufferOrchestrator.insertBulk(data, bufferManagerMap);
148
257
  }
149
258
  }
@@ -157,66 +266,18 @@ export class CircleOnTerrainPlugin {
157
266
  console.warn(`CircleOnTerrainPlugin: Circle ${key} not found in circleMap.`);
158
267
  continue;
159
268
  }
160
- const [{ radius, center }, _] = this.circleMap.get(key);
269
+ const [{ radius, center, height = null, color = null }, _] = this.circleMap.get(key);
161
270
  const circlePointsLongLat = new Float64Array((CIRCLE_POINTS_COUNT) * 2);
162
271
  CircleCDF.globeFindPointByPolarHalfCircle(circlePointsLongLat, globe, center[0], center[1], radius, zeroRotation, templateAngles);
163
272
  data[0].key = key;
164
273
  data[0].longLatArr = circlePointsLongLat;
274
+ data[0].height = height;
275
+ data[0].color = color || this._styleOptions.defaultColor;
165
276
  this.bufferOrchestrator.insertBulk(data, bufferManagerMap);
166
277
  }
167
278
  }
168
279
  }
169
- init(globe, gl) {
170
- this.globe = globe;
171
- this.gl = gl;
172
- // Initialize the program cache for line strip rendering.
173
- this._staticDynamicStrategy = new StaticDynamicStrategy(globe, 8);
174
- this.lineProgram = LineStripProgramCache.get(globe);
175
- const g3D = globe3Dcoordinates(globe, 30);
176
- const g2D = globe2Dcoordinates(globe);
177
- this.bufferManagerMap.set("position3d", {
178
- bufferManager: new BufferManager(gl, (CIRCLE_POINTS_COUNT + 1) * 3), // plus 1 is for butting linestrips
179
- adaptor: (item) => {
180
- const { longLatArr } = item;
181
- const result = g3D(longLatArr, { paddingCount: 1, paddingValue: NaN });
182
- return result;
183
- }
184
- });
185
- this.bufferManagerMap.set("position2d", {
186
- bufferManager: new BufferManager(gl, (CIRCLE_POINTS_COUNT + 1) * 2),
187
- adaptor: (item) => {
188
- const { longLatArr } = item;
189
- const result = g2D(longLatArr, { paddingCount: 1, paddingValue: NaN });
190
- return result;
191
- }
192
- });
193
- this._vao = this.lineProgram.createVAO(createBufferAndReadInfo(this.bufferManagerMap.get("position3d")?.bufferManager.buffer), createBufferAndReadInfo(this.bufferManagerMap.get("position2d")?.bufferManager.buffer), null, null, null);
194
- this._circleUBOHandler = this.lineProgram.createUBO();
195
- this._cameraUniformBlock = CameraUniformBlockTotemCache.get(globe);
196
- }
197
- insertCircle(key, longitude, latitude, radius) {
198
- const circle = {
199
- center: [longitude, latitude],
200
- radius: radius
201
- };
202
- const circleForAzimuthCalc = CircleMethods.createCircleClosestAzimuthAngleProperties(circle);
203
- this.circleMap.set(key, [circle, circleForAzimuthCalc]);
204
- // @ts-ignore
205
- if (this._staticDynamicStrategy.getState() === StaticDynamicState.STATIC) {
206
- this.__buildStaticCircles([key]);
207
- }
208
- this.globe?.DrawRender();
209
- }
210
- deleteCircle(keys) {
211
- for (const key of keys) {
212
- if (this.circleMap.has(key)) {
213
- this.circleMap.delete(key);
214
- this.globe?.DrawRender();
215
- }
216
- }
217
- this._dobuild = true;
218
- this.globe?.DrawRender();
219
- }
280
+ // GLOBE API INTERFACE
220
281
  draw3D() {
221
282
  const { _isFree, globe, gl, lineProgram, bufferOrchestrator, bufferManagerMap, _vao, _circleUBOHandler } = this;
222
283
  if (_isFree || !globe || !gl || !lineProgram || !bufferOrchestrator ||