@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.
- package/Math/arc-cdf-points.js +20 -0
- package/Math/arc-generate-points copy.js +1 -0
- package/Math/arc.js +21 -8
- package/Math/circle.js +35 -16
- package/Math/templete-shapes/grid-visually-equal.js +66 -0
- package/altitude-locator/plugin.js +3 -2
- package/bearing-line/plugin.js +1 -2
- package/circle-line-chain/plugin.js +4 -7
- package/compass-rose/compass-rose-padding-flat.js +12 -0
- package/package.json +1 -1
- package/programs/line-on-globe/degree-padding-around-circle-3d.js +1 -1
- package/programs/line-on-globe/linestrip/linestrip.js +5 -3
- package/programs/line-on-globe/naive-accurate-flexible.js +23 -16
- package/programs/picking/pickable-renderer.js +1 -2
- package/programs/rings/partial-ring/piece-of-pie copy.js +286 -0
- package/programs/rings/partial-ring/piece-of-pie.js +26 -13
- package/programs/totems/camerauniformblock.js +1 -1
- package/programs/totems/index.js +1 -1
- package/range-tools-on-terrain/bearing-line/adapters.js +111 -0
- package/range-tools-on-terrain/bearing-line/plugin.js +360 -0
- package/range-tools-on-terrain/circle-line-chain/adapters.js +83 -0
- package/range-tools-on-terrain/circle-line-chain/chain-list-map.js +351 -0
- package/range-tools-on-terrain/circle-line-chain/plugin.js +389 -0
- package/range-tools-on-terrain/circle-line-chain/types.js +1 -0
- package/range-tools-on-terrain/range-ring/adapters.js +25 -0
- package/range-tools-on-terrain/range-ring/plugin.js +31 -0
- package/range-tools-on-terrain/range-ring/types.js +1 -0
- package/rangerings/plugin.js +7 -11
- package/semiplugins/lightweight/line-plugin.js +195 -0
- package/semiplugins/lightweight/piece-of-pie-plugin.js +175 -0
- package/semiplugins/shape-on-terrain/arc-plugin.js +368 -0
- package/{shape-on-terrain/circle/plugin.js → semiplugins/shape-on-terrain/circle-plugin.js} +67 -38
- package/semiplugins/shape-on-terrain/derived/padding-plugin.js +96 -0
- package/semiplugins/type.js +1 -0
- package/types.js +0 -11
- package/util/account/create-buffermap-orchastration.js +39 -0
- package/util/account/single-attribute-buffer-management/buffer-orchestrator.js +14 -3
- package/util/check/typecheck.js +15 -1
- package/util/geometry/index.js +3 -2
- package/util/gl-util/buffer/attribute-loader.js +2 -5
- package/util/gl-util/draw-options/methods.js +4 -5
- package/util/webglobjectbuilders.js +4 -9
- package/write-text/context-text3.js +17 -0
- package/write-text/context-text3old.js +152 -0
- package/programs/line-on-globe/circle-accurate.js +0 -176
- package/programs/line-on-globe/circle.js +0 -166
- package/programs/line-on-globe/to-the-surface.js +0 -111
- package/programs/totems/canvas-webglobe-info1.js +0 -106
- package/shape-on-terrain/arc/naive/plugin.js +0 -250
- package/util/check/get.js +0 -14
- package/util/gl-util/buffer/types.js +0 -1
- package/util/gl-util/draw-options/types.js +0 -15
- package/util/webglobjectbuilders1.js +0 -219
- /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
|
|
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,
|
|
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
|
-
|
|
115
|
-
|
|
112
|
+
for (let i = 0; i < CIRCLE_POINTS_COUNT; i++) {
|
|
113
|
+
_colorArray.set(item.color, i * 4);
|
|
114
|
+
}
|
|
116
115
|
}
|
|
117
116
|
else {
|
|
118
|
-
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
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.
|
|
151
|
+
this.__buildStaticCircles(fillStaticKeys);
|
|
152
|
+
this.globe.DrawRender();
|
|
140
153
|
}
|
|
141
|
-
|
|
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
|
-
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
console.warn(`CircleOnTerrainPlugin: Circle ${key} not found in circleMap. Cannot delete.`);
|
|
146
168
|
}
|
|
147
169
|
}
|
|
148
|
-
|
|
149
|
-
|
|
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
|
|
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 }, _
|
|
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 }, _
|
|
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
|
}
|