@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.
- package/Math/arc.js +92 -2
- package/Math/circle-cdf-points.js +2 -2
- package/Math/circle.js +2 -2
- package/Math/juction/arc-plane.js +67 -12
- package/Math/juction/line-sphere.js +6 -6
- package/Math/juction/plane-plane.js +4 -6
- package/Math/methods.js +5 -5
- package/Math/templete-shapes/grid-visually-equal.js +0 -1
- package/Math/tessellation/earcut/adapters.js +37 -0
- package/Math/tessellation/methods.js +46 -0
- package/Math/tessellation/shred-input.js +18 -0
- package/Math/tessellation/tessellation-algorithm.js +67 -0
- package/Math/tessellation/tiler.js +50 -0
- package/Math/tessellation/triangle-tessellation-meta.js +370 -0
- package/Math/tessellation/triangle-tessellation.js +10 -0
- package/Math/tessellation/types.js +1 -0
- package/Math/tessellation/zoom-catch.js +1 -0
- package/Math/vec3.js +26 -1
- package/package.json +4 -2
- package/programs/polygon-on-globe/texture-dem-triangle-test-plugin-triangle.js +178 -0
- package/programs/polygon-on-globe/texture-dem-triangle-test-plugin.js +31 -10
- package/programs/polygon-on-globe/texture-dem-triangles.js +53 -11
- package/programs/totems/camerauniformblock.js +3 -3
- package/semiplugins/shape-on-terrain/arc-plugin.js +5 -5
- package/semiplugins/shape-on-terrain/padding-1-degree.js +0 -1
- package/util/gl-util/uniform-block/manager.js +4 -4
- package/util/shaderfunctions/geometrytransformations.js +6 -0
- package/Math/mesh/mapbox-delaunay.js +0 -544
|
@@ -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
|
-
|
|
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.
|
|
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
|
+
}
|