@pirireis/webglobeplugins 0.11.1-alpha → 0.13.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 (38) hide show
  1. package/Math/arc-cdf-points.js +252 -0
  2. package/Math/{arc-generate-points.js → arc-generate-points copy.js } +4 -0
  3. package/Math/arc-generate-points-exponantial.js +254 -0
  4. package/Math/arc.js +5 -5
  5. package/Math/circle-cdf-points.js +247 -0
  6. package/Math/circle.js +39 -0
  7. package/Math/methods.js +13 -3
  8. package/Math/vec3.js +3 -3
  9. package/package.json +1 -1
  10. package/programs/line-on-globe/circle-accurate.js +176 -175
  11. package/programs/line-on-globe/circle.js +166 -164
  12. package/programs/line-on-globe/linestrip/data.js +4 -0
  13. package/programs/line-on-globe/{linestrip.js → linestrip/linestrip.js} +38 -39
  14. package/programs/line-on-globe/to-the-surface.js +111 -109
  15. package/programs/rings/distancering/circleflatprogram.js +116 -120
  16. package/programs/rings/distancering/circlepaddingfreeangleprogram.js +1 -1
  17. package/programs/rings/distancering/circlepaddysharedbuffer.js +368 -354
  18. package/programs/rings/distancering/index.js +6 -5
  19. package/programs/rings/distancering/paddyflatprogram.js +127 -136
  20. package/programs/rings/distancering/paddyflatprogram2d.js +129 -138
  21. package/programs/rings/distancering/paddyflatprogram3d.js +128 -136
  22. package/programs/totems/camerauniformblock.js +35 -8
  23. package/programs/totems/canvas-webglobe-info.js +55 -20
  24. package/programs/totems/{camerauniformblock copy.js → canvas-webglobe-info1.js} +11 -76
  25. package/programs/vectorfields/logics/pixelbased.js +4 -20
  26. package/shape-on-terrain/arc/naive/plugin.js +249 -288
  27. package/shape-on-terrain/circle/plugin.js +284 -0
  28. package/shape-on-terrain/type.js +1 -0
  29. package/util/account/index.js +2 -2
  30. package/util/account/single-attribute-buffer-management/buffer-manager.js +2 -3
  31. package/util/account/single-attribute-buffer-management/buffer-orchestrator.js +2 -2
  32. package/util/build-strategy/general-strategy.js +62 -0
  33. package/util/build-strategy/static-dynamic.js +31 -0
  34. package/util/gl-util/draw-options/types.js +1 -1
  35. package/globe-types.js +0 -1
  36. package/programs/interface.js +0 -1
  37. package/programs/rings/distancering/shader.js +0 -1
  38. package/programs/totems/camerauniformblock1.js +0 -171
@@ -0,0 +1,247 @@
1
+ import { RADIANS } from "./methods";
2
+ function createTemplate(intervalCount, strength = 1.0) {
3
+ const out = new Array(intervalCount);
4
+ const TOTAL = 1;
5
+ let cummulative = 0;
6
+ if (strength <= 0) {
7
+ // If strength is 0, distribute evenly.
8
+ const step = TOTAL / (intervalCount - 1);
9
+ for (let i = 0; i < intervalCount; i++) {
10
+ out[i] = cummulative;
11
+ cummulative += step;
12
+ }
13
+ out[intervalCount - 1] = TOTAL; // Ensure the last value is exactly TOTAL
14
+ return out;
15
+ }
16
+ // If strength is greater than 0, bias towards the start.
17
+ const weights = new Array(intervalCount);
18
+ let currentStep = 1;
19
+ let totalWeight = 0;
20
+ // Calculate weights for each interval, decreasing for later intervals.
21
+ for (let i = 0; i < intervalCount; i++) {
22
+ // Using (i + 1) in the denominator gives earlier intervals the highest weight.
23
+ totalWeight += currentStep;
24
+ weights[i] = totalWeight;
25
+ currentStep += strength;
26
+ }
27
+ // Distribute the total angle based on the weights.
28
+ for (let i = 0; i < intervalCount; i++) {
29
+ // Round to the nearest whole number for this interval.
30
+ out[i] = (weights[i] / totalWeight) * TOTAL;
31
+ }
32
+ if (out[intervalCount - 1] !== TOTAL) {
33
+ out[intervalCount - 1] = TOTAL;
34
+ }
35
+ // console.log("createTemplate", "strength", strength, "intervalCount", intervalCount, "out", out);
36
+ return out;
37
+ }
38
+ function interpolation(a, b, t) {
39
+ return a + (b - a) * t;
40
+ }
41
+ /**
42
+ * Populates the `out` array with values from the `template` array,
43
+ * distributing the surplus length as interpolated values between the template samples.
44
+ *
45
+ * @param out The destination array to be filled. Its length must be >= template.length.
46
+ * @param template An ordered array of numbers to be placed in the `out` array.
47
+ * @param strength A parameter controlling the distribution bias of surplus samples.
48
+ * - strength = 0: Surplus samples are distributed evenly.
49
+ * - strength > 0: Surplus samples are biased towards the start of the template.
50
+ * - Higher values create a stronger bias.
51
+ */
52
+ function increasePopulation(// TODO: THERE IS A BUG
53
+ out, template, strength = 1.0) {
54
+ const sourceLength = template.length;
55
+ const destinationLength = out.length;
56
+ const outLengthAtStart = out.length;
57
+ // --- Handle Edge Cases ---
58
+ // If the template is empty, there is nothing to interpolate from.
59
+ if (sourceLength === 0) {
60
+ return;
61
+ }
62
+ // If the template has only one value, fill the output array with that value.
63
+ if (sourceLength === 1) {
64
+ out.fill(template[0]);
65
+ return;
66
+ }
67
+ // If the destination is not larger than the source, just copy the template values.
68
+ if (destinationLength <= sourceLength) {
69
+ for (let i = 0; i < destinationLength; i++) {
70
+ out[i] = template[i];
71
+ }
72
+ return;
73
+ }
74
+ // --- Main Logic ---
75
+ const surplus = destinationLength - sourceLength;
76
+ const numGaps = sourceLength - 1;
77
+ // This array will hold the number of extra samples to add in each gap.
78
+ const surplusPerGap = new Array(numGaps).fill(0);
79
+ if (surplus > 0) {
80
+ // --- Step 1: Determine the distribution of surplus items ---
81
+ // If strength is 0, distribute surplus items as evenly as possible.
82
+ if (strength <= 0) {
83
+ const baseToAdd = Math.floor(surplus / numGaps);
84
+ const remainder = surplus % numGaps;
85
+ for (let i = 0; i < numGaps; i++) {
86
+ // Distribute the remainder one by one to the first gaps.
87
+ surplusPerGap[i] = baseToAdd + (i < remainder ? 1 : 0);
88
+ }
89
+ }
90
+ else {
91
+ // Biased Distribution: more items in earlier gaps.
92
+ const weights = new Array(numGaps);
93
+ let totalWeight = 0;
94
+ // A. Calculate a weight for each gap. The weight decreases for later gaps.
95
+ // The `strength` parameter makes this decay steeper.
96
+ for (let i = 0; i < numGaps; i++) {
97
+ // Using (i + 1) in the denominator gives earlier gaps (i=0) the highest weight.
98
+ const weight = Math.pow(1 / (i + 1), strength);
99
+ weights[i] = weight;
100
+ totalWeight += weight;
101
+ }
102
+ // B. Distribute the surplus based on the calculated weights.
103
+ // This method ensures the total distributed count equals the surplus.
104
+ let distributedCount = 0;
105
+ for (let i = 0; i < numGaps - 1; i++) {
106
+ const idealCount = (weights[i] / totalWeight) * surplus;
107
+ // Round to the nearest whole number for this gap.
108
+ const countForThisGap = Math.ceil(idealCount);
109
+ surplusPerGap[i] = countForThisGap;
110
+ distributedCount += countForThisGap;
111
+ }
112
+ // Assign the remainder to the last gap to guarantee the sum is correct.
113
+ //surplusPerGap[numGaps - 1] = surplus - distributedCount;
114
+ // add to first
115
+ const leftover = surplus - distributedCount;
116
+ if (leftover > 0) {
117
+ surplusPerGap[0] += leftover; // Add any leftover to the first gap.
118
+ }
119
+ console.log("leftover", leftover, "distributedCount", distributedCount, "surplus", surplus);
120
+ }
121
+ }
122
+ // --- Step 2: Populate the `out` array ---
123
+ let outIndex = 0;
124
+ for (let i = 0; i < surplusPerGap.length; i++) {
125
+ if (typeof surplusPerGap[i] !== "number" || isNaN(surplusPerGap[i]) || !isFinite(surplusPerGap[i])) {
126
+ console.warn("increasePopulation: Invalid surplusPerGap value at index", i, ":", surplusPerGap[i]);
127
+ }
128
+ }
129
+ for (let i = 0; i < sourceLength; i++) {
130
+ // A. Add the original template item.
131
+ out[outIndex++] = template[i];
132
+ // B. If this is not the last template item, fill the gap after it.
133
+ if (i < numGaps) {
134
+ const numToAdd = surplusPerGap[i];
135
+ if (numToAdd <= 0)
136
+ continue;
137
+ const startVal = template[i];
138
+ const endVal = template[i + 1];
139
+ // C. Add the interpolated ("surplus") items for this gap.
140
+ // The total number of intervals in this gap is numToAdd + 1.
141
+ const totalIntervals = numToAdd + 1;
142
+ for (let j = 1; j <= numToAdd; j++) {
143
+ const t = j / totalIntervals; // The interpolation factor (0 < t < 1)
144
+ // Linear interpolation: out = start * (1 - t) + end * t
145
+ const interpolatedValue = startVal * (1 - t) + endVal * t;
146
+ out[outIndex++] = interpolatedValue;
147
+ if (outIndex >= out.length) {
148
+ console.warn("increasePopulation: Output array overflow. Stopping early.");
149
+ console.warn("processeed item ratio:", i, "/", sourceLength);
150
+ let count = numToAdd - j;
151
+ console.log("count", count);
152
+ for (let _i = i; _i < sourceLength; _i++) {
153
+ count += surplusPerGap[_i];
154
+ }
155
+ console.warn("increasePopulation: Not enough space to add", count, "more items.");
156
+ return; // Prevent overflow if the output array is not large enough.
157
+ }
158
+ }
159
+ }
160
+ }
161
+ // --- Step 3: Ensure the output length is correct ---
162
+ if (outLengthAtStart !== out.length) {
163
+ console.warn("increasePopulation: Output length mismatch. Expected", outLengthAtStart, "but got", out.length);
164
+ }
165
+ }
166
+ function createCummulativeTemplate(numberOfPoints, strength, denseRatio = 0.5 // Ratio of points to be densely packed at the start.
167
+ ) {
168
+ // Handle edge cases for the number of points.
169
+ if (numberOfPoints <= 0) {
170
+ // If zero or a negative number of points is requested, return an empty array.
171
+ return new Float64Array([]);
172
+ }
173
+ // Create the array to hold the results. Float64Array is used for high-precision floating-point numbers.
174
+ const distribution = new Float64Array(numberOfPoints);
175
+ if (numberOfPoints === 1) {
176
+ // If only one point is requested, it represents the entire range [0, 1].
177
+ // We place it at the start (0.0).
178
+ distribution[0] = 0.0;
179
+ return distribution;
180
+ }
181
+ // The exponent determines the curve of the distribution.
182
+ // We add 1 to the strength so that a strength of 0 results in an exponent of 1 (linear).
183
+ // We use Math.max(0, strength) to ensure the strength is not negative.
184
+ // The last index is used to normalize the position to a 0-1 range.
185
+ const lastIndex = numberOfPoints - 1;
186
+ distribution[0] = 0.0; // The first point is always at 0.0.
187
+ let totalWeight = 0;
188
+ let i = 1;
189
+ const denseCount = numberOfPoints * denseRatio;
190
+ for (i; i < denseCount; i++) {
191
+ // Calculate the ratio of the current index to the last index.
192
+ // The ratio is adjusted to create a non-linear distribution.
193
+ totalWeight += 1;
194
+ distribution[i] = totalWeight; // Store the raw value in the distribution array.
195
+ }
196
+ for (i; i < numberOfPoints; i++) {
197
+ // Calculate the ratio of the current index to the last index.
198
+ const ratio = 1 + ((i - denseCount) / lastIndex) / (1 - denseRatio) * 2;
199
+ const step = Math.pow(ratio, strength);
200
+ totalWeight += step;
201
+ distribution[i] = totalWeight; // Store the raw value in the distribution array.
202
+ // Apply the power function to create a non-linear distribution.
203
+ // The result is normalized to the range [0, 1].
204
+ }
205
+ for (let i = 1; i < numberOfPoints; i++) {
206
+ // Normalize the values to ensure they sum up to 1.
207
+ distribution[i] = distribution[i] / totalWeight;
208
+ }
209
+ return distribution;
210
+ }
211
+ function createCummulativeTemplateStash(levels, numberOfPoints, denseRatio = 0.5, strengthMultiplier = 2.4) {
212
+ const stash = [];
213
+ for (let i = 0; i < levels; i++) {
214
+ const template = createCummulativeTemplate(numberOfPoints, i * strengthMultiplier, denseRatio);
215
+ stash.push(template);
216
+ }
217
+ return stash;
218
+ }
219
+ function globeFindPointByPolar(out, globe, centerLong, centerLat, radius, ratios) {
220
+ for (let i = 0; i < ratios.length; i++) {
221
+ const point = globe.Math.FindPointByPolar(centerLong, centerLat, radius, ratios[i]);
222
+ out[i * 2] = point.long;
223
+ out[i * 2 + 1] = point.lat;
224
+ }
225
+ }
226
+ function globeFindPointByPolarHalfCircle(out, globe, centerLong, centerLat, radius, rotation, ratios) {
227
+ const rotCentigrade = rotation / RADIANS + 720;
228
+ for (let i = 0; i < ratios.length; i++) {
229
+ const point = globe.Math.FindPointByPolar(centerLong, centerLat, radius, (ratios[i] * 180 + rotCentigrade) % 360);
230
+ out[i * 2] = point.long;
231
+ out[i * 2 + 1] = point.lat;
232
+ }
233
+ // fill reflection
234
+ let offset = out.length;
235
+ for (let i = 0; i < ratios.length - 1; i++) {
236
+ const point = globe.Math.FindPointByPolar(centerLong, centerLat, radius, ((-ratios[i]) * 180 + rotCentigrade) % 360);
237
+ out[offset - 2] = point.long;
238
+ out[offset - 1] = point.lat;
239
+ offset -= 2;
240
+ }
241
+ }
242
+ export {
243
+ // createTemplate,
244
+ // increasePopulation,
245
+ // interpolation,
246
+ // createCummulativeTemplate,
247
+ createCummulativeTemplateStash, globeFindPointByPolar, globeFindPointByPolarHalfCircle };
package/Math/circle.js ADDED
@@ -0,0 +1,39 @@
1
+ import { RADIANS } from './methods';
2
+ import { subtract, normalize, dot, fromLongLatToUnitVector, copy, multiplyScalar } from './vec3';
3
+ const _0vec3 = [0, 0, 0];
4
+ function closestAzimuthAngle(circleProperties, point) {
5
+ const distance = dot(circleProperties.normal, point);
6
+ copy(_0vec3, circleProperties.normal);
7
+ multiplyScalar(_0vec3, _0vec3, distance);
8
+ subtract(_0vec3, point, _0vec3);
9
+ normalize(_0vec3, _0vec3);
10
+ const N = circleProperties.northPointProjectedToOriginPlaneNormalized;
11
+ const _dot = dot(_0vec3, N);
12
+ let angle = Math.acos(_dot);
13
+ const z = _0vec3[0] * N[1] - _0vec3[1] * N[0];
14
+ return z < 0 ? -angle : angle;
15
+ }
16
+ function createCircleClosestAzimuthAngleProperties(circle) {
17
+ const normal = Array(3);
18
+ fromLongLatToUnitVector(normal, [circle.center[0] * RADIANS, circle.center[1] * RADIANS]);
19
+ const distance = normal[2]; //dot(normal, [0, 0, 1] as Vec3)
20
+ const N = [0, 0, 0];
21
+ if (Math.abs(distance) < 1e-6) {
22
+ N[0] = -1;
23
+ N[1] = 0;
24
+ N[2] = 0;
25
+ }
26
+ else {
27
+ copy(N, normal);
28
+ multiplyScalar(N, N, distance);
29
+ N[0] = -N[0];
30
+ N[1] = -N[1];
31
+ N[2] = 1 - N[2];
32
+ }
33
+ normalize(N, N);
34
+ return {
35
+ normal: normal,
36
+ northPointProjectedToOriginPlaneNormalized: N,
37
+ };
38
+ }
39
+ export { closestAzimuthAngle, createCircleClosestAzimuthAngleProperties };
package/Math/methods.js CHANGED
@@ -84,14 +84,24 @@ export const globe3Dcoordinates = (globe, height = 0) => (longlats, { paddingCou
84
84
  }
85
85
  return result;
86
86
  };
87
- export const globe2Dcoordinates = (globe) => (longlats, { paddingCount = 0, paddingValue = NaN }) => {
87
+ const manhattanDistance = (a, b) => {
88
+ return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]);
89
+ };
90
+ export const globe2Dcoordinates = (globe, distanceFilterMeter = WORLD_RADIUS_MERCATOR) => (longlats, { paddingCount = 0, paddingValue = NaN }) => {
91
+ let _lastXY = [NaN, NaN];
88
92
  const len = longlats.length / 2;
89
93
  const result = new Float32Array(len * 2 + paddingCount * 2).fill(paddingValue);
90
94
  for (let i = 0; i < len; i++) {
91
95
  const long = longlats[i * 2];
92
96
  const lat = longlats[i * 2 + 1];
93
- const xyz = globe.api_GetMercator2DPoint(long, lat);
94
- result.set(xyz, i * 2);
97
+ const xy = globe.api_GetMercator2DPoint(long, lat);
98
+ if (manhattanDistance(_lastXY, xy) > distanceFilterMeter) {
99
+ result.set([paddingValue, paddingValue], i * 2);
100
+ }
101
+ else {
102
+ result.set(xy, i * 2);
103
+ }
104
+ _lastXY = xy;
95
105
  }
96
106
  return result;
97
107
  };
package/Math/vec3.js CHANGED
@@ -80,7 +80,7 @@ function equals(a, b) {
80
80
  Math.abs(a[1] - b[1]) < EPSILON &&
81
81
  Math.abs(a[2] - b[2]) < EPSILON);
82
82
  }
83
- function toUnitVectorLongLat(out, a) {
83
+ function fromUnitVectorToLongLat(out, a) {
84
84
  const len = length(a); // TODO Might drop length check
85
85
  if (len === 0) {
86
86
  throw new Error('Cannot convert a zero vector to unit vector');
@@ -88,7 +88,7 @@ function toUnitVectorLongLat(out, a) {
88
88
  out[0] = Math.atan2(a[1], a[0]); // Longitude
89
89
  out[1] = Math.asin(a[2] / len); // Latitude
90
90
  }
91
- function fromUnitVectorLongLat(out, longLat) {
91
+ function fromLongLatToUnitVector(out, longLat) {
92
92
  const longitude = longLat[0];
93
93
  const latitude = longLat[1];
94
94
  const cosLat = Math.cos(latitude);
@@ -119,4 +119,4 @@ function randomUnit(out) {
119
119
  function str(a) {
120
120
  return `Vec3(${a[0].toFixed(2)}, ${a[1].toFixed(2)}, ${a[2].toFixed(2)})`;
121
121
  }
122
- export { create, set, clone, copy, add, subtract, dot, cross, multiplyScalar, divideScalar, lengthSquared, length, normalize, distanceSquared, distance, equals, toUnitVectorLongLat, fromUnitVectorLongLat, applyQuaternion, randomUnit, str };
122
+ export { create, set, clone, copy, add, subtract, dot, cross, multiplyScalar, divideScalar, lengthSquared, length, normalize, distanceSquared, distance, equals, fromUnitVectorToLongLat, fromLongLatToUnitVector, applyQuaternion, randomUnit, str };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pirireis/webglobeplugins",
3
- "version": "0.11.1-alpha",
3
+ "version": "0.13.0-alpha",
4
4
  "main": "index.js",
5
5
  "author": "Toprak Nihat Deniz Ozturk",
6
6
  "license": "MIT",