@pirireis/webglobeplugins 0.16.4 → 0.16.7

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.
@@ -0,0 +1,370 @@
1
+ /**
2
+ * @author Toprak Ozturk
3
+ */
4
+ import { create as createArc, calculateZLimitPoint } from "../arc";
5
+ import { createUnitVectorFromLongLat, equals, length, vec3ToLongLatRadians } from "../vec3";
6
+ import { TILE_COUNTS } from "./zoom-catch";
7
+ import { pointsOnArc } from "../juction/arc-plane";
8
+ import { latToTileY, tileYtoLat } from "./methods";
9
+ import { isOnTileEdge } from "./methods";
10
+ import Delaunator from "delaunator";
11
+ // TODO:get rid of embedded lists. always flat list
12
+ const TILE_DEM_VERTEX_COUNT = 5; // 5x5 grid for DEM
13
+ const TILE_DEM_STEPCOUNT = TILE_DEM_VERTEX_COUNT - 1; // 4 inner divisions in each dimension
14
+ const _plane = /*@__PURE__*/ { normal: [0, 0, 0], distance: 0 };
15
+ const _resultPoints = /*@__PURE__*/ [[0, 0, 0], [0, 0, 0]];
16
+ function createShellPoints(triangleMeta) {
17
+ const arcs = triangleMeta.arcs;
18
+ const points = [
19
+ arcs[0].p0LongLat,
20
+ arcs[1].p0LongLat,
21
+ arcs[2].p0LongLat
22
+ ];
23
+ for (let i = 0; i < 3; i++) {
24
+ if (arcs[i].exceededLimit) {
25
+ if (arcs[i].exceededLimit !== undefined) {
26
+ const longLat = vec3ToLongLatRadians(arcs[i].exceededLimit);
27
+ points.push(longLat);
28
+ }
29
+ }
30
+ }
31
+ const center = [
32
+ points.reduce((sum, p) => sum + p[0], 0) / points.length,
33
+ points.reduce((sum, p) => sum + p[1], 0) / points.length
34
+ ];
35
+ const shellPoints = [];
36
+ for (let i = 0; i < points.length; i++) {
37
+ const p = points[i];
38
+ const x = (p[0] - center[0]) / 10;
39
+ const y = (p[1] - center[1]) / 10;
40
+ shellPoints.push([p[0] + x, p[1] + y]);
41
+ }
42
+ return shellPoints;
43
+ }
44
+ function createBBox(p1, p2, limitVec) {
45
+ if (limitVec) {
46
+ const limitLongLat = vec3ToLongLatRadians(limitVec);
47
+ console.log('Limit point found at:', limitLongLat, 'for p1:', p1, 'p2:', p2);
48
+ return {
49
+ min: [Math.min(p1[0], p2[0], limitLongLat[0]), Math.min(p1[1], p2[1], limitLongLat[1])],
50
+ max: [Math.max(p1[0], p2[0], limitLongLat[0]), Math.max(p1[1], p2[1], limitLongLat[1])],
51
+ };
52
+ }
53
+ return {
54
+ min: [Math.min(p1[0], p2[0]), Math.min(p1[1], p2[1])],
55
+ max: [Math.max(p1[0], p2[0]), Math.max(p1[1], p2[1])],
56
+ };
57
+ }
58
+ export function createTriangleTessellationMeta(p1, p2, p3) {
59
+ const p1v3 = createUnitVectorFromLongLat(p1);
60
+ const p2v3 = createUnitVectorFromLongLat(p2);
61
+ const p3v3 = createUnitVectorFromLongLat(p3);
62
+ const arc1 = createArc(p1v3, p2v3);
63
+ const arc2 = createArc(p2v3, p3v3);
64
+ const arc3 = createArc(p3v3, p1v3);
65
+ const limitVec = [0, 0, 0];
66
+ if (calculateZLimitPoint(arc1, limitVec)) {
67
+ arc1.exceededLimit = [limitVec[0], limitVec[1], limitVec[2]];
68
+ const longlat_ = vec3ToLongLatRadians(arc1.exceededLimit);
69
+ console.log('Arc 1 exceeded limit at:', longlat_.map(v => (v * 180 / Math.PI).toFixed(2)), 'rad:', arc1.exceededLimit);
70
+ }
71
+ arc1.bbox = createBBox(p1, p2, arc1.exceededLimit);
72
+ arc1.p0LongLat = p1;
73
+ arc1.p1LongLat = p2;
74
+ if (calculateZLimitPoint(arc2, limitVec)) {
75
+ arc2.exceededLimit = [limitVec[0], limitVec[1], limitVec[2]];
76
+ }
77
+ arc2.bbox = createBBox(p2, p3, arc2.exceededLimit);
78
+ arc2.p0LongLat = p2;
79
+ arc2.p1LongLat = p3;
80
+ if (calculateZLimitPoint(arc3, limitVec)) {
81
+ arc3.exceededLimit = [limitVec[0], limitVec[1], limitVec[2]];
82
+ }
83
+ arc3.bbox = createBBox(p3, p1, arc3.exceededLimit);
84
+ arc3.p0LongLat = p3;
85
+ arc3.p1LongLat = p1;
86
+ const bbox = {
87
+ min: [
88
+ Math.min(arc1.bbox.min[0], arc2.bbox.min[0], arc3.bbox.min[0]),
89
+ Math.min(arc1.bbox.min[1], arc2.bbox.min[1], arc3.bbox.min[1])
90
+ ],
91
+ max: [
92
+ Math.max(arc1.bbox.max[0], arc2.bbox.max[0], arc3.bbox.max[0]),
93
+ Math.max(arc1.bbox.max[1], arc2.bbox.max[1], arc3.bbox.max[1])
94
+ ],
95
+ };
96
+ const meta = {
97
+ arcs: [arc1, arc2, arc3],
98
+ bbox
99
+ };
100
+ showMeta(meta);
101
+ meta.shellPoints = createShellPoints(meta);
102
+ return meta;
103
+ }
104
+ function showMeta(triangleMeta) {
105
+ for (let i = 0; i < 3; i++) {
106
+ const arc = triangleMeta.arcs[i];
107
+ console.log(`Arc ${i} from ${showLongLatRadian(arc.p0LongLat)} to ${showLongLatRadian(arc.p1LongLat)}, bbox: min(${showLongLatRadian(arc.bbox.min)}) max(${showLongLatRadian(arc.bbox.max)})`);
108
+ if (arc.exceededLimit) {
109
+ console.log(`Exceeded limit at ${showLongLatRadian(vec3ToLongLatRadians(arc.exceededLimit))}`);
110
+ }
111
+ }
112
+ console.log(`Triangle BBOX: min(${showLongLatRadian(triangleMeta.bbox.min)}) max(${showLongLatRadian(triangleMeta.bbox.max)})`);
113
+ }
114
+ /**
115
+ *
116
+ * @param triangleMeta
117
+ * @param zoom
118
+ * @param angle
119
+ * @param dimension false for longitude (meridian) true for latitude (parallel)
120
+ */
121
+ function getPoints(triangleMeta, angle, dimension) {
122
+ // console.log("getPoints called with angle:", angle * 180 / Math.PI, "dimension:", dimension ? 'latitude' : 'longitude');
123
+ // find which arcs are cut by plane
124
+ const radians = angle;
125
+ if (dimension) {
126
+ _plane.normal[0] = 0;
127
+ _plane.normal[1] = 0;
128
+ _plane.normal[2] = 1;
129
+ _plane.distance = Math.sin(radians);
130
+ }
131
+ else {
132
+ _plane.normal[0] = Math.sin(radians);
133
+ _plane.normal[1] = -Math.cos(radians);
134
+ _plane.normal[2] = 0;
135
+ _plane.distance = 0;
136
+ }
137
+ let result = [];
138
+ // Add debugging
139
+ let resultsFromDistinctArcs = 0;
140
+ for (let i = 0; i < 3; i++) {
141
+ const arc = triangleMeta.arcs[i];
142
+ const coordIndex = dimension ? 1 : 0;
143
+ const minCoord = arc.bbox.min[coordIndex];
144
+ const maxCoord = arc.bbox.max[coordIndex];
145
+ if (minCoord > angle || maxCoord < angle) {
146
+ continue; // arc is out of range
147
+ }
148
+ const count = pointsOnArc(arc, _plane, _resultPoints);
149
+ if (count === 1) {
150
+ result.push([..._resultPoints[0]]);
151
+ }
152
+ else if (count === 2) {
153
+ // throw new Error('Unexpected 2 cut points on arc, should be max 1'); // TODO DELETE this line later
154
+ result.push([..._resultPoints[0]]);
155
+ result.push([..._resultPoints[1]]); // TODO: this is a fix for a bug, need to investigate later
156
+ }
157
+ resultsFromDistinctArcs += 1;
158
+ }
159
+ if (resultsFromDistinctArcs === 3) {
160
+ result = filterDuplicate(result);
161
+ }
162
+ if (result.length !== 2 && result.length !== 4) {
163
+ // TODO: THERE is a case where 4 points are found.
164
+ // this happens when two arcs has limit and share space in Z dimension
165
+ console.log("ERROR");
166
+ const text = 'Angle:' + angle + ' dimension:' + (dimension ? 'latitude' : 'longitude') + "\n" +
167
+ 'Result points count:' + result.length + "\n" +
168
+ "bbox:" + triangleMeta.bbox.min[0] * 180 / Math.PI + ", " + triangleMeta.bbox.min[1] * 180 / Math.PI + ", " + triangleMeta.bbox.max[0] * 180 / Math.PI + ", " + triangleMeta.bbox.max[1] * 180 / Math.PI + "\n";
169
+ showMeta(triangleMeta);
170
+ for (let res of result) {
171
+ const ll = vec3ToLongLatRadians(res);
172
+ console.log("Point: " + ll[0] * 180 / Math.PI + ", " + ll[1] * 180 / Math.PI + "\n");
173
+ }
174
+ throw new Error(`Unexpected cut count for tile cut, got: ${result.length}, angle: ${angle * 180 / Math.PI}, dimension: ${dimension ? 'latitude' : 'longitude'} \n` + text);
175
+ }
176
+ // TODO: i want to see it delete later
177
+ if (result.length === 4) {
178
+ console.warn("Warning: 4 cut points found on triangle for angle:", angle * 180 / Math.PI, "dimension:", dimension ? 'latitude' : 'longitude', "points:", result);
179
+ }
180
+ result.sort((a, b) => {
181
+ if (dimension) {
182
+ return a[1] - b[1]; // sort by y for longitude cuts
183
+ }
184
+ else {
185
+ return a[0] - b[0]; // sort by x for latitude cuts
186
+ }
187
+ });
188
+ return result;
189
+ }
190
+ function getEdgePoints(triangleMeta) {
191
+ const points = [
192
+ triangleMeta.arcs[0].p0,
193
+ triangleMeta.arcs[1].p0,
194
+ triangleMeta.arcs[2].p0,
195
+ ];
196
+ for (let i = 0; i < 3; i++) {
197
+ if (triangleMeta.arcs[i].exceededLimit) {
198
+ points.push(triangleMeta.arcs[i].exceededLimit);
199
+ }
200
+ }
201
+ return points;
202
+ }
203
+ // TODO: EDGES NEED ! LEVEL MORE ZOOM LEVEL OF RESOLUTION as THEY CAN BE NEIGHBOURS OF HIGHER ZOOM LEVEL TILES....
204
+ // simple strategy: get max zoom level of neighbour, add edge cuts based on that zoom level, do not fill inner points.
205
+ // partialTessellation cure this problem automatically
206
+ export function getAllPoints(triangleMeta, zoom, innerCuts = TILE_DEM_STEPCOUNT) {
207
+ // TODO: lonLengthRadian and latInnerStep might be change. Dynamic zoom level will show if needed
208
+ const points = [];
209
+ const longLatPoints = [];
210
+ // CALCULATE INFORMATION NEEDED FOR CUTTING
211
+ const tileCount = TILE_COUNTS[zoom];
212
+ const lonLengthRadian = 2 * Math.PI / tileCount / innerCuts; // inner step
213
+ const startMeridianRadian = triangleMeta.bbox.min[0];
214
+ const endMeridianRadian = triangleMeta.bbox.max[0];
215
+ const startParallelRadian = triangleMeta.bbox.min[1];
216
+ const endParallelRadian = triangleMeta.bbox.max[1];
217
+ // GET EDGE POINTS
218
+ const edgePoints = getEdgePoints(triangleMeta);
219
+ const shellPoints = triangleMeta.shellPoints;
220
+ for (let i = 0; i < edgePoints.length; i++) {
221
+ const longLat = vec3ToLongLatRadians(edgePoints[i]);
222
+ longLatPoints.push(...shellPoints[i]);
223
+ longLatPoints.push(...longLat);
224
+ points.push(0, 0, 0);
225
+ points.push(...edgePoints[i]);
226
+ }
227
+ // GET ALL PARRALLEL CUTS AND FILL MIDDLE POINTS
228
+ // how to calculate parallel tiles in range of bbox
229
+ const startTileY = latToTileY(startParallelRadian, zoom);
230
+ const endTileY = latToTileY(endParallelRadian, zoom);
231
+ const latInnerStep = 1 / innerCuts;
232
+ let currentY = startTileY - Math.abs(startTileY % latInnerStep);
233
+ if (currentY === startTileY)
234
+ currentY -= latInnerStep; // since start point is already added
235
+ let latCutCount = 0;
236
+ while (currentY > endTileY) {
237
+ const lat = tileYtoLat(currentY, zoom);
238
+ const concurances = getPoints(triangleMeta, lat, true);
239
+ for (let i = 0; i < concurances.length; i += 2) {
240
+ const p0 = concurances[i];
241
+ const p1 = concurances[i + 1];
242
+ points.push(...p0);
243
+ points.push(...p1);
244
+ const p0LongLat = vec3ToLongLatRadians(p0);
245
+ const p1LongLat = vec3ToLongLatRadians(p1);
246
+ longLatPoints.push(...p0LongLat);
247
+ longLatPoints.push(...p1LongLat);
248
+ fillBetweenInParallels(lat, p0LongLat, p1LongLat, lonLengthRadian, points, longLatPoints);
249
+ if (length(p0) < 0.99 || length(p1) < 0.99 || length(p0) > 1.01 || length(p1) > 1.01) {
250
+ console.warn("Warning: Cut point is not on unit sphere!", length(p0), length(p1));
251
+ }
252
+ }
253
+ currentY -= latInnerStep;
254
+ latCutCount++;
255
+ }
256
+ let currentLong = startMeridianRadian - startMeridianRadian % lonLengthRadian;
257
+ if (currentLong === startMeridianRadian)
258
+ currentLong += lonLengthRadian; // since start point is already added
259
+ while (currentLong < endMeridianRadian) {
260
+ const [p0, p1] = getPoints(triangleMeta, currentLong, false);
261
+ const p0LongLat = vec3ToLongLatRadians(p0);
262
+ const p1LongLat = vec3ToLongLatRadians(p1);
263
+ if (!isOnTileEdge(p0LongLat, zoom)) {
264
+ points.push(...p0);
265
+ longLatPoints.push(...p0LongLat);
266
+ }
267
+ if (!isOnTileEdge(p1LongLat, zoom)) {
268
+ points.push(...p1);
269
+ longLatPoints.push(...p1LongLat);
270
+ }
271
+ currentLong += lonLengthRadian;
272
+ }
273
+ const delaunator = new Delaunator(longLatPoints);
274
+ let indices = delaunator.triangles;
275
+ const edgeIndexes = shellPoints.map((e, index) => index * 2); // edge points are always first points in list
276
+ indices = filteroutEdgeConnections(indices, edgeIndexes);
277
+ rotateIndices(indices);
278
+ return { vec3s: new Float32Array(points), longLats: new Float32Array(longLatPoints), indices: indices };
279
+ }
280
+ function fillBetweenInParallels(lat, p1, p2, step, fillVec3Arr, longLatPoints) {
281
+ // return;
282
+ // const start = Math.min(p1[0], p2[0]);
283
+ // const end = Math.max(p1[0], p2[0]);
284
+ const start = p1[0];
285
+ const end = p2[0];
286
+ // console.log("start:", start * 180 / Math.PI, "end:", end * 180 / Math.PI, "lat:", lat * 180 / Math.PI);
287
+ let current = start - (start % step);
288
+ while (current < end) {
289
+ const item = [current, lat];
290
+ fillVec3Arr.push(...createUnitVectorFromLongLat(item));
291
+ longLatPoints.push(...item);
292
+ current += step;
293
+ }
294
+ }
295
+ function filterDuplicate(vec3s) {
296
+ const result = [];
297
+ let dublicate = false;
298
+ for (let i = 0; i < vec3s.length; i++) {
299
+ for (let j = 0; j < result.length; j++) {
300
+ if (equals(vec3s[i], result[j])) {
301
+ dublicate = true;
302
+ break;
303
+ }
304
+ }
305
+ if (!dublicate) {
306
+ result.push(vec3s[i]);
307
+ }
308
+ }
309
+ return result;
310
+ }
311
+ function showLongLatRadian(longLat) {
312
+ return `(${(longLat[0] * 180 / Math.PI).toFixed(2)}°, ${(longLat[1] * 180 / Math.PI).toFixed(2)}°)`;
313
+ }
314
+ function rotateIndices(indices) {
315
+ const len = indices.length / 3;
316
+ let hold;
317
+ for (let i = 0; i < len; i++) {
318
+ hold = indices[i * 3];
319
+ indices[i * 3] = indices[i * 3 + 1];
320
+ indices[i * 3 + 1] = hold;
321
+ }
322
+ return indices;
323
+ }
324
+ // This method for removing external edge connections. The connections are unnecessary and cause a veil descending to the center of sphere from the edges
325
+ function filteroutEdgeConnections(indexes, filterOutIndexes) {
326
+ const length = indexes.length / 3;
327
+ const result = [];
328
+ for (let i = 0; i < length; i++) {
329
+ let pass = false;
330
+ for (let filterIndex of filterOutIndexes) {
331
+ if (indexes[i * 3] === filterIndex || indexes[i * 3 + 1] === filterIndex || indexes[i * 3 + 2] === filterIndex) {
332
+ pass = true;
333
+ break;
334
+ }
335
+ }
336
+ if (pass)
337
+ continue;
338
+ result.push(indexes[i * 3], indexes[i * 3 + 1], indexes[i * 3 + 2]);
339
+ }
340
+ return new Uint32Array(result);
341
+ }
342
+ /**
343
+ * @unlockedPerk cache
344
+ * final outpout can be saved on a hashmap since this triangles are static
345
+ */
346
+ function shredTriangleTessellationMeta(triangleMeta, zoomLevel) {
347
+ /**
348
+ * What if tile is covered by the curve of the limit of a single arc.
349
+ */
350
+ const result = [];
351
+ // cut triangleMeta into smaller triangles based on zoom level...
352
+ return result;
353
+ }
354
+ /**
355
+ * @lockedPerk cache
356
+ *
357
+ * cache can be applied at tile triangle intersection level;
358
+ *
359
+ * @unlockedPerk smoothZoomTransition
360
+ *
361
+ * @puzzle triangle should be covered without duplicate points. A tile can be covered by a bigger one.
362
+ * @solution bbox cuts:
363
+ * Ax 1 x x is higher zoom level tile, A is a tile that covers it. 1 2 3 should be asked with A zoom level.
364
+ * AA -> Problem1: 1 2 3 x will have edge points duplicated
365
+ * 2 3 p1 sol1: edges can be taged, or added separately by and algorithm that only adds edge poitns.
366
+ *
367
+ * still all triangles should have some sort of cached tessellation to fast render on rapit earth rotation
368
+ */
369
+ // function partialTessellation(triangleMeta: TriangleTessellationMeta, limits: BBox[], zoomLevel: number, innerCuts: number): { vec3s: Float32Array, longLats: Float32Array, indices: Uint32Array } {
370
+ // }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @author Toprak Ozturk
3
+ *
4
+ */
5
+ import { createTriangleTessellationMeta, getAllPoints } from "./triangle-tessellation-meta";
6
+ export function test1(zoomLevel, p1, p2, p3) {
7
+ const triangleMeta = createTriangleTessellationMeta(p1, p2, p3);
8
+ const { vec3s, longLats, indices } = getAllPoints(triangleMeta, zoomLevel);
9
+ return { vec3s, longLats, indices };
10
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1 @@
1
+ export const TILE_COUNTS = Array.from({ length: 22 }, (_, i) => Math.pow(2, i));
package/Math/vec3.js CHANGED
@@ -7,6 +7,11 @@ function set(out, x, y, z) {
7
7
  out[1] = y;
8
8
  out[2] = z;
9
9
  }
10
+ function negate(item) {
11
+ item[0] = -item[0];
12
+ item[1] = -item[1];
13
+ item[2] = -item[2];
14
+ }
10
15
  function clone(a) {
11
16
  return [a[0], a[1], a[2]];
12
17
  }
@@ -100,6 +105,14 @@ function fromLongLatToUnitVector(out, longLat) {
100
105
  out[1] = cosLat * Math.sin(longitude);
101
106
  out[2] = Math.sin(latitude);
102
107
  }
108
+ function createUnitVectorFromLongLat(longLat) {
109
+ const cosLat = Math.cos(longLat[1]);
110
+ return [
111
+ cosLat * Math.cos(longLat[0]),
112
+ cosLat * Math.sin(longLat[0]),
113
+ Math.sin(longLat[1])
114
+ ];
115
+ }
103
116
  function applyQuaternion(out, a, q) {
104
117
  const x = a[0], y = a[1], z = a[2];
105
118
  const qx = q[0], qy = q[1], qz = q[2], qw = q[3];
@@ -123,4 +136,16 @@ function randomUnit(out) {
123
136
  function str(a) {
124
137
  return `Vec3(${a[0].toFixed(2)}, ${a[1].toFixed(2)}, ${a[2].toFixed(2)})`;
125
138
  }
126
- export { create, set, clone, copy, add, subtract, dot, cross, multiplyScalar, divideScalar, lengthSquared, length, normalize, distanceSquared, distance, equals, fromUnitVectorToLongLat, fromLongLatToUnitVector, applyQuaternion, randomUnit, str };
139
+ function vec3ToLongLatDegrees(v) {
140
+ return [
141
+ Math.atan2(v[1], v[0]) * 180 / Math.PI,
142
+ Math.asin(v[2]) * 180 / Math.PI
143
+ ];
144
+ }
145
+ function vec3ToLongLatRadians(v) {
146
+ return [
147
+ Math.atan2(v[1], v[0]),
148
+ Math.asin(v[2])
149
+ ];
150
+ }
151
+ export { create, set, clone, copy, add, subtract, negate, dot, cross, multiplyScalar, divideScalar, lengthSquared, length, normalize, distanceSquared, distance, equals, fromUnitVectorToLongLat, fromLongLatToUnitVector, applyQuaternion, randomUnit, str, createUnitVectorFromLongLat, vec3ToLongLatDegrees, vec3ToLongLatRadians };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pirireis/webglobeplugins",
3
- "version": "0.16.4",
3
+ "version": "0.16.7",
4
4
  "main": "index.js",
5
5
  "author": "Toprak Nihat Deniz Ozturk",
6
6
  "license": "MIT",
@@ -9,6 +9,8 @@
9
9
  },
10
10
  "dependencies": {
11
11
  "@pirireis/webglobe": "^6.2.22",
12
+ "delaunator": "^5.0.1",
13
+ "earcut": "^3.0.2",
12
14
  "rbush": "^4.0.1"
13
15
  }
14
- }
16
+ }
@@ -0,0 +1,178 @@
1
+ import { TextureDemTriangles } from "./texture-dem-triangles";
2
+ import { test1 } from "../../Math/tessellation/triangle-tessellation";
3
+ /**
4
+ * Loads a plugin with test data for TextureDemTriangles
5
+ */
6
+ const createTestBBOXES = () => {
7
+ const bboxes = [];
8
+ for (let i = 0; i < 6; i++) {
9
+ const north = Math.random() * Math.PI / 2 / 1.4; // random latitude
10
+ const west = Math.random() * -1 * Math.PI / 10; // random longitude
11
+ const south = north - Math.PI / 30; // random latitude
12
+ const east = west + Math.PI / 30; // random longitude
13
+ const nw = [west, north]; // random northWest
14
+ const se = [east, south]; // random southEast
15
+ bboxes.push({ northWest: nw, southEast: se });
16
+ }
17
+ return bboxes;
18
+ };
19
+ function showTextureBBoxes(bboxes, demData = []) {
20
+ for (let i = 0; i < bboxes.length; i++) {
21
+ const bbox = bboxes[i];
22
+ console.log(`Texture BBOX ${i}: NW(${(bbox.northWest[0] * 180 / Math.PI).toFixed(2)}, ${(bbox.northWest[1] * 180 / Math.PI).toFixed(2)}) SE(${(bbox.southEast[0] * 180 / Math.PI).toFixed(2)}, ${(bbox.southEast[1] * 180 / Math.PI).toFixed(2)})`);
23
+ if (demData.length > i) {
24
+ const dem = demData[i];
25
+ let demStr = "DEM: \n";
26
+ for (let j = 0; j < dem.length; j++) {
27
+ demStr += dem[j].toFixed(1) + " ";
28
+ if ((j + 1) % 5 === 0) {
29
+ demStr += "\n";
30
+ }
31
+ }
32
+ console.log(demStr);
33
+ }
34
+ }
35
+ }
36
+ const createTestDemTextures = () => {
37
+ const textures = [];
38
+ for (let i = 0; i < 6; i++) {
39
+ const texture = [];
40
+ for (let j = 0; j < 5 * 5; j++) {
41
+ const value = 100 * Math.random(); // random elevation value
42
+ texture.push(value);
43
+ }
44
+ textures.push(texture);
45
+ }
46
+ return textures;
47
+ };
48
+ // TODO: NAME IT longlat degree or radian
49
+ export function createBuffersAndFill(gl, vec3s, longLats, indices) {
50
+ const positionBuffer = gl.createBuffer();
51
+ const longLatBuffer = gl.createBuffer();
52
+ const indexBuffer = gl.createBuffer();
53
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
54
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vec3s), gl.STATIC_DRAW);
55
+ gl.bindBuffer(gl.ARRAY_BUFFER, longLatBuffer);
56
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(longLats), gl.STATIC_DRAW);
57
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
58
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
59
+ return {
60
+ buffers: {
61
+ positionBuffer,
62
+ longLatBuffer,
63
+ indexBuffer
64
+ }
65
+ };
66
+ }
67
+ export class TextureDemTrianglesTestPlugin {
68
+ globe = null;
69
+ textureDemTriangles = null;
70
+ vao = null;
71
+ drawOptions = null;
72
+ bufferInfo = null;
73
+ id;
74
+ uboTriangleStyle = null;
75
+ uboStringStyle = null;
76
+ showDemPoints = false;
77
+ constructor(id) {
78
+ this.id = id;
79
+ }
80
+ init(globe) {
81
+ this.globe = globe;
82
+ this.textureDemTriangles = new TextureDemTriangles(globe);
83
+ // set bboxes and dem textures
84
+ const demTextures = createTestDemTextures();
85
+ const demTextureBBOX = createTestBBOXES();
86
+ this.textureDemTriangles.setDemTextures(demTextures, demTextureBBOX);
87
+ //
88
+ showTextureBBoxes(demTextureBBOX, demTextures);
89
+ this.uboTriangleStyle = this.textureDemTriangles.createUBO();
90
+ this.uboStringStyle = this.textureDemTriangles.createUBO();
91
+ this.uboTriangleStyle.updateSingle("u_color", new Float32Array([1.0, 0.0, 0.0, 0.0]));
92
+ this.uboStringStyle.updateSingle("u_color", new Float32Array([.3, .3, .0, 1.0]));
93
+ const elementBuffer = globe.gl.createBuffer();
94
+ const bufferInfo = {
95
+ pos3dBufferInfo: {
96
+ buffer: globe.gl.createBuffer(),
97
+ stride: 0,
98
+ offset: 0,
99
+ },
100
+ longLatBufferInfo: {
101
+ buffer: globe.gl.createBuffer(),
102
+ stride: 0,
103
+ offset: 0,
104
+ },
105
+ elementBufferInfo: {
106
+ buffer: elementBuffer,
107
+ stride: 0,
108
+ offset: 0,
109
+ },
110
+ drawOptions: {
111
+ drawRange: { count: 0, first: 0 },
112
+ drawMode: globe.gl.TRIANGLES,
113
+ elementBuffer: elementBuffer,
114
+ elementBufferIndexType: globe.gl.UNSIGNED_INT
115
+ },
116
+ drawOptionsPoint: {
117
+ drawRange: { count: 0, first: 0 },
118
+ drawMode: globe.gl.POINTS,
119
+ },
120
+ };
121
+ this.vao = this.textureDemTriangles.createVAO(bufferInfo.pos3dBufferInfo, bufferInfo.longLatBufferInfo);
122
+ this.bufferInfo = bufferInfo;
123
+ this.setZoom(5);
124
+ }
125
+ setUniform(key, value) {
126
+ if (this.uboTriangleStyle) {
127
+ this.uboTriangleStyle.updateSingle(key, value);
128
+ }
129
+ if (this.uboStringStyle) {
130
+ this.uboStringStyle.updateSingle(key, value);
131
+ }
132
+ this.globe?.DrawRender();
133
+ }
134
+ setZoom(zoomLevel) {
135
+ if (!this.globe || !this.textureDemTriangles || !this.bufferInfo)
136
+ return;
137
+ const p1 = [-20 * Math.PI / 180, 50 * Math.PI / 180];
138
+ const p2 = [20 * Math.PI / 180, 50 * Math.PI / 180];
139
+ const p3 = [0, -10 * Math.PI / 180];
140
+ // const p1_1: LongLatRadian = [-20 * Math.PI / 180, 30 * Math.PI / 180];
141
+ // const p2_2: LongLatRadian = [20 * Math.PI / 180, 20 * Math.PI / 180];
142
+ // const p3_3: LongLatRadian = [5, -20 * Math.PI / 180];
143
+ const { vec3s, longLats, indices } = test1(zoomLevel, p1, p2, p3);
144
+ // const {vec3s, longLats, indices} = test1(5, p1_1, p2_2, p3_3);
145
+ const bufferInfo = this.bufferInfo;
146
+ bufferInfo.drawOptions.drawRange.first = 0;
147
+ bufferInfo.drawOptions.drawRange.count = indices.length;
148
+ bufferInfo.drawOptionsPoint.drawRange.first = 0;
149
+ bufferInfo.drawOptionsPoint.drawRange.count = longLats.length / 2;
150
+ const gl = this.globe.gl;
151
+ // const longLatArray = createTestLongLatArray();
152
+ // const pos3dArray = createTestPos3dArray(longLatArray);
153
+ // @ts-ignore
154
+ gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.pos3dBufferInfo.buffer);
155
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vec3s), gl.STATIC_DRAW);
156
+ // @ts-ignore
157
+ gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.longLatBufferInfo.buffer);
158
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(longLats), gl.STATIC_DRAW);
159
+ // @ts-ignore
160
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferInfo.elementBufferInfo.buffer);
161
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(indices), gl.STATIC_DRAW);
162
+ this.globe.DrawRender();
163
+ console.log("DrawIInfo", this.bufferInfo);
164
+ }
165
+ setShowDemPoints(show) {
166
+ this.showDemPoints = show;
167
+ }
168
+ draw3D() {
169
+ if (!this.globe || !this.textureDemTriangles || !this.vao || !this.bufferInfo)
170
+ return;
171
+ // @ts-ignore
172
+ this.textureDemTriangles.draw(this.vao, this.bufferInfo.drawOptions, this.uboTriangleStyle);
173
+ if (this.showDemPoints) {
174
+ // @ts-ignore
175
+ this.textureDemTriangles.draw(this.vao, this.bufferInfo.drawOptionsPoint, this.uboStringStyle);
176
+ }
177
+ }
178
+ }