@luma.gl/shadertools 9.3.6 → 9.4.0-alpha.1

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 (113) hide show
  1. package/dist/dist.dev.js +6555 -2373
  2. package/dist/dist.min.js +2984 -237
  3. package/dist/index.cjs +4356 -268
  4. package/dist/index.cjs.map +4 -4
  5. package/dist/index.d.ts +13 -3
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +6 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/preprocessor/preprocessor.d.ts +11 -1
  10. package/dist/lib/preprocessor/preprocessor.d.ts.map +1 -1
  11. package/dist/lib/preprocessor/preprocessor.js +47 -2
  12. package/dist/lib/preprocessor/preprocessor.js.map +1 -1
  13. package/dist/lib/shader-assembler.d.ts +10 -10
  14. package/dist/lib/shader-assembler.d.ts.map +1 -1
  15. package/dist/lib/shader-assembler.js +36 -20
  16. package/dist/lib/shader-assembler.js.map +1 -1
  17. package/dist/lib/shader-assembly/assemble-shaders.d.ts +28 -7
  18. package/dist/lib/shader-assembly/assemble-shaders.d.ts.map +1 -1
  19. package/dist/lib/shader-assembly/assemble-shaders.js +133 -15
  20. package/dist/lib/shader-assembly/assemble-shaders.js.map +1 -1
  21. package/dist/lib/shader-assembly/platform-info.d.ts +2 -0
  22. package/dist/lib/shader-assembly/platform-info.d.ts.map +1 -1
  23. package/dist/lib/shader-assembly/shader-hooks.d.ts +1 -1
  24. package/dist/lib/shader-assembly/shader-hooks.d.ts.map +1 -1
  25. package/dist/lib/shader-assembly/shader-hooks.js +6 -3
  26. package/dist/lib/shader-assembly/shader-hooks.js.map +1 -1
  27. package/dist/lib/shader-assembly/shader-injections.d.ts +4 -1
  28. package/dist/lib/shader-assembly/shader-injections.d.ts.map +1 -1
  29. package/dist/lib/shader-assembly/shader-injections.js +68 -11
  30. package/dist/lib/shader-assembly/shader-injections.js.map +1 -1
  31. package/dist/lib/shader-assembly/shader-plugin-varyings.d.ts +15 -0
  32. package/dist/lib/shader-assembly/shader-plugin-varyings.d.ts.map +1 -0
  33. package/dist/lib/shader-assembly/shader-plugin-varyings.js +412 -0
  34. package/dist/lib/shader-assembly/shader-plugin-varyings.js.map +1 -0
  35. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.d.ts +12 -0
  36. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.d.ts.map +1 -0
  37. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.js +237 -0
  38. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.js.map +1 -0
  39. package/dist/lib/shader-module/shader-module.d.ts +3 -0
  40. package/dist/lib/shader-module/shader-module.d.ts.map +1 -1
  41. package/dist/lib/shader-module/shader-module.js.map +1 -1
  42. package/dist/lib/shader-module/shader-pass-pipeline.d.ts +14 -0
  43. package/dist/lib/shader-module/shader-pass-pipeline.d.ts.map +1 -0
  44. package/dist/lib/shader-module/shader-pass-pipeline.js +5 -0
  45. package/dist/lib/shader-module/shader-pass-pipeline.js.map +1 -0
  46. package/dist/lib/shader-module/shader-pass.d.ts +21 -4
  47. package/dist/lib/shader-module/shader-pass.d.ts.map +1 -1
  48. package/dist/lib/shader-plugin.d.ts +68 -0
  49. package/dist/lib/shader-plugin.d.ts.map +1 -0
  50. package/dist/lib/shader-plugin.js +98 -0
  51. package/dist/lib/shader-plugin.js.map +1 -0
  52. package/dist/lib/utils/assert.js +1 -1
  53. package/dist/lib/utils/assert.js.map +1 -1
  54. package/dist/modules/color/float-colors.d.ts +111 -5
  55. package/dist/modules/color/float-colors.d.ts.map +1 -1
  56. package/dist/modules/color/float-colors.js +200 -34
  57. package/dist/modules/color/float-colors.js.map +1 -1
  58. package/dist/modules/engine/clip/clip.d.ts +12 -0
  59. package/dist/modules/engine/clip/clip.d.ts.map +1 -0
  60. package/dist/modules/engine/clip/clip.js +129 -0
  61. package/dist/modules/engine/clip/clip.js.map +1 -0
  62. package/dist/modules/engine/filter/filter.d.ts +12 -0
  63. package/dist/modules/engine/filter/filter.d.ts.map +1 -0
  64. package/dist/modules/engine/filter/filter.js +88 -0
  65. package/dist/modules/engine/filter/filter.js.map +1 -0
  66. package/dist/modules/geospatial/dggs/dggs-wgsl.d.ts +3 -0
  67. package/dist/modules/geospatial/dggs/dggs-wgsl.d.ts.map +1 -0
  68. package/dist/modules/geospatial/dggs/dggs-wgsl.js +1892 -0
  69. package/dist/modules/geospatial/dggs/dggs-wgsl.js.map +1 -0
  70. package/dist/modules/geospatial/dggs/dggs.d.ts +6 -0
  71. package/dist/modules/geospatial/dggs/dggs.d.ts.map +1 -0
  72. package/dist/modules/geospatial/dggs/dggs.js +10 -0
  73. package/dist/modules/geospatial/dggs/dggs.js.map +1 -0
  74. package/dist/modules/lighting/water-material/water-material.d.ts +28 -0
  75. package/dist/modules/lighting/water-material/water-material.d.ts.map +1 -0
  76. package/dist/modules/lighting/water-material/water-material.js +179 -0
  77. package/dist/modules/lighting/water-material/water-material.js.map +1 -0
  78. package/dist/modules/lighting/water-material/water-shaders-glsl.d.ts +3 -0
  79. package/dist/modules/lighting/water-material/water-shaders-glsl.d.ts.map +1 -0
  80. package/dist/modules/lighting/water-material/water-shaders-glsl.js +232 -0
  81. package/dist/modules/lighting/water-material/water-shaders-glsl.js.map +1 -0
  82. package/dist/modules/lighting/water-material/water-shaders-wgsl.d.ts +2 -0
  83. package/dist/modules/lighting/water-material/water-shaders-wgsl.d.ts.map +1 -0
  84. package/dist/modules/lighting/water-material/water-shaders-wgsl.js +230 -0
  85. package/dist/modules/lighting/water-material/water-shaders-wgsl.js.map +1 -0
  86. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts +2 -1
  87. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts.map +1 -1
  88. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js +268 -0
  89. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js.map +1 -1
  90. package/package.json +2 -2
  91. package/src/index.ts +50 -3
  92. package/src/lib/preprocessor/preprocessor.ts +68 -3
  93. package/src/lib/shader-assembler.ts +49 -20
  94. package/src/lib/shader-assembly/assemble-shaders.ts +242 -30
  95. package/src/lib/shader-assembly/platform-info.ts +2 -0
  96. package/src/lib/shader-assembly/shader-hooks.ts +7 -3
  97. package/src/lib/shader-assembly/shader-injections.ts +96 -11
  98. package/src/lib/shader-assembly/shader-plugin-varyings.ts +524 -0
  99. package/src/lib/shader-assembly/shader-plugin-vertex-inputs.ts +279 -0
  100. package/src/lib/shader-module/shader-module.ts +3 -0
  101. package/src/lib/shader-module/shader-pass-pipeline.ts +19 -0
  102. package/src/lib/shader-module/shader-pass.ts +29 -4
  103. package/src/lib/shader-plugin.ts +214 -0
  104. package/src/lib/utils/assert.ts +1 -1
  105. package/src/modules/color/float-colors.ts +272 -37
  106. package/src/modules/engine/clip/clip.ts +149 -0
  107. package/src/modules/engine/filter/filter.ts +107 -0
  108. package/src/modules/geospatial/dggs/dggs-wgsl.ts +1892 -0
  109. package/src/modules/geospatial/dggs/dggs.ts +12 -0
  110. package/src/modules/lighting/water-material/water-material.ts +234 -0
  111. package/src/modules/lighting/water-material/water-shaders-glsl.ts +233 -0
  112. package/src/modules/lighting/water-material/water-shaders-wgsl.ts +230 -0
  113. package/src/modules/math/fp64/fp64-arithmetic-wgsl.ts +268 -0
@@ -0,0 +1,1892 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+ /** WGSL source implementing 64-bit DGGS cell key and boundary helpers. */
5
+ export const dggsWGSL = /* wgsl */ `\
6
+ const DGGS_H3_CELL_MODE: u32 = 1u;
7
+ const DGGS_H3_MAX_RESOLUTION: u32 = 15u;
8
+ const DGGS_H3_MAX_BASE_CELL: u32 = 121u;
9
+ const DGGS_H3_UNUSED_DIGIT: u32 = 7u;
10
+ const DGGS_H3_RES0_U_GNOMONIC: f32 = 0.381966011250105;
11
+ const DGGS_H3_RSQRT7: f32 = 0.3779644730092272;
12
+ const DGGS_H3_ONETHIRD: f32 = 0.3333333333333333;
13
+ const DGGS_H3_AP7_ROT_RADS: f32 = 0.3334731722518321;
14
+ const DGGS_H3_SQRT3_2: f32 = 0.8660254037844386;
15
+ const DGGS_S2_MAX_LEVEL: u32 = 30u;
16
+ const DGGS_GEOHASH_MAX_LENGTH: u32 = 12u;
17
+ const DGGS_GEOHASH_LENGTH_BIT_OFFSET: u32 = 60u;
18
+ const DGGS_QUADKEY_MAX_LENGTH: u32 = 29u;
19
+ const DGGS_QUADKEY_LENGTH_BIT_OFFSET: u32 = 58u;
20
+ const DGGS_A5_FIRST_HILBERT_RESOLUTION: u32 = 2u;
21
+ const DGGS_A5_MAX_RESOLUTION: u32 = 30u;
22
+ const DGGS_A5_HILBERT_START_BIT: u32 = 58u;
23
+ const DGGS_PI: f32 = 3.141592653589793;
24
+ const DGGS_TWO_PI: f32 = 6.283185307179586;
25
+ const DGGS_TWO_PI_OVER_5: f32 = 1.2566370614359172;
26
+ const DGGS_PI_OVER_5: f32 = 0.6283185307179586;
27
+ const DGGS_PI_OVER_2: f32 = 1.5707963267948966;
28
+ const DGGS_A5_DISTANCE_TO_EDGE: f32 = 0.6180339887498949;
29
+ const DGGS_A5_REFLECTED_TRIANGLE_SCALE: f32 = 3.23606797749979;
30
+ const DGGS_A5_LONGITUDE_OFFSET: f32 = 93.0;
31
+ const DGGS_RADIANS_TO_DEGREES: f32 = 57.29577951308232;
32
+ const DGGS_DEGREES_TO_RADIANS: f32 = 0.017453292519943295;
33
+ const DGGS_U64_HIGH_WORD_FLOAT_SCALE: f32 = 4294967296.0;
34
+
35
+ // DGGS 64-bit helper functions use canonical word order vec2u(high, low).
36
+ // Arrow BigInt64/BigUint64 buffers are read as little-endian vec2u(low, high),
37
+ // so storage-buffer reads should pass through dggs_u64_from_little_endian_words().
38
+ fn dggs_u64_make(high: u32, low: u32) -> vec2u {
39
+ return vec2u(high, low);
40
+ }
41
+
42
+ fn dggs_u64_from_little_endian_words(words: vec2u) -> vec2u {
43
+ return words.yx;
44
+ }
45
+
46
+ fn dggs_u64_to_little_endian_words(value: vec2u) -> vec2u {
47
+ return value.yx;
48
+ }
49
+
50
+ fn dggs_u64_high(value: vec2u) -> u32 {
51
+ return value.x;
52
+ }
53
+
54
+ fn dggs_u64_low(value: vec2u) -> u32 {
55
+ return value.y;
56
+ }
57
+
58
+ fn dggs_u64_is_zero(value: vec2u) -> bool {
59
+ return value.x == 0u && value.y == 0u;
60
+ }
61
+
62
+ fn dggs_u64_equal(a: vec2u, b: vec2u) -> bool {
63
+ return a.x == b.x && a.y == b.y;
64
+ }
65
+
66
+ fn dggs_u64_compare(a: vec2u, b: vec2u) -> i32 {
67
+ if (a.x != b.x) {
68
+ return select(-1, 1, a.x > b.x);
69
+ }
70
+ if (a.y != b.y) {
71
+ return select(-1, 1, a.y > b.y);
72
+ }
73
+ return 0;
74
+ }
75
+
76
+ fn dggs_u64_less(a: vec2u, b: vec2u) -> bool {
77
+ return dggs_u64_compare(a, b) < 0;
78
+ }
79
+
80
+ fn dggs_u64_add(a: vec2u, b: vec2u) -> vec2u {
81
+ let low = a.y + b.y;
82
+ let carry = select(0u, 1u, low < a.y);
83
+ return vec2u(a.x + b.x + carry, low);
84
+ }
85
+
86
+ fn dggs_u64_subtract(a: vec2u, b: vec2u) -> vec2u {
87
+ let borrow = select(0u, 1u, a.y < b.y);
88
+ return vec2u(a.x - b.x - borrow, a.y - b.y);
89
+ }
90
+
91
+ fn dggs_u64_to_f32(value: vec2u) -> f32 {
92
+ return f32(value.x) * DGGS_U64_HIGH_WORD_FLOAT_SCALE + f32(value.y);
93
+ }
94
+
95
+ fn dggs_i64_from_little_endian_words(words: vec2u) -> vec2u {
96
+ return dggs_u64_from_little_endian_words(words);
97
+ }
98
+
99
+ fn dggs_i64_to_little_endian_words(value: vec2u) -> vec2u {
100
+ return dggs_u64_to_little_endian_words(value);
101
+ }
102
+
103
+ fn dggs_i64_is_negative(value: vec2u) -> bool {
104
+ return (value.x & 0x80000000u) != 0u;
105
+ }
106
+
107
+ fn dggs_i64_negate(value: vec2u) -> vec2u {
108
+ return dggs_u64_add(vec2u(~value.x, ~value.y), vec2u(0u, 1u));
109
+ }
110
+
111
+ fn dggs_i64_compare(a: vec2u, b: vec2u) -> i32 {
112
+ let highA = bitcast<i32>(a.x);
113
+ let highB = bitcast<i32>(b.x);
114
+ if (highA != highB) {
115
+ return select(-1, 1, highA > highB);
116
+ }
117
+ if (a.y != b.y) {
118
+ return select(-1, 1, a.y > b.y);
119
+ }
120
+ return 0;
121
+ }
122
+
123
+ fn dggs_i64_less(a: vec2u, b: vec2u) -> bool {
124
+ return dggs_i64_compare(a, b) < 0;
125
+ }
126
+
127
+ fn dggs_i64_subtract(a: vec2u, b: vec2u) -> vec2u {
128
+ return dggs_u64_subtract(a, b);
129
+ }
130
+
131
+ fn dggs_i64_to_f32(value: vec2u) -> f32 {
132
+ if (dggs_i64_is_negative(value)) {
133
+ return -dggs_u64_to_f32(dggs_i64_negate(value));
134
+ }
135
+ return dggs_u64_to_f32(value);
136
+ }
137
+
138
+ fn dggs_u32_mask_low(bitCount: u32) -> u32 {
139
+ if (bitCount == 0u) {
140
+ return 0u;
141
+ }
142
+ if (bitCount >= 32u) {
143
+ return 0xffffffffu;
144
+ }
145
+ return (1u << bitCount) - 1u;
146
+ }
147
+
148
+ fn dggs_u64_shift_left(value: vec2u, shift: u32) -> vec2u {
149
+ if (shift == 0u) {
150
+ return value;
151
+ }
152
+ if (shift < 32u) {
153
+ return vec2u((value.x << shift) | (value.y >> (32u - shift)), value.y << shift);
154
+ }
155
+ if (shift == 32u) {
156
+ return vec2u(value.y, 0u);
157
+ }
158
+ if (shift < 64u) {
159
+ return vec2u(value.y << (shift - 32u), 0u);
160
+ }
161
+ return vec2u(0u);
162
+ }
163
+
164
+ fn dggs_u64_shift_right(value: vec2u, shift: u32) -> vec2u {
165
+ if (shift == 0u) {
166
+ return value;
167
+ }
168
+ if (shift < 32u) {
169
+ return vec2u(value.x >> shift, (value.y >> shift) | (value.x << (32u - shift)));
170
+ }
171
+ if (shift == 32u) {
172
+ return vec2u(0u, value.x);
173
+ }
174
+ if (shift < 64u) {
175
+ return vec2u(0u, value.x >> (shift - 32u));
176
+ }
177
+ return vec2u(0u);
178
+ }
179
+
180
+ fn dggs_u64_extract_bits(value: vec2u, bitOffset: u32, bitCount: u32) -> u32 {
181
+ if (bitCount == 0u || bitOffset >= 64u) {
182
+ return 0u;
183
+ }
184
+ let shifted = dggs_u64_shift_right(value, bitOffset);
185
+ return shifted.y & dggs_u32_mask_low(bitCount);
186
+ }
187
+
188
+ fn dggs_u64_set_bits(value: vec2u, bitOffset: u32, bitCount: u32, bits: u32) -> vec2u {
189
+ if (bitCount == 0u || bitOffset >= 64u) {
190
+ return value;
191
+ }
192
+ let bitMask = dggs_u32_mask_low(bitCount);
193
+ let fieldMask = dggs_u64_shift_left(vec2u(0u, bitMask), bitOffset);
194
+ let fieldBits = dggs_u64_shift_left(vec2u(0u, bits & bitMask), bitOffset);
195
+ return (value & vec2u(~fieldMask.x, ~fieldMask.y)) | fieldBits;
196
+ }
197
+
198
+ fn dggs_u64_count_trailing_zeros(value: vec2u) -> u32 {
199
+ if (value.y != 0u) {
200
+ return countTrailingZeros(value.y);
201
+ }
202
+ if (value.x != 0u) {
203
+ return 32u + countTrailingZeros(value.x);
204
+ }
205
+ return 64u;
206
+ }
207
+
208
+ struct DggsA5Cell {
209
+ origin : u32,
210
+ segment : u32,
211
+ resolution : u32,
212
+ valid : u32,
213
+ quintantShift : u32,
214
+ hilbertResolution : u32,
215
+ };
216
+
217
+ struct DggsA5Anchor {
218
+ q : u32,
219
+ offset : vec2i,
220
+ flips : vec2i,
221
+ orientation : u32,
222
+ quintant : u32,
223
+ };
224
+
225
+ struct DggsA5FaceTriangle {
226
+ a : vec2f,
227
+ b : vec2f,
228
+ c : vec2f,
229
+ };
230
+
231
+ struct DggsA5SphericalTriangle {
232
+ a : vec3f,
233
+ b : vec3f,
234
+ c : vec3f,
235
+ };
236
+
237
+ struct DggsH3FaceIJK {
238
+ face : u32,
239
+ coord : vec3i,
240
+ valid : u32,
241
+ };
242
+
243
+ struct DggsH3BoundaryVertex {
244
+ face : u32,
245
+ coord : vec3i,
246
+ resolution : u32,
247
+ valid : u32,
248
+ };
249
+
250
+ fn dggs_boundary_point_to_fp64_split(point : vec2f) -> vec4f {
251
+ return vec4f(point.x, point.y, 0.0, 0.0);
252
+ }
253
+
254
+ fn dggs_a5_positive_mod_i32(value : i32, modulus : i32) -> i32 {
255
+ return ((value % modulus) + modulus) % modulus;
256
+ }
257
+
258
+ fn dggs_a5_has_bit(index : vec2u, bitOffset : u32) -> bool {
259
+ return dggs_u64_extract_bits(index, bitOffset, 1u) != 0u;
260
+ }
261
+
262
+ fn dggs_a5_get_resolution(index : vec2u) -> u32 {
263
+ if (dggs_u64_is_zero(index)) {
264
+ return 0u;
265
+ }
266
+ if (
267
+ dggs_a5_has_bit(index, 0u) ||
268
+ dggs_u64_extract_bits(index, 0u, 3u) == 4u ||
269
+ dggs_u64_extract_bits(index, 0u, 5u) == 16u
270
+ ) {
271
+ return DGGS_A5_MAX_RESOLUTION;
272
+ }
273
+
274
+ var resolution = DGGS_A5_MAX_RESOLUTION - 1u;
275
+ var shifted = dggs_u64_shift_right(index, 1u);
276
+ if (dggs_u64_is_zero(shifted)) {
277
+ return 0u;
278
+ }
279
+
280
+ var remaining = shifted.y;
281
+ if (remaining == 0u) {
282
+ shifted = dggs_u64_shift_right(shifted, 32u);
283
+ resolution -= 16u;
284
+ remaining = shifted.y;
285
+ }
286
+ if ((remaining & 0xffffu) == 0u) {
287
+ remaining >>= 16u;
288
+ resolution -= 8u;
289
+ }
290
+ if (resolution >= 6u && (remaining & 0xffu) == 0u) {
291
+ remaining >>= 8u;
292
+ resolution -= 4u;
293
+ }
294
+ if (resolution >= 4u && (remaining & 0xfu) == 0u) {
295
+ remaining >>= 4u;
296
+ resolution -= 2u;
297
+ }
298
+ loop {
299
+ if ((remaining & 1u) != 0u) {
300
+ break;
301
+ }
302
+ if (resolution == 0u) {
303
+ break;
304
+ }
305
+ resolution -= 1u;
306
+ remaining >>= select(2u, 1u, resolution < DGGS_A5_FIRST_HILBERT_RESOLUTION);
307
+ }
308
+ return resolution;
309
+ }
310
+
311
+ fn dggs_a5_get_origin_first_quintant(origin : u32) -> u32 {
312
+ let values = array<u32, 12>(
313
+ 4u, 2u, 3u, 0u, 2u, 4u, 2u, 2u, 3u, 0u, 3u, 0u
314
+ );
315
+ return values[min(origin, 11u)];
316
+ }
317
+
318
+ fn dggs_a5_get_origin_step(origin : u32) -> i32 {
319
+ let values = array<i32, 12>(
320
+ -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1
321
+ );
322
+ return values[min(origin, 11u)];
323
+ }
324
+
325
+ fn dggs_a5_get_origin_orientation(origin : u32, faceRelativeQuintant : u32) -> u32 {
326
+ // Orientation codes: uv=0, vu=1, uw=2, wu=3, vw=4, wv=5.
327
+ let values = array<u32, 60>(
328
+ 1u, 2u, 4u, 4u, 4u,
329
+ 1u, 0u, 5u, 3u, 2u,
330
+ 3u, 0u, 5u, 3u, 2u,
331
+ 3u, 0u, 5u, 3u, 2u,
332
+ 3u, 2u, 4u, 1u, 2u,
333
+ 1u, 0u, 5u, 3u, 2u,
334
+ 3u, 2u, 4u, 1u, 2u,
335
+ 3u, 2u, 4u, 1u, 2u,
336
+ 3u, 0u, 5u, 3u, 2u,
337
+ 1u, 0u, 5u, 3u, 2u,
338
+ 1u, 0u, 5u, 3u, 2u,
339
+ 3u, 2u, 4u, 1u, 2u
340
+ );
341
+ return values[min(origin, 11u) * 5u + min(faceRelativeQuintant, 4u)];
342
+ }
343
+
344
+ fn dggs_a5_get_origin_angle(origin : u32) -> f32 {
345
+ if (origin == 0u || origin == 9u) {
346
+ return 0.0;
347
+ }
348
+ return DGGS_PI_OVER_5;
349
+ }
350
+
351
+ fn dggs_a5_get_origin_quaternion(origin : u32) -> vec4f {
352
+ let values = array<vec4f, 12>(
353
+ vec4f(0.0, 0.0, 0.0, 1.0),
354
+ vec4f(0.0, 0.525731112119, 0.0, 0.850650808352),
355
+ vec4f(-0.5, 0.688190960236, 0.0, 0.525731112119),
356
+ vec4f(-0.809016994375, -0.262865556060, 0.0, 0.525731112119),
357
+ vec4f(-0.5, 0.162459848116, 0.0, 0.850650808352),
358
+ vec4f(-0.309016994375, -0.425325404176, 0.0, 0.850650808352),
359
+ vec4f(0.309016994375, -0.425325404176, 0.0, 0.850650808352),
360
+ vec4f(0.809016994375, -0.262865556060, 0.0, 0.525731112119),
361
+ vec4f(0.0, -0.850650808352, 0.0, 0.525731112119),
362
+ vec4f(0.0, -1.0, 0.0, 0.0),
363
+ vec4f(0.5, 0.688190960236, 0.0, 0.525731112119),
364
+ vec4f(0.5, 0.162459848116, 0.0, 0.850650808352)
365
+ );
366
+ return values[min(origin, 11u)];
367
+ }
368
+
369
+ fn dggs_a5_quaternion_rotate(point : vec3f, quaternion : vec4f) -> vec3f {
370
+ let q = quaternion.xyz;
371
+ let t = 2.0 * cross(q, point);
372
+ return point + quaternion.w * t + cross(q, t);
373
+ }
374
+
375
+ fn dggs_a5_deserialize(index : vec2u) -> DggsA5Cell {
376
+ if (dggs_u64_is_zero(index)) {
377
+ return DggsA5Cell(0u, 0u, 0u, 0u, DGGS_A5_HILBERT_START_BIT, 0u);
378
+ }
379
+
380
+ let resolution = dggs_a5_get_resolution(index);
381
+ var quintantShift = DGGS_A5_HILBERT_START_BIT;
382
+ var quintantOffset = 0u;
383
+ if (resolution == DGGS_A5_MAX_RESOLUTION) {
384
+ var markerBits = 5u;
385
+ if (dggs_a5_has_bit(index, 0u)) {
386
+ markerBits = 1u;
387
+ } else if (dggs_a5_has_bit(index, 2u)) {
388
+ markerBits = 3u;
389
+ }
390
+ quintantShift = DGGS_A5_HILBERT_START_BIT + markerBits;
391
+ quintantOffset = select(select(40u, 32u, markerBits == 3u), 0u, markerBits == 1u);
392
+ }
393
+
394
+ let topBits = dggs_u64_shift_right(index, quintantShift).y + quintantOffset;
395
+ if (resolution == 0u) {
396
+ if (topBits >= 12u) {
397
+ return DggsA5Cell(0u, 0u, resolution, 0u, quintantShift, 0u);
398
+ }
399
+ return DggsA5Cell(topBits, 0u, resolution, 1u, quintantShift, 0u);
400
+ }
401
+
402
+ let origin = topBits / 5u;
403
+ if (origin >= 12u) {
404
+ return DggsA5Cell(0u, 0u, resolution, 0u, quintantShift, 0u);
405
+ }
406
+ let segment = (topBits + dggs_a5_get_origin_first_quintant(origin)) % 5u;
407
+ let hilbertResolution = select(0u, resolution - 1u, resolution >= 2u);
408
+ return DggsA5Cell(origin, segment, resolution, 1u, quintantShift, hilbertResolution);
409
+ }
410
+
411
+ fn dggs_a5_segment_to_anchor_info(cell : DggsA5Cell) -> DggsA5Anchor {
412
+ let firstQuintant = dggs_a5_get_origin_first_quintant(cell.origin);
413
+ let faceRelativeQuintant = (cell.segment + 5u - firstQuintant) % 5u;
414
+ let orientation = dggs_a5_get_origin_orientation(cell.origin, faceRelativeQuintant);
415
+ let step = dggs_a5_get_origin_step(cell.origin);
416
+ let quintant = u32(dggs_a5_positive_mod_i32(
417
+ i32(firstQuintant) + step * i32(faceRelativeQuintant),
418
+ 5
419
+ ));
420
+ return DggsA5Anchor(0u, vec2i(0), vec2i(1), orientation, quintant);
421
+ }
422
+
423
+ fn dggs_a5_is_reverse_orientation(orientation : u32) -> bool {
424
+ return orientation == 1u || orientation == 3u || orientation == 4u;
425
+ }
426
+
427
+ fn dggs_a5_is_invert_j_orientation(orientation : u32) -> bool {
428
+ return orientation == 5u || orientation == 4u;
429
+ }
430
+
431
+ fn dggs_a5_is_flip_ij_orientation(orientation : u32) -> bool {
432
+ return orientation == 3u || orientation == 2u;
433
+ }
434
+
435
+ fn dggs_a5_pattern_value(index : u32, flipIj : bool) -> u32 {
436
+ let pattern = array<u32, 8>(0u, 1u, 3u, 4u, 5u, 6u, 7u, 2u);
437
+ let flippedPattern = array<u32, 8>(0u, 1u, 2u, 7u, 3u, 4u, 5u, 6u);
438
+ return select(pattern[min(index, 7u)], flippedPattern[min(index, 7u)], flipIj);
439
+ }
440
+
441
+ fn dggs_a5_quaternary_to_flips(digit : u32) -> vec2i {
442
+ if (digit == 1u) {
443
+ return vec2i(1, -1);
444
+ }
445
+ if (digit == 3u) {
446
+ return vec2i(-1, 1);
447
+ }
448
+ return vec2i(1, 1);
449
+ }
450
+
451
+ fn dggs_a5_quaternary_to_kj(digit : u32, flips : vec2i) -> vec2i {
452
+ var p = vec2i(0);
453
+ var q = vec2i(0);
454
+ if (flips.x == 1 && flips.y == 1) {
455
+ p = vec2i(1, 0);
456
+ q = vec2i(0, 1);
457
+ } else if (flips.x == -1 && flips.y == 1) {
458
+ p = vec2i(0, -1);
459
+ q = vec2i(-1, 0);
460
+ } else if (flips.x == 1 && flips.y == -1) {
461
+ p = vec2i(0, 1);
462
+ q = vec2i(1, 0);
463
+ } else {
464
+ p = vec2i(-1, 0);
465
+ q = vec2i(0, -1);
466
+ }
467
+
468
+ if (digit == 1u) {
469
+ return p;
470
+ }
471
+ if (digit == 2u) {
472
+ return p + q;
473
+ }
474
+ if (digit == 3u) {
475
+ return q + 2 * p;
476
+ }
477
+ return vec2i(0);
478
+ }
479
+
480
+ fn dggs_a5_kj_to_ij(kj : vec2i) -> vec2i {
481
+ return vec2i(kj.x - kj.y, kj.y);
482
+ }
483
+
484
+ fn dggs_a5_shift_digits(
485
+ digits : ptr<function, array<u32, 29>>,
486
+ digitIndex : u32,
487
+ flips : vec2i,
488
+ invertJ : bool,
489
+ flipIj : bool
490
+ ) {
491
+ if (digitIndex == 0u) {
492
+ return;
493
+ }
494
+ let parentK = (*digits)[digitIndex];
495
+ let childK = (*digits)[digitIndex - 1u];
496
+ let flipSum = flips.x + flips.y;
497
+ var needsShift = true;
498
+ var first = true;
499
+ if (invertJ != (flipSum == 0)) {
500
+ needsShift = parentK == 1u || parentK == 2u;
501
+ first = parentK == 1u;
502
+ } else {
503
+ needsShift = parentK < 2u;
504
+ first = parentK == 0u;
505
+ }
506
+ if (!needsShift) {
507
+ return;
508
+ }
509
+ let source = select(childK + 4u, childK, first);
510
+ let destination = dggs_a5_pattern_value(source, flipIj);
511
+ (*digits)[digitIndex - 1u] = destination % 4u;
512
+ (*digits)[digitIndex] = u32(dggs_a5_positive_mod_i32(
513
+ i32(parentK) + 4 + i32(destination / 4u) - i32(source / 4u),
514
+ 4
515
+ ));
516
+ }
517
+
518
+ fn dggs_a5_make_anchor(index : vec2u, cell : DggsA5Cell, anchorInfo : DggsA5Anchor) -> DggsA5Anchor {
519
+ if (cell.hilbertResolution == 0u) {
520
+ return anchorInfo;
521
+ }
522
+
523
+ let reverse = dggs_a5_is_reverse_orientation(anchorInfo.orientation);
524
+ let invertJ = dggs_a5_is_invert_j_orientation(anchorInfo.orientation);
525
+ let flipIj = dggs_a5_is_flip_ij_orientation(anchorInfo.orientation);
526
+ let hilbertBits = 2u * cell.hilbertResolution;
527
+ let sBitOffset = cell.quintantShift - hilbertBits;
528
+ var digits : array<u32, 29>;
529
+ var digitIndex = 0u;
530
+ loop {
531
+ if (digitIndex >= cell.hilbertResolution) {
532
+ break;
533
+ }
534
+ var digit = dggs_u64_extract_bits(index, sBitOffset + 2u * digitIndex, 2u);
535
+ if (reverse) {
536
+ digit = 3u - digit;
537
+ }
538
+ digits[digitIndex] = digit;
539
+ digitIndex += 1u;
540
+ }
541
+
542
+ var flips = vec2i(1, 1);
543
+ digitIndex = cell.hilbertResolution;
544
+ loop {
545
+ if (digitIndex == 0u) {
546
+ break;
547
+ }
548
+ digitIndex -= 1u;
549
+ dggs_a5_shift_digits(&digits, digitIndex, flips, invertJ, flipIj);
550
+ flips *= dggs_a5_quaternary_to_flips(digits[digitIndex]);
551
+ }
552
+
553
+ flips = vec2i(1, 1);
554
+ var offset = vec2i(0);
555
+ digitIndex = cell.hilbertResolution;
556
+ loop {
557
+ if (digitIndex == 0u) {
558
+ break;
559
+ }
560
+ digitIndex -= 1u;
561
+ offset *= 2;
562
+ offset += dggs_a5_quaternary_to_kj(digits[digitIndex], flips);
563
+ flips *= dggs_a5_quaternary_to_flips(digits[digitIndex]);
564
+ }
565
+
566
+ var anchorOffset = dggs_a5_kj_to_ij(offset);
567
+ if (flipIj) {
568
+ let originalOffset = anchorOffset;
569
+ anchorOffset = originalOffset.yx;
570
+ if (flips.x == -1) {
571
+ anchorOffset += vec2i(-1, 1);
572
+ }
573
+ if (flips.y == -1) {
574
+ anchorOffset -= vec2i(-1, 1);
575
+ }
576
+ }
577
+ if (invertJ) {
578
+ let i = anchorOffset.x;
579
+ let j = i32(1u << cell.hilbertResolution) - (i + anchorOffset.y);
580
+ flips.x = -flips.x;
581
+ anchorOffset.y = j;
582
+ }
583
+
584
+ return DggsA5Anchor(
585
+ digits[0],
586
+ anchorOffset,
587
+ flips,
588
+ anchorInfo.orientation,
589
+ anchorInfo.quintant
590
+ );
591
+ }
592
+
593
+ fn dggs_a5_rotate_face_point(point : vec2f, quintant : u32) -> vec2f {
594
+ let angle = f32(quintant) * DGGS_TWO_PI_OVER_5;
595
+ let cosine = cos(angle);
596
+ let sine = sin(angle);
597
+ return vec2f(point.x * cosine - point.y * sine, point.x * sine + point.y * cosine);
598
+ }
599
+
600
+ fn dggs_a5_get_base_pentagon_vertex(vertexIndex : u32) -> vec2f {
601
+ let vertices = array<vec2f, 5>(
602
+ vec2f(0.0, 0.0),
603
+ vec2f(0.199381847431, 0.375413822391),
604
+ vec2f(0.618033988750, 0.449027976580),
605
+ vec2f(0.817415836181, 0.073614154188),
606
+ vec2f(0.418652141319, -0.073614154188)
607
+ );
608
+ return vertices[min(vertexIndex, 4u)];
609
+ }
610
+
611
+ fn dggs_a5_get_base_triangle_vertex(vertexIndex : u32) -> vec2f {
612
+ let vertices = array<vec2f, 3>(
613
+ vec2f(0.0, 0.0),
614
+ vec2f(0.618033988750, 0.449027976580),
615
+ vec2f(0.618033988750, -0.449027976580)
616
+ );
617
+ return vertices[min(vertexIndex, 2u)];
618
+ }
619
+
620
+ fn dggs_a5_get_face_vertex(vertexIndex : u32) -> vec2f {
621
+ return dggs_a5_rotate_face_point(dggs_a5_get_base_triangle_vertex(1u), 4u - min(vertexIndex, 4u));
622
+ }
623
+
624
+ fn dggs_a5_get_triangle_vertex(quintant : u32, vertexIndex : u32) -> vec2f {
625
+ return dggs_a5_rotate_face_point(dggs_a5_get_base_triangle_vertex(vertexIndex), quintant);
626
+ }
627
+
628
+ fn dggs_a5_get_pentagon_vertex(
629
+ anchor : DggsA5Anchor,
630
+ hilbertResolution : u32,
631
+ vertexIndex : u32
632
+ ) -> vec2f {
633
+ let flipSum = anchor.flips.x + anchor.flips.y;
634
+ let reflectsY = ((flipSum == -2 || flipSum == 2) && anchor.q > 1u) ||
635
+ (flipSum == 0 && (anchor.q == 0u || anchor.q == 3u));
636
+ let sourceIndex = select(vertexIndex, 4u - vertexIndex, reflectsY);
637
+ var point = dggs_a5_get_base_pentagon_vertex(sourceIndex);
638
+
639
+ if (anchor.flips.x == 1 && anchor.flips.y == -1) {
640
+ point = -point;
641
+ }
642
+ if (reflectsY) {
643
+ point.y = -point.y;
644
+ }
645
+ if (anchor.flips.x == -1 && anchor.flips.y == -1) {
646
+ point = -point;
647
+ } else if (anchor.flips.x == -1) {
648
+ point += vec2f(-0.618033988750, 0.449027976580);
649
+ } else if (anchor.flips.y == -1) {
650
+ point += vec2f(0.618033988750, -0.449027976580);
651
+ }
652
+
653
+ let translation = vec2f(
654
+ f32(anchor.offset.x) * 0.618033988750 + f32(anchor.offset.y) * 0.618033988750,
655
+ f32(anchor.offset.x) * 0.449027976580 + f32(anchor.offset.y) * -0.449027976580
656
+ );
657
+ point = (point + translation) / f32(1u << hilbertResolution);
658
+ return dggs_a5_rotate_face_point(point, anchor.quintant);
659
+ }
660
+
661
+ fn dggs_a5_get_shape_vertex_count(cell : DggsA5Cell) -> u32 {
662
+ return select(5u, 3u, cell.resolution == 1u);
663
+ }
664
+
665
+ fn dggs_a5_get_reversed_shape_index(vertexIndex : u32, shapeVertexCount : u32) -> u32 {
666
+ if (vertexIndex == 0u || vertexIndex >= shapeVertexCount) {
667
+ return 0u;
668
+ }
669
+ return shapeVertexCount - vertexIndex;
670
+ }
671
+
672
+ fn dggs_a5_get_cell_shape_face_point(index : vec2u, cell : DggsA5Cell, shapeIndex : u32) -> vec2f {
673
+ let anchorInfo = dggs_a5_segment_to_anchor_info(cell);
674
+ if (cell.resolution == 0u) {
675
+ return dggs_a5_get_face_vertex(shapeIndex);
676
+ }
677
+ if (cell.resolution == 1u) {
678
+ return dggs_a5_get_triangle_vertex(anchorInfo.quintant, shapeIndex);
679
+ }
680
+ let anchor = dggs_a5_make_anchor(index, cell, anchorInfo);
681
+ return dggs_a5_get_pentagon_vertex(anchor, cell.hilbertResolution, shapeIndex);
682
+ }
683
+
684
+ fn dggs_a5_get_cell_center_face_point(index : vec2u, cell : DggsA5Cell) -> vec2f {
685
+ let shapeVertexCount = dggs_a5_get_shape_vertex_count(cell);
686
+ var center = vec2f(0.0);
687
+ var vertexIndex = 0u;
688
+ loop {
689
+ if (vertexIndex >= shapeVertexCount) {
690
+ break;
691
+ }
692
+ center += dggs_a5_get_cell_shape_face_point(index, cell, vertexIndex);
693
+ vertexIndex += 1u;
694
+ }
695
+ return center / f32(shapeVertexCount);
696
+ }
697
+
698
+ fn dggs_a5_to_polar(point : vec2f) -> vec2f {
699
+ return vec2f(length(point), atan2(point.y, point.x));
700
+ }
701
+
702
+ fn dggs_a5_to_cartesian(thetaPhi : vec2f) -> vec3f {
703
+ let sinPhi = sin(thetaPhi.y);
704
+ return vec3f(sinPhi * cos(thetaPhi.x), sinPhi * sin(thetaPhi.x), cos(thetaPhi.y));
705
+ }
706
+
707
+ fn dggs_a5_normalize_vec3(point : vec3f) -> vec3f {
708
+ let magnitude = length(point);
709
+ if (magnitude < 1.0e-12) {
710
+ return vec3f(0.0, 0.0, 1.0);
711
+ }
712
+ return point / magnitude;
713
+ }
714
+
715
+ fn dggs_a5_get_face_triangle_index(polar : vec2f) -> u32 {
716
+ return u32(dggs_a5_positive_mod_i32(i32(floor(polar.y / DGGS_PI_OVER_5)), 10));
717
+ }
718
+
719
+ fn dggs_a5_normalize_gamma(gamma : f32) -> f32 {
720
+ let segment = gamma / DGGS_TWO_PI_OVER_5;
721
+ return (segment - round(segment)) * DGGS_TWO_PI_OVER_5;
722
+ }
723
+
724
+ fn dggs_a5_should_reflect(polar : vec2f) -> bool {
725
+ return polar.x * cos(dggs_a5_normalize_gamma(polar.y)) > DGGS_A5_DISTANCE_TO_EDGE;
726
+ }
727
+
728
+ fn dggs_a5_get_base_face_triangle(faceTriangleIndex : u32) -> DggsA5FaceTriangle {
729
+ let quintant = ((faceTriangleIndex + 1u) / 2u) % 5u;
730
+ let center = dggs_a5_get_triangle_vertex(quintant, 0u);
731
+ let corner1 = dggs_a5_get_triangle_vertex(quintant, 1u);
732
+ let corner2 = dggs_a5_get_triangle_vertex(quintant, 2u);
733
+ let edgeMidpoint = (corner1 + corner2) * 0.5;
734
+ if ((faceTriangleIndex & 1u) == 0u) {
735
+ return DggsA5FaceTriangle(center, edgeMidpoint, corner1);
736
+ }
737
+ return DggsA5FaceTriangle(center, corner2, edgeMidpoint);
738
+ }
739
+
740
+ fn dggs_a5_get_face_triangle_vertex(triangle : DggsA5FaceTriangle, vertexIndex : u32) -> vec2f {
741
+ if (vertexIndex == 0u) {
742
+ return triangle.a;
743
+ }
744
+ if (vertexIndex == 1u) {
745
+ return triangle.b;
746
+ }
747
+ return triangle.c;
748
+ }
749
+
750
+ fn dggs_a5_get_reflected_face_triangle(
751
+ faceTriangleIndex : u32,
752
+ squashed : bool
753
+ ) -> DggsA5FaceTriangle {
754
+ let baseTriangle = dggs_a5_get_base_face_triangle(faceTriangleIndex);
755
+ let even = (faceTriangleIndex & 1u) == 0u;
756
+ let midpoint = select(baseTriangle.c, baseTriangle.b, even);
757
+ let scale = select(2.0, DGGS_A5_REFLECTED_TRIANGLE_SCALE, squashed);
758
+ let reflectedA = -baseTriangle.a + midpoint * scale;
759
+ return DggsA5FaceTriangle(reflectedA, baseTriangle.c, baseTriangle.b);
760
+ }
761
+
762
+ fn dggs_a5_get_face_triangle(
763
+ faceTriangleIndex : u32,
764
+ reflected : bool,
765
+ squashed : bool
766
+ ) -> DggsA5FaceTriangle {
767
+ if (reflected) {
768
+ return dggs_a5_get_reflected_face_triangle(faceTriangleIndex, squashed);
769
+ }
770
+ return dggs_a5_get_base_face_triangle(faceTriangleIndex);
771
+ }
772
+
773
+ fn dggs_a5_face_triangle_to_spherical_triangle(
774
+ faceTriangleIndex : u32,
775
+ origin : u32,
776
+ reflected : bool
777
+ ) -> DggsA5SphericalTriangle {
778
+ let faceTriangle = dggs_a5_get_face_triangle(faceTriangleIndex, reflected, true);
779
+ let originAngle = dggs_a5_get_origin_angle(origin);
780
+ let quaternion = dggs_a5_get_origin_quaternion(origin);
781
+
782
+ let polarA = dggs_a5_to_polar(faceTriangle.a);
783
+ let polarB = dggs_a5_to_polar(faceTriangle.b);
784
+ let polarC = dggs_a5_to_polar(faceTriangle.c);
785
+ let sphericalA = dggs_a5_quaternion_rotate(
786
+ dggs_a5_to_cartesian(vec2f(polarA.y + originAngle, atan(polarA.x))),
787
+ quaternion
788
+ );
789
+ let sphericalB = dggs_a5_quaternion_rotate(
790
+ dggs_a5_to_cartesian(vec2f(polarB.y + originAngle, atan(polarB.x))),
791
+ quaternion
792
+ );
793
+ let sphericalC = dggs_a5_quaternion_rotate(
794
+ dggs_a5_to_cartesian(vec2f(polarC.y + originAngle, atan(polarC.x))),
795
+ quaternion
796
+ );
797
+ return DggsA5SphericalTriangle(
798
+ dggs_a5_normalize_vec3(sphericalA),
799
+ dggs_a5_normalize_vec3(sphericalB),
800
+ dggs_a5_normalize_vec3(sphericalC)
801
+ );
802
+ }
803
+
804
+ fn dggs_a5_face_to_barycentric(point : vec2f, triangle : DggsA5FaceTriangle) -> vec3f {
805
+ let d31 = triangle.a - triangle.c;
806
+ let d23 = triangle.c - triangle.b;
807
+ let d3p = point - triangle.c;
808
+ let determinant = d23.x * d31.y - d23.y * d31.x;
809
+ if (abs(determinant) < 1.0e-12) {
810
+ return vec3f(1.0, 0.0, 0.0);
811
+ }
812
+ let b0 = (d23.x * d3p.y - d23.y * d3p.x) / determinant;
813
+ let b1 = (d31.x * d3p.y - d31.y * d3p.x) / determinant;
814
+ return vec3f(b0, b1, 1.0 - (b0 + b1));
815
+ }
816
+
817
+ fn dggs_a5_triangle_area(a : vec3f, b : vec3f, c : vec3f) -> f32 {
818
+ let midA = dggs_a5_normalize_vec3((b + c) * 0.5);
819
+ let midB = dggs_a5_normalize_vec3((c + a) * 0.5);
820
+ let midC = dggs_a5_normalize_vec3((a + b) * 0.5);
821
+ let tripleProduct = dot(midA, cross(midB, midC));
822
+ let clamped = clamp(tripleProduct, -1.0, 1.0);
823
+ if (abs(clamped) < 1.0e-8) {
824
+ return 2.0 * clamped;
825
+ }
826
+ return asin(clamped) * 2.0;
827
+ }
828
+
829
+ fn dggs_a5_spherical_triangle_area(triangle : DggsA5SphericalTriangle) -> f32 {
830
+ return dggs_a5_triangle_area(triangle.a, triangle.b, triangle.c);
831
+ }
832
+
833
+ fn dggs_a5_vector_difference(a : vec3f, b : vec3f) -> f32 {
834
+ let midpoint = dggs_a5_normalize_vec3((a + b) * 0.5);
835
+ let crossProduct = cross(a, midpoint);
836
+ let distance = length(crossProduct);
837
+ if (distance < 1.0e-8) {
838
+ return 0.5 * length(a - b);
839
+ }
840
+ return distance;
841
+ }
842
+
843
+ fn dggs_a5_slerp(a : vec3f, b : vec3f, t : f32) -> vec3f {
844
+ let cosineGamma = clamp(dot(a, b), -1.0, 1.0);
845
+ let gamma = acos(cosineGamma);
846
+ if (gamma < 1.0e-8) {
847
+ return dggs_a5_normalize_vec3(mix(a, b, t));
848
+ }
849
+ let sinGamma = sin(gamma);
850
+ if (abs(sinGamma) < 1.0e-8) {
851
+ return dggs_a5_normalize_vec3(mix(a, b, t));
852
+ }
853
+ let weightA = sin((1.0 - t) * gamma) / sinGamma;
854
+ let weightB = sin(t * gamma) / sinGamma;
855
+ return dggs_a5_normalize_vec3(weightA * a + weightB * b);
856
+ }
857
+
858
+ fn dggs_a5_safe_acos(value : f32) -> f32 {
859
+ if (value < 1.0e-3) {
860
+ return 2.0 * value + value * value * value / 3.0;
861
+ }
862
+ return acos(clamp(1.0 - 2.0 * value * value, -1.0, 1.0));
863
+ }
864
+
865
+ fn dggs_a5_polyhedral_inverse_edge(a : vec3f, b : vec3f, edgeHeight : f32) -> vec3f {
866
+ let difference = dggs_a5_vector_difference(a, b);
867
+ let denominator = max(dggs_a5_safe_acos(difference), 1.0e-8);
868
+ let interpolation = dggs_a5_safe_acos(clamp(edgeHeight, 0.0, 1.0) * difference) / denominator;
869
+ return dggs_a5_slerp(a, b, clamp(interpolation, 0.0, 1.0));
870
+ }
871
+
872
+ fn dggs_a5_polyhedral_inverse(
873
+ facePoint : vec2f,
874
+ faceTriangle : DggsA5FaceTriangle,
875
+ sphericalTriangle : DggsA5SphericalTriangle
876
+ ) -> vec3f {
877
+ let barycentric = dggs_a5_face_to_barycentric(facePoint, faceTriangle);
878
+ if (barycentric.x > 0.9999999) {
879
+ return sphericalTriangle.a;
880
+ }
881
+ if (barycentric.y > 0.9999999) {
882
+ return sphericalTriangle.b;
883
+ }
884
+ if (barycentric.z > 0.9999999) {
885
+ return sphericalTriangle.c;
886
+ }
887
+ if (abs(barycentric.z) < 1.0e-6) {
888
+ return dggs_a5_polyhedral_inverse_edge(
889
+ sphericalTriangle.a,
890
+ sphericalTriangle.b,
891
+ 1.0 - barycentric.x
892
+ );
893
+ }
894
+ if (abs(barycentric.y) < 1.0e-6) {
895
+ return dggs_a5_polyhedral_inverse_edge(
896
+ sphericalTriangle.a,
897
+ sphericalTriangle.c,
898
+ 1.0 - barycentric.x
899
+ );
900
+ }
901
+
902
+ let crossBC = cross(sphericalTriangle.b, sphericalTriangle.c);
903
+ let areaABC = dggs_a5_spherical_triangle_area(sphericalTriangle);
904
+ let h = max(1.0 - barycentric.x, 1.0e-8);
905
+ let areaRatio = barycentric.z / h;
906
+ let alpha = areaRatio * areaABC;
907
+ let sineAlpha = sin(alpha);
908
+ let halfSineAlpha = sin(alpha * 0.5);
909
+ let chordCoefficient = 2.0 * halfSineAlpha * halfSineAlpha;
910
+ let dotAB = dot(sphericalTriangle.a, sphericalTriangle.b);
911
+ let dotBC = dot(sphericalTriangle.b, sphericalTriangle.c);
912
+ let dotCA = dot(sphericalTriangle.c, sphericalTriangle.a);
913
+ let lengthBC = length(crossBC);
914
+ let volume = dot(sphericalTriangle.a, crossBC);
915
+ let f = sineAlpha * volume + chordCoefficient * (dotAB * dotBC - dotCA);
916
+ let g = chordCoefficient * lengthBC * (1.0 + dotAB);
917
+ let edgeAngle = max(acos(clamp(dotBC, -1.0, 1.0)), 1.0e-8);
918
+ let q = 2.0 / edgeAngle * atan2(g, f);
919
+ let pointOnBC = dggs_a5_slerp(sphericalTriangle.b, sphericalTriangle.c, q);
920
+ let k = dggs_a5_vector_difference(sphericalTriangle.a, pointOnBC);
921
+ let denominator = max(dggs_a5_safe_acos(k), 1.0e-8);
922
+ let t = dggs_a5_safe_acos(h * k) / denominator;
923
+ return dggs_a5_slerp(sphericalTriangle.a, pointOnBC, t);
924
+ }
925
+
926
+ fn dggs_a5_authalic_inverse(phi : f32) -> f32 {
927
+ let sinPhi = sin(phi);
928
+ let cosPhi = cos(phi);
929
+ let coefficientX = 2.0 * (cosPhi - sinPhi) * (cosPhi + sinPhi);
930
+ var u0 = coefficientX * 4.92842354825238055e-17 + 2.19128723067677184e-14;
931
+ var u1 = coefficientX * u0 + 1.02018123778161003e-11;
932
+ u0 = coefficientX * u1 - u0 + 5.08622073997266026e-9;
933
+ u1 = coefficientX * u0 - u1 + 0.00000288319780486075558;
934
+ u0 = coefficientX * u1 - u0 + 0.00223920899635416575;
935
+ return phi + 2.0 * sinPhi * cosPhi * u0;
936
+ }
937
+
938
+ fn dggs_a5_normalize_longitude(longitude : f32) -> f32 {
939
+ var result = longitude;
940
+ loop {
941
+ if (result < -180.0) {
942
+ result += 360.0;
943
+ } else {
944
+ break;
945
+ }
946
+ }
947
+ loop {
948
+ if (result >= 180.0) {
949
+ result -= 360.0;
950
+ } else {
951
+ break;
952
+ }
953
+ }
954
+ return result;
955
+ }
956
+
957
+ fn dggs_a5_normalize_longitude_to_center(longitude : f32, centerLongitude : f32) -> f32 {
958
+ var result = longitude;
959
+ loop {
960
+ if (result - centerLongitude > 180.0) {
961
+ result -= 360.0;
962
+ } else {
963
+ break;
964
+ }
965
+ }
966
+ loop {
967
+ if (result - centerLongitude < -180.0) {
968
+ result += 360.0;
969
+ } else {
970
+ break;
971
+ }
972
+ }
973
+ return result;
974
+ }
975
+
976
+ fn dggs_a5_sphere_to_lnglat(cartesian : vec3f) -> vec2f {
977
+ let point = dggs_a5_normalize_vec3(cartesian);
978
+ let theta = atan2(point.y, point.x);
979
+ let phi = acos(clamp(point.z, -1.0, 1.0));
980
+ let longitude = dggs_a5_normalize_longitude(theta * DGGS_RADIANS_TO_DEGREES - DGGS_A5_LONGITUDE_OFFSET);
981
+ let authalicLatitude = DGGS_PI_OVER_2 - phi;
982
+ let latitude = dggs_a5_authalic_inverse(authalicLatitude) * DGGS_RADIANS_TO_DEGREES;
983
+ return vec2f(longitude, latitude);
984
+ }
985
+
986
+ fn dggs_a5_face_to_lnglat(facePoint : vec2f, origin : u32) -> vec2f {
987
+ let polar = dggs_a5_to_polar(facePoint);
988
+ let faceTriangleIndex = dggs_a5_get_face_triangle_index(polar);
989
+ let reflected = dggs_a5_should_reflect(polar);
990
+ let faceTriangle = dggs_a5_get_face_triangle(faceTriangleIndex, reflected, false);
991
+ let sphericalTriangle = dggs_a5_face_triangle_to_spherical_triangle(
992
+ faceTriangleIndex,
993
+ origin,
994
+ reflected
995
+ );
996
+ return dggs_a5_sphere_to_lnglat(
997
+ dggs_a5_polyhedral_inverse(facePoint, faceTriangle, sphericalTriangle)
998
+ );
999
+ }
1000
+
1001
+ fn dggs_a5_get_boundary_point(index : vec2u, vertexIndex : u32) -> vec2f {
1002
+ let cell = dggs_a5_deserialize(index);
1003
+ if (cell.valid == 0u || dggs_u64_is_zero(index)) {
1004
+ return vec2f(0.0);
1005
+ }
1006
+
1007
+ let shapeVertexCount = dggs_a5_get_shape_vertex_count(cell);
1008
+ let shapeIndex = dggs_a5_get_reversed_shape_index(vertexIndex, shapeVertexCount);
1009
+ let facePoint = dggs_a5_get_cell_shape_face_point(index, cell, shapeIndex);
1010
+ let centerPoint = dggs_a5_get_cell_center_face_point(index, cell);
1011
+ var lngLat = dggs_a5_face_to_lnglat(facePoint, cell.origin);
1012
+ let centerLngLat = dggs_a5_face_to_lnglat(centerPoint, cell.origin);
1013
+ lngLat.x = dggs_a5_normalize_longitude_to_center(lngLat.x, centerLngLat.x);
1014
+ return lngLat;
1015
+ }
1016
+
1017
+ fn dggs_a5_get_boundary_point_fp64_split(index : vec2u, vertexIndex : u32) -> vec4f {
1018
+ return dggs_boundary_point_to_fp64_split(dggs_a5_get_boundary_point(index, vertexIndex));
1019
+ }
1020
+
1021
+ fn dggs_h3_get_mode(index: vec2u) -> u32 {
1022
+ return dggs_u64_extract_bits(index, 59u, 4u);
1023
+ }
1024
+
1025
+ fn dggs_h3_is_cell_mode(index: vec2u) -> bool {
1026
+ return dggs_h3_get_mode(index) == DGGS_H3_CELL_MODE;
1027
+ }
1028
+
1029
+ fn dggs_h3_get_resolution(index: vec2u) -> u32 {
1030
+ return dggs_u64_extract_bits(index, 52u, 4u);
1031
+ }
1032
+
1033
+ fn dggs_h3_get_base_cell(index: vec2u) -> u32 {
1034
+ return dggs_u64_extract_bits(index, 45u, 7u);
1035
+ }
1036
+
1037
+ fn dggs_h3_digit_bit_offset(resolution: u32) -> u32 {
1038
+ return 3u * (DGGS_H3_MAX_RESOLUTION - resolution);
1039
+ }
1040
+
1041
+ fn dggs_h3_get_digit(index: vec2u, resolution: u32) -> u32 {
1042
+ if (resolution == 0u || resolution > DGGS_H3_MAX_RESOLUTION) {
1043
+ return DGGS_H3_UNUSED_DIGIT;
1044
+ }
1045
+ return dggs_u64_extract_bits(index, dggs_h3_digit_bit_offset(resolution), 3u);
1046
+ }
1047
+
1048
+ fn dggs_h3_is_valid_cell_id(index: vec2u) -> bool {
1049
+ let cellResolution = dggs_h3_get_resolution(index);
1050
+ if (
1051
+ !dggs_h3_is_cell_mode(index) ||
1052
+ cellResolution > DGGS_H3_MAX_RESOLUTION ||
1053
+ dggs_h3_get_base_cell(index) > DGGS_H3_MAX_BASE_CELL
1054
+ ) {
1055
+ return false;
1056
+ }
1057
+
1058
+ var digitResolution = 1u;
1059
+ loop {
1060
+ if (digitResolution > DGGS_H3_MAX_RESOLUTION) {
1061
+ break;
1062
+ }
1063
+
1064
+ let digit = dggs_h3_get_digit(index, digitResolution);
1065
+ if (digitResolution <= cellResolution) {
1066
+ if (digit == DGGS_H3_UNUSED_DIGIT) {
1067
+ return false;
1068
+ }
1069
+ } else if (digit != DGGS_H3_UNUSED_DIGIT) {
1070
+ return false;
1071
+ }
1072
+ digitResolution += 1u;
1073
+ }
1074
+ return true;
1075
+ }
1076
+
1077
+ fn dggs_h3_get_parent(index: vec2u, parentResolution: u32) -> vec2u {
1078
+ let currentResolution = dggs_h3_get_resolution(index);
1079
+ let targetResolution = min(parentResolution, currentResolution);
1080
+ var parent = dggs_u64_set_bits(index, 52u, 4u, targetResolution);
1081
+ var resolution = targetResolution + 1u;
1082
+ loop {
1083
+ if (resolution > DGGS_H3_MAX_RESOLUTION) {
1084
+ break;
1085
+ }
1086
+ parent = dggs_u64_set_bits(
1087
+ parent,
1088
+ dggs_h3_digit_bit_offset(resolution),
1089
+ 3u,
1090
+ DGGS_H3_UNUSED_DIGIT
1091
+ );
1092
+ resolution += 1u;
1093
+ }
1094
+ return parent;
1095
+ }
1096
+
1097
+ fn dggs_h3_positive_angle_rads(angle: f32) -> f32 {
1098
+ var result = angle;
1099
+ if (result < 0.0) {
1100
+ result += DGGS_TWO_PI;
1101
+ }
1102
+ if (result >= DGGS_TWO_PI) {
1103
+ result -= DGGS_TWO_PI;
1104
+ }
1105
+ return result;
1106
+ }
1107
+
1108
+ fn dggs_h3_constrain_longitude(longitude: f32) -> f32 {
1109
+ var result = longitude;
1110
+ loop {
1111
+ if (result <= DGGS_PI) {
1112
+ break;
1113
+ }
1114
+ result -= DGGS_TWO_PI;
1115
+ }
1116
+ loop {
1117
+ if (result >= -DGGS_PI) {
1118
+ break;
1119
+ }
1120
+ result += DGGS_TWO_PI;
1121
+ }
1122
+ return result;
1123
+ }
1124
+
1125
+ fn dggs_h3_is_resolution_class_iii(resolution: u32) -> bool {
1126
+ return (resolution & 1u) != 0u;
1127
+ }
1128
+
1129
+ fn dggs_h3_is_base_cell_pentagon(baseCell: u32) -> bool {
1130
+ return baseCell == 4u ||
1131
+ baseCell == 14u ||
1132
+ baseCell == 24u ||
1133
+ baseCell == 38u ||
1134
+ baseCell == 49u ||
1135
+ baseCell == 58u ||
1136
+ baseCell == 63u ||
1137
+ baseCell == 72u ||
1138
+ baseCell == 83u ||
1139
+ baseCell == 97u ||
1140
+ baseCell == 107u ||
1141
+ baseCell == 117u;
1142
+ }
1143
+
1144
+ fn dggs_h3_get_base_cell_home(baseCell: u32) -> DggsH3FaceIJK {
1145
+ let values = array<vec4i, 122>(
1146
+ vec4i(1, 1, 0, 0),
1147
+ vec4i(2, 1, 1, 0),
1148
+ vec4i(1, 0, 0, 0),
1149
+ vec4i(2, 1, 0, 0),
1150
+ vec4i(0, 2, 0, 0),
1151
+ vec4i(1, 1, 1, 0),
1152
+ vec4i(1, 0, 0, 1),
1153
+ vec4i(2, 0, 0, 0),
1154
+ vec4i(0, 1, 0, 0),
1155
+ vec4i(2, 0, 1, 0),
1156
+ vec4i(1, 0, 1, 0),
1157
+ vec4i(1, 0, 1, 1),
1158
+ vec4i(3, 1, 0, 0),
1159
+ vec4i(3, 1, 1, 0),
1160
+ vec4i(11, 2, 0, 0),
1161
+ vec4i(4, 1, 0, 0),
1162
+ vec4i(0, 0, 0, 0),
1163
+ vec4i(6, 0, 1, 0),
1164
+ vec4i(0, 0, 0, 1),
1165
+ vec4i(2, 0, 1, 1),
1166
+ vec4i(7, 0, 0, 1),
1167
+ vec4i(2, 0, 0, 1),
1168
+ vec4i(0, 1, 1, 0),
1169
+ vec4i(6, 0, 0, 1),
1170
+ vec4i(10, 2, 0, 0),
1171
+ vec4i(6, 0, 0, 0),
1172
+ vec4i(3, 0, 0, 0),
1173
+ vec4i(11, 1, 0, 0),
1174
+ vec4i(4, 1, 1, 0),
1175
+ vec4i(3, 0, 1, 0),
1176
+ vec4i(0, 0, 1, 1),
1177
+ vec4i(4, 0, 0, 0),
1178
+ vec4i(5, 0, 1, 0),
1179
+ vec4i(0, 0, 1, 0),
1180
+ vec4i(7, 0, 1, 0),
1181
+ vec4i(11, 1, 1, 0),
1182
+ vec4i(7, 0, 0, 0),
1183
+ vec4i(10, 1, 0, 0),
1184
+ vec4i(12, 2, 0, 0),
1185
+ vec4i(6, 1, 0, 1),
1186
+ vec4i(7, 1, 0, 1),
1187
+ vec4i(4, 0, 0, 1),
1188
+ vec4i(3, 0, 0, 1),
1189
+ vec4i(3, 0, 1, 1),
1190
+ vec4i(4, 0, 1, 0),
1191
+ vec4i(6, 1, 0, 0),
1192
+ vec4i(11, 0, 0, 0),
1193
+ vec4i(8, 0, 0, 1),
1194
+ vec4i(5, 0, 0, 1),
1195
+ vec4i(14, 2, 0, 0),
1196
+ vec4i(5, 0, 0, 0),
1197
+ vec4i(12, 1, 0, 0),
1198
+ vec4i(10, 1, 1, 0),
1199
+ vec4i(4, 0, 1, 1),
1200
+ vec4i(12, 1, 1, 0),
1201
+ vec4i(7, 1, 0, 0),
1202
+ vec4i(11, 0, 1, 0),
1203
+ vec4i(10, 0, 0, 0),
1204
+ vec4i(13, 2, 0, 0),
1205
+ vec4i(10, 0, 0, 1),
1206
+ vec4i(11, 0, 0, 1),
1207
+ vec4i(9, 0, 1, 0),
1208
+ vec4i(8, 0, 1, 0),
1209
+ vec4i(6, 2, 0, 0),
1210
+ vec4i(8, 0, 0, 0),
1211
+ vec4i(9, 0, 0, 1),
1212
+ vec4i(14, 1, 0, 0),
1213
+ vec4i(5, 1, 0, 1),
1214
+ vec4i(16, 0, 1, 1),
1215
+ vec4i(8, 1, 0, 1),
1216
+ vec4i(5, 1, 0, 0),
1217
+ vec4i(12, 0, 0, 0),
1218
+ vec4i(7, 2, 0, 0),
1219
+ vec4i(12, 0, 1, 0),
1220
+ vec4i(10, 0, 1, 0),
1221
+ vec4i(9, 0, 0, 0),
1222
+ vec4i(13, 1, 0, 0),
1223
+ vec4i(16, 0, 0, 1),
1224
+ vec4i(15, 0, 1, 1),
1225
+ vec4i(15, 0, 1, 0),
1226
+ vec4i(16, 0, 1, 0),
1227
+ vec4i(14, 1, 1, 0),
1228
+ vec4i(13, 1, 1, 0),
1229
+ vec4i(5, 2, 0, 0),
1230
+ vec4i(8, 1, 0, 0),
1231
+ vec4i(14, 0, 0, 0),
1232
+ vec4i(9, 1, 0, 1),
1233
+ vec4i(14, 0, 0, 1),
1234
+ vec4i(17, 0, 0, 1),
1235
+ vec4i(12, 0, 0, 1),
1236
+ vec4i(16, 0, 0, 0),
1237
+ vec4i(17, 0, 1, 1),
1238
+ vec4i(15, 0, 0, 1),
1239
+ vec4i(16, 1, 0, 1),
1240
+ vec4i(9, 1, 0, 0),
1241
+ vec4i(15, 0, 0, 0),
1242
+ vec4i(13, 0, 0, 0),
1243
+ vec4i(8, 2, 0, 0),
1244
+ vec4i(13, 0, 1, 0),
1245
+ vec4i(17, 1, 0, 1),
1246
+ vec4i(19, 0, 1, 0),
1247
+ vec4i(14, 0, 1, 0),
1248
+ vec4i(19, 0, 1, 1),
1249
+ vec4i(17, 0, 1, 0),
1250
+ vec4i(13, 0, 0, 1),
1251
+ vec4i(17, 0, 0, 0),
1252
+ vec4i(16, 1, 0, 0),
1253
+ vec4i(9, 2, 0, 0),
1254
+ vec4i(15, 1, 0, 1),
1255
+ vec4i(15, 1, 0, 0),
1256
+ vec4i(18, 0, 1, 1),
1257
+ vec4i(18, 0, 0, 1),
1258
+ vec4i(19, 0, 0, 1),
1259
+ vec4i(17, 1, 0, 0),
1260
+ vec4i(19, 0, 0, 0),
1261
+ vec4i(18, 0, 1, 0),
1262
+ vec4i(18, 1, 0, 1),
1263
+ vec4i(19, 2, 0, 0),
1264
+ vec4i(19, 1, 0, 0),
1265
+ vec4i(18, 0, 0, 0),
1266
+ vec4i(19, 1, 0, 1),
1267
+ vec4i(18, 1, 0, 0)
1268
+ );
1269
+ let value = values[min(baseCell, DGGS_H3_MAX_BASE_CELL)];
1270
+ return DggsH3FaceIJK(
1271
+ u32(value.x),
1272
+ value.yzw,
1273
+ select(1u, 0u, baseCell > DGGS_H3_MAX_BASE_CELL)
1274
+ );
1275
+ }
1276
+
1277
+ fn dggs_h3_get_face_center_geo(face: u32) -> vec2f {
1278
+ let values = array<vec2f, 20>(
1279
+ vec2f(0.803582649718989942, 1.248397419617396099),
1280
+ vec2f(1.307747883455638156, 2.536945009877921159),
1281
+ vec2f(1.054751253523952054, -1.347517358900396623),
1282
+ vec2f(0.600191595538186799, -0.450603909469755746),
1283
+ vec2f(0.491715428198773866, 0.401988202911306943),
1284
+ vec2f(0.172745327415618701, 1.678146885280433686),
1285
+ vec2f(0.605929321571350690, 2.953923329812411617),
1286
+ vec2f(0.427370518328979641, -1.888876200336285401),
1287
+ vec2f(-0.079066118549212831, -0.733429513380867741),
1288
+ vec2f(-0.230961644455383637, 0.506495587332349035),
1289
+ vec2f(0.079066118549212831, 2.408163140208925497),
1290
+ vec2f(0.230961644455383637, -2.635097066257444203),
1291
+ vec2f(-0.172745327415618701, -1.463445768309359553),
1292
+ vec2f(-0.605929321571350690, -0.187669323777381622),
1293
+ vec2f(-0.427370518328979641, 1.252716453253507838),
1294
+ vec2f(-0.600191595538186799, 2.690988744120037492),
1295
+ vec2f(-0.491715428198773866, -2.739604450678486295),
1296
+ vec2f(-0.803582649718989942, -1.893195233972397139),
1297
+ vec2f(-1.307747883455638156, -0.604647643711872080),
1298
+ vec2f(-1.054751253523952054, 1.794075294689396615)
1299
+ );
1300
+ return values[min(face, 19u)];
1301
+ }
1302
+
1303
+ fn dggs_h3_get_face_axis_azimuths(face: u32) -> vec3f {
1304
+ let values = array<vec3f, 20>(
1305
+ vec3f(5.619958268523939882, 3.525563166130744542, 1.431168063737548730),
1306
+ vec3f(5.760339081714187279, 3.665943979320991689, 1.571548876927796127),
1307
+ vec3f(0.780213654393430055, 4.969003859179821079, 2.874608756786625655),
1308
+ vec3f(0.430469363979999913, 4.619259568766391033, 2.524864466373195467),
1309
+ vec3f(6.130269123335111400, 4.035874020941915804, 1.941478918548720291),
1310
+ vec3f(2.692877706530642877, 0.598482604137447119, 4.787272808923838195),
1311
+ vec3f(2.982963003477243874, 0.888567901084048369, 5.077358105870439581),
1312
+ vec3f(3.532912002790141181, 1.438516900396945656, 5.627307105183336758),
1313
+ vec3f(3.494305004259568154, 1.399909901866372864, 5.588700106652763840),
1314
+ vec3f(3.003214169499538391, 0.908819067106342928, 5.097609271892733906),
1315
+ vec3f(5.930472956509811562, 3.836077854116615875, 1.741682751723420374),
1316
+ vec3f(0.138378484090254847, 4.327168688876645809, 2.232773586483450311),
1317
+ vec3f(0.448714947059150361, 4.637505151845541521, 2.543110049452346120),
1318
+ vec3f(0.158629650112549365, 4.347419854898940135, 2.253024752505744869),
1319
+ vec3f(5.891865957979238535, 3.797470855586042958, 1.703075753192847583),
1320
+ vec3f(2.711123289609793325, 0.616728187216597771, 4.805518392002988683),
1321
+ vec3f(3.294508837434268316, 1.200113735041072948, 5.388903939827463911),
1322
+ vec3f(3.804819692245439833, 1.710424589852244509, 5.899214794638635174),
1323
+ vec3f(3.664438879055192436, 1.570043776661997111, 5.758833981448388027),
1324
+ vec3f(2.361378999196363184, 0.266983896803167583, 4.455774101589558636)
1325
+ );
1326
+ return values[min(face, 19u)];
1327
+ }
1328
+
1329
+ fn dggs_h3_get_max_dim_by_cii_resolution(resolution: u32) -> i32 {
1330
+ let values = array<i32, 17>(
1331
+ 2, -1, 14, -1, 98, -1, 686, -1, 4802, -1, 33614, -1, 235298, -1, 1647086, -1, 11529602
1332
+ );
1333
+ return values[min(resolution, 16u)];
1334
+ }
1335
+
1336
+ fn dggs_h3_get_unit_vector(digit: u32) -> vec3i {
1337
+ if (digit == 1u) {
1338
+ return vec3i(0, 0, 1);
1339
+ }
1340
+ if (digit == 2u) {
1341
+ return vec3i(0, 1, 0);
1342
+ }
1343
+ if (digit == 3u) {
1344
+ return vec3i(0, 1, 1);
1345
+ }
1346
+ if (digit == 4u) {
1347
+ return vec3i(1, 0, 0);
1348
+ }
1349
+ if (digit == 5u) {
1350
+ return vec3i(1, 0, 1);
1351
+ }
1352
+ if (digit == 6u) {
1353
+ return vec3i(1, 1, 0);
1354
+ }
1355
+ return vec3i(0);
1356
+ }
1357
+
1358
+ fn dggs_h3_ijk_normalize(coord: vec3i) -> vec3i {
1359
+ var normalized = coord;
1360
+ if (normalized.x < 0) {
1361
+ normalized.y -= normalized.x;
1362
+ normalized.z -= normalized.x;
1363
+ normalized.x = 0;
1364
+ }
1365
+ if (normalized.y < 0) {
1366
+ normalized.x -= normalized.y;
1367
+ normalized.z -= normalized.y;
1368
+ normalized.y = 0;
1369
+ }
1370
+ if (normalized.z < 0) {
1371
+ normalized.x -= normalized.z;
1372
+ normalized.y -= normalized.z;
1373
+ normalized.z = 0;
1374
+ }
1375
+
1376
+ let minimumValue = min(normalized.x, min(normalized.y, normalized.z));
1377
+ if (minimumValue > 0) {
1378
+ normalized -= vec3i(minimumValue);
1379
+ }
1380
+ return normalized;
1381
+ }
1382
+
1383
+ fn dggs_h3_neighbor(coord: vec3i, digit: u32) -> vec3i {
1384
+ if (digit > 0u && digit < DGGS_H3_UNUSED_DIGIT) {
1385
+ return dggs_h3_ijk_normalize(coord + dggs_h3_get_unit_vector(digit));
1386
+ }
1387
+ return coord;
1388
+ }
1389
+
1390
+ fn dggs_h3_down_ap3(coord: vec3i) -> vec3i {
1391
+ let iVector = vec3i(2, 0, 1) * coord.x;
1392
+ let jVector = vec3i(1, 2, 0) * coord.y;
1393
+ let kVector = vec3i(0, 1, 2) * coord.z;
1394
+ return dggs_h3_ijk_normalize(iVector + jVector + kVector);
1395
+ }
1396
+
1397
+ fn dggs_h3_down_ap3r(coord: vec3i) -> vec3i {
1398
+ let iVector = vec3i(2, 1, 0) * coord.x;
1399
+ let jVector = vec3i(0, 2, 1) * coord.y;
1400
+ let kVector = vec3i(1, 0, 2) * coord.z;
1401
+ return dggs_h3_ijk_normalize(iVector + jVector + kVector);
1402
+ }
1403
+
1404
+ fn dggs_h3_down_ap7(coord: vec3i) -> vec3i {
1405
+ let iVector = vec3i(3, 0, 1) * coord.x;
1406
+ let jVector = vec3i(1, 3, 0) * coord.y;
1407
+ let kVector = vec3i(0, 1, 3) * coord.z;
1408
+ return dggs_h3_ijk_normalize(iVector + jVector + kVector);
1409
+ }
1410
+
1411
+ fn dggs_h3_down_ap7r(coord: vec3i) -> vec3i {
1412
+ let iVector = vec3i(3, 1, 0) * coord.x;
1413
+ let jVector = vec3i(0, 3, 1) * coord.y;
1414
+ let kVector = vec3i(1, 0, 3) * coord.z;
1415
+ return dggs_h3_ijk_normalize(iVector + jVector + kVector);
1416
+ }
1417
+
1418
+ fn dggs_h3_get_center_face_ijk(index: vec2u) -> DggsH3FaceIJK {
1419
+ if (!dggs_h3_is_valid_cell_id(index)) {
1420
+ return DggsH3FaceIJK(0u, vec3i(0), 0u);
1421
+ }
1422
+
1423
+ let baseCell = dggs_h3_get_base_cell(index);
1424
+ if (dggs_h3_is_base_cell_pentagon(baseCell)) {
1425
+ return DggsH3FaceIJK(0u, vec3i(0), 0u);
1426
+ }
1427
+
1428
+ var faceIJK = dggs_h3_get_base_cell_home(baseCell);
1429
+ let cellResolution = dggs_h3_get_resolution(index);
1430
+ var resolution = 1u;
1431
+ loop {
1432
+ if (resolution > cellResolution) {
1433
+ break;
1434
+ }
1435
+
1436
+ if (dggs_h3_is_resolution_class_iii(resolution)) {
1437
+ faceIJK.coord = dggs_h3_down_ap7(faceIJK.coord);
1438
+ } else {
1439
+ faceIJK.coord = dggs_h3_down_ap7r(faceIJK.coord);
1440
+ }
1441
+ faceIJK.coord = dggs_h3_neighbor(faceIJK.coord, dggs_h3_get_digit(index, resolution));
1442
+ resolution += 1u;
1443
+ }
1444
+
1445
+ return faceIJK;
1446
+ }
1447
+
1448
+ fn dggs_h3_get_vertex_offset(resolution: u32, vertexIndex: u32) -> vec3i {
1449
+ let pointIndex = vertexIndex % 6u;
1450
+ if (dggs_h3_is_resolution_class_iii(resolution)) {
1451
+ let vertices = array<vec3i, 6>(
1452
+ vec3i(5, 4, 0),
1453
+ vec3i(1, 5, 0),
1454
+ vec3i(0, 5, 4),
1455
+ vec3i(0, 1, 5),
1456
+ vec3i(4, 0, 5),
1457
+ vec3i(5, 0, 1)
1458
+ );
1459
+ return vertices[pointIndex];
1460
+ }
1461
+
1462
+ let vertices = array<vec3i, 6>(
1463
+ vec3i(2, 1, 0),
1464
+ vec3i(1, 2, 0),
1465
+ vec3i(0, 2, 1),
1466
+ vec3i(0, 1, 2),
1467
+ vec3i(1, 0, 2),
1468
+ vec3i(2, 0, 1)
1469
+ );
1470
+ return vertices[pointIndex];
1471
+ }
1472
+
1473
+ fn dggs_h3_get_boundary_vertex(index: vec2u, vertexIndex: u32) -> DggsH3BoundaryVertex {
1474
+ let center = dggs_h3_get_center_face_ijk(index);
1475
+ if (center.valid == 0u) {
1476
+ return DggsH3BoundaryVertex(0u, vec3i(0), 0u, 0u);
1477
+ }
1478
+
1479
+ let cellResolution = dggs_h3_get_resolution(index);
1480
+ var adjustedResolution = cellResolution;
1481
+ var centerCoord = dggs_h3_down_ap3r(dggs_h3_down_ap3(center.coord));
1482
+ if (dggs_h3_is_resolution_class_iii(cellResolution)) {
1483
+ centerCoord = dggs_h3_down_ap7r(centerCoord);
1484
+ adjustedResolution += 1u;
1485
+ }
1486
+
1487
+ let vertexCoord = dggs_h3_ijk_normalize(
1488
+ centerCoord + dggs_h3_get_vertex_offset(cellResolution, vertexIndex)
1489
+ );
1490
+ let maximumDimension = dggs_h3_get_max_dim_by_cii_resolution(adjustedResolution) * 3;
1491
+ let vertexDimension = vertexCoord.x + vertexCoord.y + vertexCoord.z;
1492
+ if (vertexDimension >= maximumDimension) {
1493
+ return DggsH3BoundaryVertex(center.face, vertexCoord, adjustedResolution, 0u);
1494
+ }
1495
+
1496
+ return DggsH3BoundaryVertex(center.face, vertexCoord, adjustedResolution, 1u);
1497
+ }
1498
+
1499
+ fn dggs_h3_is_single_face_boundary(index: vec2u) -> bool {
1500
+ var vertexIndex = 0u;
1501
+ loop {
1502
+ if (vertexIndex >= 6u) {
1503
+ break;
1504
+ }
1505
+ if (dggs_h3_get_boundary_vertex(index, vertexIndex).valid == 0u) {
1506
+ return false;
1507
+ }
1508
+ vertexIndex += 1u;
1509
+ }
1510
+ return true;
1511
+ }
1512
+
1513
+ fn dggs_h3_ijk_to_hex2d(coord: vec3i) -> vec2f {
1514
+ let i = f32(coord.x - coord.z);
1515
+ let j = f32(coord.y - coord.z);
1516
+ return vec2f(i - 0.5 * j, j * DGGS_H3_SQRT3_2);
1517
+ }
1518
+
1519
+ fn dggs_h3_geo_az_distance_rads(center: vec2f, azimuth: f32, distance: f32) -> vec2f {
1520
+ if (distance < 1.0e-7) {
1521
+ return center;
1522
+ }
1523
+
1524
+ let positiveAzimuth = dggs_h3_positive_angle_rads(azimuth);
1525
+ let latitude = asin(clamp(
1526
+ sin(center.x) * cos(distance) + cos(center.x) * sin(distance) * cos(positiveAzimuth),
1527
+ -1.0,
1528
+ 1.0
1529
+ ));
1530
+ var longitude = 0.0;
1531
+ if (abs(latitude - DGGS_PI_OVER_2) < 1.0e-7) {
1532
+ return vec2f(DGGS_PI_OVER_2, 0.0);
1533
+ }
1534
+ if (abs(latitude + DGGS_PI_OVER_2) < 1.0e-7) {
1535
+ return vec2f(-DGGS_PI_OVER_2, 0.0);
1536
+ }
1537
+
1538
+ let inverseCosLatitude = 1.0 / max(cos(latitude), 1.0e-8);
1539
+ let sinLongitude = clamp(
1540
+ sin(positiveAzimuth) * sin(distance) * inverseCosLatitude,
1541
+ -1.0,
1542
+ 1.0
1543
+ );
1544
+ let cosLongitude = clamp(
1545
+ (cos(distance) - sin(center.x) * sin(latitude)) / max(cos(center.x), 1.0e-8) *
1546
+ inverseCosLatitude,
1547
+ -1.0,
1548
+ 1.0
1549
+ );
1550
+ longitude = dggs_h3_constrain_longitude(center.y + atan2(sinLongitude, cosLongitude));
1551
+ return vec2f(latitude, longitude);
1552
+ }
1553
+
1554
+ fn dggs_h3_hex2d_to_lnglat(point: vec2f, face: u32, resolution: u32, substrate: bool) -> vec2f {
1555
+ var radius = length(point);
1556
+ let center = dggs_h3_get_face_center_geo(face);
1557
+ if (radius < 1.0e-7) {
1558
+ return vec2f(center.y * DGGS_RADIANS_TO_DEGREES, center.x * DGGS_RADIANS_TO_DEGREES);
1559
+ }
1560
+
1561
+ var theta = atan2(point.y, point.x);
1562
+ var resolutionIndex = 0u;
1563
+ loop {
1564
+ if (resolutionIndex >= resolution) {
1565
+ break;
1566
+ }
1567
+ radius *= DGGS_H3_RSQRT7;
1568
+ resolutionIndex += 1u;
1569
+ }
1570
+
1571
+ if (substrate) {
1572
+ radius *= DGGS_H3_ONETHIRD;
1573
+ if (dggs_h3_is_resolution_class_iii(resolution)) {
1574
+ radius *= DGGS_H3_RSQRT7;
1575
+ }
1576
+ } else if (dggs_h3_is_resolution_class_iii(resolution)) {
1577
+ theta = dggs_h3_positive_angle_rads(theta + DGGS_H3_AP7_ROT_RADS);
1578
+ }
1579
+
1580
+ radius = atan(radius * DGGS_H3_RES0_U_GNOMONIC);
1581
+ theta = dggs_h3_positive_angle_rads(dggs_h3_get_face_axis_azimuths(face).x - theta);
1582
+ let latitudeLongitude = dggs_h3_geo_az_distance_rads(center, theta, radius);
1583
+ return vec2f(
1584
+ latitudeLongitude.y * DGGS_RADIANS_TO_DEGREES,
1585
+ latitudeLongitude.x * DGGS_RADIANS_TO_DEGREES
1586
+ );
1587
+ }
1588
+
1589
+ fn dggs_h3_get_boundary_point(index: vec2u, vertexIndex: u32) -> vec2f {
1590
+ if (!dggs_h3_is_single_face_boundary(index)) {
1591
+ return vec2f(0.0);
1592
+ }
1593
+
1594
+ let vertex = dggs_h3_get_boundary_vertex(index, vertexIndex % 6u);
1595
+ let hexPoint = dggs_h3_ijk_to_hex2d(vertex.coord);
1596
+ return dggs_h3_hex2d_to_lnglat(hexPoint, vertex.face, vertex.resolution, true);
1597
+ }
1598
+
1599
+ fn dggs_h3_get_boundary_point_fp64_split(index: vec2u, vertexIndex: u32) -> vec4f {
1600
+ return dggs_boundary_point_to_fp64_split(dggs_h3_get_boundary_point(index, vertexIndex));
1601
+ }
1602
+
1603
+ fn dggs_s2_get_face(index: vec2u) -> u32 {
1604
+ return dggs_u64_extract_bits(index, 61u, 3u);
1605
+ }
1606
+
1607
+ fn dggs_s2_get_level(index: vec2u) -> u32 {
1608
+ let trailingZeros = dggs_u64_count_trailing_zeros(index);
1609
+ if (trailingZeros > 60u) {
1610
+ return 0u;
1611
+ }
1612
+ return DGGS_S2_MAX_LEVEL - trailingZeros / 2u;
1613
+ }
1614
+
1615
+ fn dggs_s2_is_valid_cell_id(index: vec2u) -> bool {
1616
+ let trailingZeros = dggs_u64_count_trailing_zeros(index);
1617
+ return !dggs_u64_is_zero(index) &&
1618
+ dggs_s2_get_face(index) <= 5u &&
1619
+ trailingZeros <= 60u &&
1620
+ trailingZeros % 2u == 0u;
1621
+ }
1622
+
1623
+ fn dggs_s2_get_child_position(index: vec2u, level: u32) -> u32 {
1624
+ if (level == 0u || level > DGGS_S2_MAX_LEVEL) {
1625
+ return 0u;
1626
+ }
1627
+ return dggs_u64_extract_bits(index, 2u * (DGGS_S2_MAX_LEVEL - level) + 1u, 2u);
1628
+ }
1629
+
1630
+ // Packed geohash keys store the geohash length in bits 60..63 and right-align
1631
+ // the base32 character codes in the lower 60 bits, first character first.
1632
+ fn dggs_geohash_get_length(index: vec2u) -> u32 {
1633
+ return min(
1634
+ dggs_u64_extract_bits(index, DGGS_GEOHASH_LENGTH_BIT_OFFSET, 4u),
1635
+ DGGS_GEOHASH_MAX_LENGTH
1636
+ );
1637
+ }
1638
+
1639
+ fn dggs_geohash_get_character(index: vec2u, characterIndex: u32) -> u32 {
1640
+ let length = dggs_geohash_get_length(index);
1641
+ if (characterIndex >= length) {
1642
+ return 0u;
1643
+ }
1644
+ return dggs_u64_extract_bits(index, 5u * (length - characterIndex - 1u), 5u);
1645
+ }
1646
+
1647
+ // Returns vec4(west, south, east, north) in longitude/latitude degrees.
1648
+ fn dggs_geohash_get_bounds(index: vec2u) -> vec4f {
1649
+ let length = dggs_geohash_get_length(index);
1650
+ var west = -180.0;
1651
+ var east = 180.0;
1652
+ var south = -90.0;
1653
+ var north = 90.0;
1654
+ var isLongitude = true;
1655
+ var characterIndex = 0u;
1656
+ loop {
1657
+ if (characterIndex >= length) {
1658
+ break;
1659
+ }
1660
+
1661
+ let character = dggs_geohash_get_character(index, characterIndex);
1662
+ var bitIndex = 0u;
1663
+ loop {
1664
+ if (bitIndex >= 5u) {
1665
+ break;
1666
+ }
1667
+
1668
+ let bit = (character >> (4u - bitIndex)) & 1u;
1669
+ if (isLongitude) {
1670
+ let midpoint = (west + east) * 0.5;
1671
+ if (bit == 0u) {
1672
+ east = midpoint;
1673
+ } else {
1674
+ west = midpoint;
1675
+ }
1676
+ } else {
1677
+ let midpoint = (south + north) * 0.5;
1678
+ if (bit == 0u) {
1679
+ north = midpoint;
1680
+ } else {
1681
+ south = midpoint;
1682
+ }
1683
+ }
1684
+ isLongitude = !isLongitude;
1685
+ bitIndex += 1u;
1686
+ }
1687
+ characterIndex += 1u;
1688
+ }
1689
+
1690
+ return vec4f(west, south, east, north);
1691
+ }
1692
+
1693
+ fn dggs_bounds_get_boundary_point(bounds: vec4f, vertexIndex: u32) -> vec2f {
1694
+ let pointIndex = vertexIndex % 4u;
1695
+ if (pointIndex == 0u) {
1696
+ return vec2f(bounds.x, bounds.w);
1697
+ }
1698
+ if (pointIndex == 1u) {
1699
+ return vec2f(bounds.z, bounds.w);
1700
+ }
1701
+ if (pointIndex == 2u) {
1702
+ return vec2f(bounds.z, bounds.y);
1703
+ }
1704
+ return vec2f(bounds.x, bounds.y);
1705
+ }
1706
+
1707
+ fn dggs_geohash_get_boundary_point(index: vec2u, vertexIndex: u32) -> vec2f {
1708
+ return dggs_bounds_get_boundary_point(dggs_geohash_get_bounds(index), vertexIndex);
1709
+ }
1710
+
1711
+ fn dggs_geohash_get_boundary_point_fp64_split(index: vec2u, vertexIndex: u32) -> vec4f {
1712
+ return dggs_boundary_point_to_fp64_split(dggs_geohash_get_boundary_point(index, vertexIndex));
1713
+ }
1714
+
1715
+ // Packed quadkey keys store the quadkey length in bits 58..63 and right-align
1716
+ // the base4 digits in the lower 58 bits, first digit first.
1717
+ fn dggs_quadkey_get_length(index: vec2u) -> u32 {
1718
+ return min(
1719
+ dggs_u64_extract_bits(index, DGGS_QUADKEY_LENGTH_BIT_OFFSET, 6u),
1720
+ DGGS_QUADKEY_MAX_LENGTH
1721
+ );
1722
+ }
1723
+
1724
+ fn dggs_quadkey_get_digit(index: vec2u, digitIndex: u32) -> u32 {
1725
+ let length = dggs_quadkey_get_length(index);
1726
+ if (digitIndex >= length) {
1727
+ return 0u;
1728
+ }
1729
+ return dggs_u64_extract_bits(index, 2u * (length - digitIndex - 1u), 2u);
1730
+ }
1731
+
1732
+ fn dggs_quadkey_get_tile(index: vec2u) -> vec3u {
1733
+ let length = dggs_quadkey_get_length(index);
1734
+ var tileX = 0u;
1735
+ var tileY = 0u;
1736
+ var digitIndex = 0u;
1737
+ loop {
1738
+ if (digitIndex >= length) {
1739
+ break;
1740
+ }
1741
+
1742
+ let digit = dggs_quadkey_get_digit(index, digitIndex);
1743
+ let mask = 1u << (length - digitIndex - 1u);
1744
+ if ((digit & 1u) != 0u) {
1745
+ tileX |= mask;
1746
+ }
1747
+ if ((digit & 2u) != 0u) {
1748
+ tileY |= mask;
1749
+ }
1750
+ digitIndex += 1u;
1751
+ }
1752
+ return vec3u(tileX, tileY, length);
1753
+ }
1754
+
1755
+ fn dggs_web_mercator_tile_y_to_latitude(tileY: f32, tileScale: f32) -> f32 {
1756
+ let mercatorY = DGGS_PI * (1.0 - 2.0 * tileY / tileScale);
1757
+ return (2.0 * atan(exp(mercatorY)) - DGGS_PI * 0.5) * DGGS_RADIANS_TO_DEGREES;
1758
+ }
1759
+
1760
+ // Returns vec4(west, south, east, north) in longitude/latitude degrees.
1761
+ fn dggs_quadkey_get_bounds(index: vec2u) -> vec4f {
1762
+ let tile = dggs_quadkey_get_tile(index);
1763
+ let tileScale = f32(1u << tile.z);
1764
+ let west = f32(tile.x) / tileScale * 360.0 - 180.0;
1765
+ let east = f32(tile.x + 1u) / tileScale * 360.0 - 180.0;
1766
+ let north = dggs_web_mercator_tile_y_to_latitude(f32(tile.y), tileScale);
1767
+ let south = dggs_web_mercator_tile_y_to_latitude(f32(tile.y + 1u), tileScale);
1768
+ return vec4f(west, south, east, north);
1769
+ }
1770
+
1771
+ fn dggs_quadkey_get_boundary_point(index: vec2u, vertexIndex: u32) -> vec2f {
1772
+ return dggs_bounds_get_boundary_point(dggs_quadkey_get_bounds(index), vertexIndex);
1773
+ }
1774
+
1775
+ fn dggs_quadkey_get_boundary_point_fp64_split(index: vec2u, vertexIndex: u32) -> vec4f {
1776
+ return dggs_boundary_point_to_fp64_split(dggs_quadkey_get_boundary_point(index, vertexIndex));
1777
+ }
1778
+
1779
+ fn dggs_s2_digit_to_xy(digit: u32) -> vec2u {
1780
+ if (digit == 1u) {
1781
+ return vec2u(0u, 1u);
1782
+ }
1783
+ if (digit == 2u) {
1784
+ return vec2u(1u, 1u);
1785
+ }
1786
+ if (digit == 3u) {
1787
+ return vec2u(1u, 0u);
1788
+ }
1789
+ return vec2u(0u, 0u);
1790
+ }
1791
+
1792
+ fn dggs_s2_rotate_and_flip_quadrant(size: u32, point: vec2u, digitXY: vec2u) -> vec2u {
1793
+ var result = point;
1794
+ if (digitXY.y == 0u) {
1795
+ if (digitXY.x == 1u) {
1796
+ result = vec2u(size - 1u - result.x, size - 1u - result.y);
1797
+ }
1798
+ result = result.yx;
1799
+ }
1800
+ return result;
1801
+ }
1802
+
1803
+ fn dggs_s2_get_ij(index: vec2u) -> vec2u {
1804
+ let level = dggs_s2_get_level(index);
1805
+ var point = vec2u(0u);
1806
+ var hilbertLevel = 1u;
1807
+ loop {
1808
+ if (hilbertLevel > level) {
1809
+ break;
1810
+ }
1811
+ let digitLevel = level - hilbertLevel + 1u;
1812
+ let digitXY = dggs_s2_digit_to_xy(dggs_s2_get_child_position(index, digitLevel));
1813
+ let size = 1u << (hilbertLevel - 1u);
1814
+ point = dggs_s2_rotate_and_flip_quadrant(size, point, digitXY);
1815
+ point += size * digitXY;
1816
+ hilbertLevel += 1u;
1817
+ }
1818
+ if ((dggs_s2_get_face(index) & 1u) != 0u) {
1819
+ point = point.yx;
1820
+ }
1821
+ return point;
1822
+ }
1823
+
1824
+ fn dggs_s2_single_st_to_uv(st: f32) -> f32 {
1825
+ if (st >= 0.5) {
1826
+ return (4.0 * st * st - 1.0) / 3.0;
1827
+ }
1828
+ return (1.0 - 4.0 * (1.0 - st) * (1.0 - st)) / 3.0;
1829
+ }
1830
+
1831
+ fn dggs_s2_ij_to_st(ij: vec2u, level: u32, offset: vec2f) -> vec2f {
1832
+ let maxSize = f32(1u << level);
1833
+ return (vec2f(f32(ij.x), f32(ij.y)) + offset) / maxSize;
1834
+ }
1835
+
1836
+ fn dggs_s2_st_to_uv(st: vec2f) -> vec2f {
1837
+ return vec2f(dggs_s2_single_st_to_uv(st.x), dggs_s2_single_st_to_uv(st.y));
1838
+ }
1839
+
1840
+ fn dggs_s2_face_uv_to_xyz(face: u32, uv: vec2f) -> vec3f {
1841
+ if (face == 0u) {
1842
+ return vec3f(1.0, uv.x, uv.y);
1843
+ }
1844
+ if (face == 1u) {
1845
+ return vec3f(-uv.x, 1.0, uv.y);
1846
+ }
1847
+ if (face == 2u) {
1848
+ return vec3f(-uv.x, -uv.y, 1.0);
1849
+ }
1850
+ if (face == 3u) {
1851
+ return vec3f(-1.0, -uv.y, -uv.x);
1852
+ }
1853
+ if (face == 4u) {
1854
+ return vec3f(uv.y, -1.0, -uv.x);
1855
+ }
1856
+ return vec3f(uv.y, uv.x, -1.0);
1857
+ }
1858
+
1859
+ fn dggs_s2_xyz_to_lnglat(xyz: vec3f) -> vec2f {
1860
+ let latitude = atan2(xyz.z, length(xyz.xy)) * DGGS_RADIANS_TO_DEGREES;
1861
+ let longitude = atan2(xyz.y, xyz.x) * DGGS_RADIANS_TO_DEGREES;
1862
+ return vec2f(longitude, latitude);
1863
+ }
1864
+
1865
+ fn dggs_s2_get_boundary_offset(vertexIndex: u32) -> vec2f {
1866
+ let pointIndex = vertexIndex % 4u;
1867
+ if (pointIndex == 1u) {
1868
+ return vec2f(0.0, 1.0);
1869
+ }
1870
+ if (pointIndex == 2u) {
1871
+ return vec2f(1.0, 1.0);
1872
+ }
1873
+ if (pointIndex == 3u) {
1874
+ return vec2f(1.0, 0.0);
1875
+ }
1876
+ return vec2f(0.0, 0.0);
1877
+ }
1878
+
1879
+ fn dggs_s2_get_boundary_point(index: vec2u, vertexIndex: u32) -> vec2f {
1880
+ let level = dggs_s2_get_level(index);
1881
+ let ij = dggs_s2_get_ij(index);
1882
+ let st = dggs_s2_ij_to_st(ij, level, dggs_s2_get_boundary_offset(vertexIndex));
1883
+ let uv = dggs_s2_st_to_uv(st);
1884
+ let xyz = dggs_s2_face_uv_to_xyz(dggs_s2_get_face(index), uv);
1885
+ return dggs_s2_xyz_to_lnglat(xyz);
1886
+ }
1887
+
1888
+ fn dggs_s2_get_boundary_point_fp64_split(index: vec2u, vertexIndex: u32) -> vec4f {
1889
+ return dggs_boundary_point_to_fp64_split(dggs_s2_get_boundary_point(index, vertexIndex));
1890
+ }
1891
+ `;
1892
+ //# sourceMappingURL=dggs-wgsl.js.map