@math.gl/dggs 5.0.0-alpha.10

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 (118) hide show
  1. package/LICENSE +140 -0
  2. package/README.md +7 -0
  3. package/dist/a5-decoder.d.ts +15 -0
  4. package/dist/a5-decoder.d.ts.map +1 -0
  5. package/dist/a5-decoder.js +36 -0
  6. package/dist/a5-decoder.js.map +1 -0
  7. package/dist/a5.cjs +134 -0
  8. package/dist/a5.cjs.map +6 -0
  9. package/dist/a5.d.ts +2 -0
  10. package/dist/a5.d.ts.map +1 -0
  11. package/dist/a5.js +5 -0
  12. package/dist/a5.js.map +1 -0
  13. package/dist/converters/s2-to-obb-points.d.ts +15 -0
  14. package/dist/converters/s2-to-obb-points.d.ts.map +1 -0
  15. package/dist/converters/s2-to-obb-points.js +60 -0
  16. package/dist/converters/s2-to-obb-points.js.map +1 -0
  17. package/dist/converters/s2-to-region.d.ts +6 -0
  18. package/dist/converters/s2-to-region.d.ts.map +1 -0
  19. package/dist/converters/s2-to-region.js +27 -0
  20. package/dist/converters/s2-to-region.js.map +1 -0
  21. package/dist/dggs-decoder.d.ts +46 -0
  22. package/dist/dggs-decoder.d.ts.map +1 -0
  23. package/dist/dggs-decoder.js +52 -0
  24. package/dist/dggs-decoder.js.map +1 -0
  25. package/dist/geohash-decoder.d.ts +17 -0
  26. package/dist/geohash-decoder.d.ts.map +1 -0
  27. package/dist/geohash-decoder.js +88 -0
  28. package/dist/geohash-decoder.js.map +1 -0
  29. package/dist/geohash.cjs +181 -0
  30. package/dist/geohash.cjs.map +6 -0
  31. package/dist/geohash.d.ts +2 -0
  32. package/dist/geohash.d.ts.map +1 -0
  33. package/dist/geohash.js +5 -0
  34. package/dist/geohash.js.map +1 -0
  35. package/dist/h3-decoder.d.ts +15 -0
  36. package/dist/h3-decoder.d.ts.map +1 -0
  37. package/dist/h3-decoder.js +46 -0
  38. package/dist/h3-decoder.js.map +1 -0
  39. package/dist/h3.cjs +144 -0
  40. package/dist/h3.cjs.map +6 -0
  41. package/dist/h3.d.ts +2 -0
  42. package/dist/h3.d.ts.map +1 -0
  43. package/dist/h3.js +5 -0
  44. package/dist/h3.js.map +1 -0
  45. package/dist/index.cjs +863 -0
  46. package/dist/index.cjs.map +6 -0
  47. package/dist/index.d.ts +27 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +54 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/plus-code-decoder.d.ts +16 -0
  52. package/dist/plus-code-decoder.d.ts.map +1 -0
  53. package/dist/plus-code-decoder.js +50 -0
  54. package/dist/plus-code-decoder.js.map +1 -0
  55. package/dist/plus-code.cjs +161 -0
  56. package/dist/plus-code.cjs.map +6 -0
  57. package/dist/plus-code.d.ts +2 -0
  58. package/dist/plus-code.d.ts.map +1 -0
  59. package/dist/plus-code.js +5 -0
  60. package/dist/plus-code.js.map +1 -0
  61. package/dist/quadkey-decoder.d.ts +14 -0
  62. package/dist/quadkey-decoder.d.ts.map +1 -0
  63. package/dist/quadkey-decoder.js +86 -0
  64. package/dist/quadkey-decoder.js.map +1 -0
  65. package/dist/quadkey.cjs +179 -0
  66. package/dist/quadkey.cjs.map +6 -0
  67. package/dist/quadkey.d.ts +2 -0
  68. package/dist/quadkey.d.ts.map +1 -0
  69. package/dist/quadkey.js +5 -0
  70. package/dist/quadkey.js.map +1 -0
  71. package/dist/s2-decoder.d.ts +36 -0
  72. package/dist/s2-decoder.d.ts.map +1 -0
  73. package/dist/s2-decoder.js +144 -0
  74. package/dist/s2-decoder.js.map +1 -0
  75. package/dist/s2-geometry/s2-geometry.d.ts +33 -0
  76. package/dist/s2-geometry/s2-geometry.d.ts.map +1 -0
  77. package/dist/s2-geometry/s2-geometry.js +249 -0
  78. package/dist/s2-geometry/s2-geometry.js.map +1 -0
  79. package/dist/s2-geometry/s2-to-boundary.d.ts +14 -0
  80. package/dist/s2-geometry/s2-to-boundary.d.ts.map +1 -0
  81. package/dist/s2-geometry/s2-to-boundary.js +60 -0
  82. package/dist/s2-geometry/s2-to-boundary.js.map +1 -0
  83. package/dist/s2-geometry/s2-token.d.ts +43 -0
  84. package/dist/s2-geometry/s2-token.d.ts.map +1 -0
  85. package/dist/s2-geometry/s2-token.js +127 -0
  86. package/dist/s2-geometry/s2-token.js.map +1 -0
  87. package/dist/s2.cjs +543 -0
  88. package/dist/s2.cjs.map +6 -0
  89. package/dist/s2.d.ts +5 -0
  90. package/dist/s2.d.ts.map +1 -0
  91. package/dist/s2.js +7 -0
  92. package/dist/s2.js.map +1 -0
  93. package/dist/unwrap-dggs-boundary.d.ts +12 -0
  94. package/dist/unwrap-dggs-boundary.d.ts.map +1 -0
  95. package/dist/unwrap-dggs-boundary.js +49 -0
  96. package/dist/unwrap-dggs-boundary.js.map +1 -0
  97. package/package.json +80 -0
  98. package/src/a5-decoder.ts +47 -0
  99. package/src/a5.ts +5 -0
  100. package/src/converters/s2-to-obb-points.ts +78 -0
  101. package/src/converters/s2-to-region.ts +30 -0
  102. package/src/dggs-decoder.ts +108 -0
  103. package/src/geohash-decoder.ts +104 -0
  104. package/src/geohash.ts +5 -0
  105. package/src/h3-decoder.ts +58 -0
  106. package/src/h3.ts +5 -0
  107. package/src/index.ts +72 -0
  108. package/src/open-location-code.d.ts +19 -0
  109. package/src/plus-code-decoder.ts +61 -0
  110. package/src/plus-code.ts +5 -0
  111. package/src/quadkey-decoder.ts +103 -0
  112. package/src/quadkey.ts +5 -0
  113. package/src/s2-decoder.ts +157 -0
  114. package/src/s2-geometry/s2-geometry.ts +303 -0
  115. package/src/s2-geometry/s2-to-boundary.ts +76 -0
  116. package/src/s2-geometry/s2-token.ts +139 -0
  117. package/src/s2.ts +15 -0
  118. package/src/unwrap-dggs-boundary.ts +54 -0
@@ -0,0 +1,139 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT and Apache-2.0
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ // s2-geometry is a pure JavaScript port of Google/Niantic's S2 Geometry library
6
+ // which is perfect since it works in the browser.
7
+
8
+ const MAXIMUM_TOKEN_LENGTH = 16;
9
+ const MAXIMUM_S2_INDEX = (1n << 64n) - 1n;
10
+ const VALID_LOWEST_ON_BITS = 0x1555555555555555n;
11
+ const MAXIMUM_LEVEL = 30;
12
+
13
+ // INDEX CALCULATIONS
14
+
15
+ /**
16
+ * Given an S2 token (String) this function convert the token to 64 bit id (Index)
17
+ * 'X' is the empty cell
18
+ * https://github.com/google/s2-geometry-library-java/blob/c04b68bf3197a9c34082327eeb3aec7ab7c85da1/src/com/google/common/geometry/S2CellId.java#L439
19
+ */
20
+ export function getS2IndexFromToken(token: string): bigint {
21
+ if (token === 'X') {
22
+ return 0n;
23
+ }
24
+ if (!isS2TokenValid(token)) {
25
+ throw new Error(`Invalid S2 token: ${token}`);
26
+ }
27
+ // pad token with zeros to make the length 16
28
+ const paddedToken = token.padEnd(MAXIMUM_TOKEN_LENGTH, '0');
29
+ return BigInt(`0x${paddedToken}`);
30
+ }
31
+
32
+ /**
33
+ * Convert a 64 bit number to a string token
34
+ * 'X' is the empty cell
35
+ */
36
+ export function getS2TokenFromIndex(cellId: bigint): string {
37
+ if (cellId === 0n) {
38
+ return 'X';
39
+ }
40
+ if (!isS2IndexValid(cellId)) {
41
+ throw new Error(`Invalid S2 index: ${cellId}`);
42
+ }
43
+ let numZeroDigits = countTrailingZeros(cellId);
44
+
45
+ const remainder = numZeroDigits % 4;
46
+ numZeroDigits = (numZeroDigits - remainder) / 4;
47
+ const trailingZeroHexChars = numZeroDigits;
48
+ numZeroDigits *= 4;
49
+
50
+ const x = cellId >> BigInt(numZeroDigits);
51
+ const hexString = x.toString(16).replace(/0+$/, '');
52
+ const zeroString = Array(17 - trailingZeroHexChars - hexString.length).join('0');
53
+ return zeroString + hexString;
54
+ }
55
+
56
+ /**
57
+ * Returns whether a value is a valid non-empty 64-bit S2 cell index.
58
+ *
59
+ * @param s2Index - Candidate S2 cell index.
60
+ * @returns `true` when the face and level marker encode a valid S2 cell.
61
+ */
62
+ export function isS2IndexValid(s2Index: unknown): s2Index is bigint {
63
+ if (typeof s2Index !== 'bigint' || s2Index <= 0n || s2Index > MAXIMUM_S2_INDEX) {
64
+ return false;
65
+ }
66
+ const face = s2Index >> 61n;
67
+ const lowestOnBit = s2Index & -s2Index;
68
+ return face < 6n && (lowestOnBit & VALID_LOWEST_ON_BITS) !== 0n;
69
+ }
70
+
71
+ /**
72
+ * Returns whether a string is a canonical token for a non-empty S2 cell.
73
+ *
74
+ * The empty-cell sentinel `X` is supported by the conversion functions but is not a valid cell.
75
+ *
76
+ * @param token - Candidate hexadecimal S2 token.
77
+ * @returns `true` when the token canonically encodes a valid S2 cell.
78
+ */
79
+ export function isS2TokenValid(token: unknown): token is string {
80
+ if (typeof token !== 'string' || !/^[0-9a-fA-F]{1,16}$/.test(token) || token.endsWith('0')) {
81
+ return false;
82
+ }
83
+ const paddedToken = token.padEnd(MAXIMUM_TOKEN_LENGTH, '0');
84
+ return isS2IndexValid(BigInt(`0x${paddedToken}`));
85
+ }
86
+
87
+ /**
88
+ * Returns the subdivision level encoded by an S2 cell index.
89
+ *
90
+ * @param s2Index - Valid non-empty S2 cell index.
91
+ * @returns The S2 level in the range `[0, 30]`.
92
+ */
93
+ export function getS2Level(s2Index: bigint): number {
94
+ if (!isS2IndexValid(s2Index)) {
95
+ throw new Error(`Invalid S2 index: ${s2Index}`);
96
+ }
97
+ return (60 - countTrailingZeros(s2Index)) / 2;
98
+ }
99
+
100
+ /**
101
+ * Returns one of the four Hilbert-ordered children of an S2 cell.
102
+ *
103
+ * @param s2Index - Valid S2 cell index below level 30.
104
+ * @param index - Hilbert child position in the range `[0, 3]`.
105
+ * @returns The child S2 cell index.
106
+ */
107
+ export function getS2ChildIndex(s2Index: bigint, index: number): bigint {
108
+ if (!isS2IndexValid(s2Index)) {
109
+ throw new Error(`Invalid S2 index: ${s2Index}`);
110
+ }
111
+ if (!Number.isInteger(index) || index < 0 || index > 3) {
112
+ throw new Error(`Invalid S2 child index: ${index}`);
113
+ }
114
+ if (getS2Level(s2Index) === MAXIMUM_LEVEL) {
115
+ throw new Error('Cannot subdivide an S2 leaf cell');
116
+ }
117
+ // Shift sentinel bit 2 positions to the right.
118
+ const newLsb = lsb(s2Index) >> 2n;
119
+ // Insert child index before the sentinel bit.
120
+ const childCellId: bigint = s2Index + BigInt(2 * index + 1 - 4) * newLsb;
121
+ return childCellId;
122
+ }
123
+
124
+ /**
125
+ * Return the lowest-numbered bit that is on for this cell id
126
+ * @private
127
+ */
128
+ function lsb(cellId: bigint): bigint {
129
+ return cellId & -cellId; // eslint-disable-line
130
+ }
131
+
132
+ function countTrailingZeros(n: bigint): number {
133
+ let count = 0;
134
+ while (n % 2n === 0n) {
135
+ n /= 2n;
136
+ count++;
137
+ }
138
+ return count;
139
+ }
package/src/s2.ts ADDED
@@ -0,0 +1,15 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ export {S2Decoder, getS2Bounds, getS2LngLat, getS2BoundaryFlat} from './s2-decoder';
6
+ export {
7
+ getS2ChildIndex,
8
+ getS2IndexFromToken,
9
+ getS2Level,
10
+ getS2TokenFromIndex,
11
+ isS2IndexValid,
12
+ isS2TokenValid
13
+ } from './s2-geometry/s2-token';
14
+ export {getS2DescendantIndex, getS2IndexFromCell} from './s2-geometry/s2-geometry';
15
+ export type {S2Cell} from './s2-geometry/s2-geometry';
@@ -0,0 +1,54 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ /**
6
+ * Copy a cell boundary, unwrapping longitudes across the antimeridian.
7
+ * @param boundary Open or closed longitude/latitude pairs in degrees.
8
+ * @param referenceLongitude Optional longitude near which to place the first vertex.
9
+ * @returns Fresh pairs with each longitude nearest the preceding longitude. Exact
10
+ * 180-degree ties retain their direction. Latitudes and vertex order are preserved.
11
+ * @remarks Explicit boundaries spanning at least 360 degrees and closed rings with
12
+ * net longitude winding are copied unchanged. Polar cells need additional topology
13
+ * handling. This helper neither splits polygons nor calculates geodesic edges.
14
+ */
15
+ export function unwrapDGGSBoundary(
16
+ boundary: ReadonlyArray<readonly [number, number]>,
17
+ referenceLongitude?: number
18
+ ): [number, number][] {
19
+ const result: [number, number][] = boundary.map(([longitude, latitude]) => [longitude, latitude]);
20
+ if (result.length === 0) {
21
+ return result;
22
+ }
23
+
24
+ let west = Infinity;
25
+ let east = -Infinity;
26
+ for (const [longitude] of boundary) {
27
+ west = Math.min(west, longitude);
28
+ east = Math.max(east, longitude);
29
+ }
30
+ if (east - west >= 360) {
31
+ return result;
32
+ }
33
+
34
+ let previous = referenceLongitude ?? result[0][0];
35
+ for (const point of result) {
36
+ const delta = point[0] - previous;
37
+ if (delta > 180) {
38
+ point[0] -= 360 * Math.ceil((delta - 180) / 360);
39
+ } else if (delta < -180) {
40
+ point[0] += 360 * Math.ceil((-delta - 180) / 360);
41
+ }
42
+ previous = point[0];
43
+ }
44
+
45
+ const first = boundary[0];
46
+ const last = boundary[boundary.length - 1];
47
+ if (first[0] === last[0] && first[1] === last[1]) {
48
+ if (Math.abs(result[result.length - 1][0] - result[0][0]) > 180) {
49
+ return boundary.map(([longitude, latitude]) => [longitude, latitude]);
50
+ }
51
+ result[result.length - 1] = [...result[0]];
52
+ }
53
+ return result;
54
+ }