@truelies/osm-dybuf 0.4.2 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -2
- package/grid_index.d.ts +66 -0
- package/grid_index.mjs +207 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -88,7 +88,22 @@ Feature ID usage notes:
|
|
|
88
88
|
`grid_index.mjs` exposes Gridex helpers (integers, pole triangles) aligned with the exporter:
|
|
89
89
|
|
|
90
90
|
```ts
|
|
91
|
-
import {
|
|
91
|
+
import {
|
|
92
|
+
GridUnit,
|
|
93
|
+
Gridex,
|
|
94
|
+
INT_COORD_SCALE,
|
|
95
|
+
CANONICAL_CODE_LEVEL,
|
|
96
|
+
gridexAtLonLat,
|
|
97
|
+
gridCodeAtLonLat,
|
|
98
|
+
gridCodeComponentsAtLonLat,
|
|
99
|
+
lonCodeFromLondex,
|
|
100
|
+
latCodeFromLatdex,
|
|
101
|
+
londexPrefixCodeFromLonCode,
|
|
102
|
+
lonLatCodeRangeForGridex,
|
|
103
|
+
encodeAxisCode,
|
|
104
|
+
decodeAxisCode,
|
|
105
|
+
lonCodeMagnitudeBits,
|
|
106
|
+
} from "@truelies/osm-dybuf/grid_index";
|
|
92
107
|
|
|
93
108
|
const unit = new GridUnit(8); // level 8
|
|
94
109
|
const cell = new Gridex(213, 161);
|
|
@@ -97,6 +112,28 @@ const [minLon, minLat, maxLon, maxLat] = unit.boundsOfGrid(cell);
|
|
|
97
112
|
// parent/child conversion (same rules as Python GridUnit)
|
|
98
113
|
const children = unit.toLowerLevelGridexes(cell); // level 9, 4 cells
|
|
99
114
|
const parent = new GridUnit(9).toUpperLevelGridex(children[0]); // back to level 8
|
|
115
|
+
|
|
116
|
+
// GPS -> gridex / lonCode / latCode / gridCode
|
|
117
|
+
const gridex = gridexAtLonLat(16, 121.56, 25.03);
|
|
118
|
+
const parts = gridCodeComponentsAtLonLat(16, 121.56, 25.03);
|
|
119
|
+
console.log(gridex.londex, gridex.latdex);
|
|
120
|
+
console.log(parts.lonCode, parts.latCode, parts.gridCode);
|
|
121
|
+
|
|
122
|
+
// gridex <-> code
|
|
123
|
+
const lonCode = lonCodeFromLondex(16, -123);
|
|
124
|
+
const latCode = latCodeFromLatdex(16, 456);
|
|
125
|
+
console.log(lonCode, latCode);
|
|
126
|
+
console.log(gridCodeAtLonLat(16, 121.56, 25.03));
|
|
127
|
+
|
|
128
|
+
// canonical prefix / range for coarser level query
|
|
129
|
+
const lonPrefix = londexPrefixCodeFromLonCode(15, lonCode, CANONICAL_CODE_LEVEL);
|
|
130
|
+
const range = lonLatCodeRangeForGridex(15, -3, 4, CANONICAL_CODE_LEVEL);
|
|
131
|
+
console.log(lonPrefix, range.lonCode.from, range.lonCode.to);
|
|
132
|
+
|
|
133
|
+
// axis code roundtrip
|
|
134
|
+
const lonBits = lonCodeMagnitudeBits(CANONICAL_CODE_LEVEL);
|
|
135
|
+
const axisCode = encodeAxisCode(-123, lonBits);
|
|
136
|
+
console.log(decodeAxisCode(axisCode, lonBits)); // -123
|
|
100
137
|
```
|
|
101
138
|
|
|
102
139
|
- `toLowerLevelGridexes(gridex)`:
|
|
@@ -105,6 +142,20 @@ const parent = new GridUnit(9).toUpperLevelGridex(children[0]); // back to level
|
|
|
105
142
|
- `toUpperLevelGridex(gridex)`:
|
|
106
143
|
- returns the parent cell at `level - 1`
|
|
107
144
|
- throws when current unit is level `0`
|
|
145
|
+
- `gridexAtLonLat(level, lon, lat)`:
|
|
146
|
+
- converts GPS directly to a `Gridex`
|
|
147
|
+
- `gridCodeComponentsAtLonLat(level, lon, lat)`:
|
|
148
|
+
- returns `{ gridex, lonCode, latCode, gridCode }`
|
|
149
|
+
- `lonCodeFromLondex(level, londex)` / `latCodeFromLatdex(level, latdex)`:
|
|
150
|
+
- converts axis indices to canonical axis codes
|
|
151
|
+
- `londexPrefixCodeFromLonCode(targetLevel, lonCode, sourceLevel?)`:
|
|
152
|
+
- trims a finer `lonCode` into a coarser-level prefix view
|
|
153
|
+
- `lonLatCodeRangeForGridex(level, londex, latdex, sourceLevel?)`:
|
|
154
|
+
- expands any `lv <= sourceLevel` cell into the corresponding canonical axis-code range
|
|
155
|
+
- `gridCodeAtLonLat(level, lon, lat)` / `gridCodeFromGridex(level, gridex)`:
|
|
156
|
+
- returns the packed `gridCode`
|
|
157
|
+
- `encodeAxisCode(index, magnitudeBits)` / `decodeAxisCode(code, magnitudeBits)`:
|
|
158
|
+
- encodes grid index as `sign bit + (abs(index) - 1)`
|
|
108
159
|
|
|
109
160
|
## Local Development
|
|
110
161
|
|
|
@@ -118,6 +169,9 @@ Unit test example (`tests/grid_index.test.mjs`) covers:
|
|
|
118
169
|
- `gridexesAt` near axis (no zero index cell)
|
|
119
170
|
- `toLowerLevelGridexes` and `toUpperLevelGridex` roundtrip
|
|
120
171
|
- level boundary errors (`lv0` has no upper level, `lv16` has no lower level)
|
|
172
|
+
- canonical axis-code encode/decode roundtrip
|
|
173
|
+
- GPS -> `gridex / lonCode / latCode / gridCode`
|
|
174
|
+
- `lv15` cell -> canonical code range expansion correctness
|
|
121
175
|
|
|
122
176
|
- `npm pack`: build a tarball so other repos can install via `npm install ./path/to/osm-dybuf-*.tgz`
|
|
123
177
|
- `npm link`: link the package locally (`npm link` here, then `npm link @truelies/osm-dybuf` in the consumer repo)
|
|
@@ -139,4 +193,4 @@ Unit test example (`tests/grid_index.test.mjs`) covers:
|
|
|
139
193
|
- `region_numeric_codes.json`: latest region ID table (generated via `scripts/dump_region_codes.py`)
|
|
140
194
|
- `inspect_dybuf.mjs`: CLI tool that uses the package locally
|
|
141
195
|
|
|
142
|
-
When schema IDs or DyBuf layouts change in the exporter, remember to bump the version here and re-publish/install so frontends and tools stay in sync. Version `0.4.
|
|
196
|
+
When schema IDs or DyBuf layouts change in the exporter, remember to bump the version here and re-publish/install so frontends and tools stay in sync. Version `0.4.3` aligns the package with the current `lv0~13` export range, the current frontend feature set (`water_wetland`, `building`, derived `label_*`, no exported `place_label`), the numeric `featureId` parser contract, and the canonical grid conversion helpers shared by Firestore / Redis / frontend indexing.
|
package/grid_index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export declare const INT_COORD_SCALE: number;
|
|
2
2
|
export declare const GRID_FINE_RES: number;
|
|
3
3
|
export declare const GRID_LV0_UNIT: number;
|
|
4
|
+
export declare const MAX_LEVEL: number;
|
|
5
|
+
export declare const CANONICAL_CODE_LEVEL: number;
|
|
4
6
|
export declare class Gridex {
|
|
5
7
|
readonly londex: number;
|
|
6
8
|
readonly latdex: number;
|
|
@@ -47,3 +49,67 @@ export declare class GridUnit {
|
|
|
47
49
|
maxLatdex: number;
|
|
48
50
|
};
|
|
49
51
|
}
|
|
52
|
+
export declare function gridexAtLonLat(level: number, longitude: number, latitude: number): GridexAtLv;
|
|
53
|
+
export declare function gridexStringAtLonLat(level: number, longitude: number, latitude: number): string;
|
|
54
|
+
export declare function lonCodeMagnitudeBits(level: number): number;
|
|
55
|
+
export declare function latCodeMagnitudeBits(level: number): number;
|
|
56
|
+
export declare function encodeAxisCode(index: number, magnitudeBits: number): number;
|
|
57
|
+
export declare function decodeAxisCode(code: number, magnitudeBits: number): number;
|
|
58
|
+
export declare function lonCodeFromLondex(level: number, londex: number): number;
|
|
59
|
+
export declare function latCodeFromLatdex(level: number, latdex: number): number;
|
|
60
|
+
export declare function londexFromLonCode(level: number, lonCode: number): number;
|
|
61
|
+
export declare function latdexFromLatCode(level: number, latCode: number): number;
|
|
62
|
+
export declare function londexPrefixCodeFromLonCode(targetLevel: number, lonCode: number, sourceLevel?: number): number;
|
|
63
|
+
export declare function latdexPrefixCodeFromLatCode(targetLevel: number, latCode: number, sourceLevel?: number): number;
|
|
64
|
+
export declare function lonCodeRangeForLondex(
|
|
65
|
+
level: number,
|
|
66
|
+
londex: number,
|
|
67
|
+
sourceLevel?: number
|
|
68
|
+
): {
|
|
69
|
+
from: number;
|
|
70
|
+
to: number;
|
|
71
|
+
};
|
|
72
|
+
export declare function latCodeRangeForLatdex(
|
|
73
|
+
level: number,
|
|
74
|
+
latdex: number,
|
|
75
|
+
sourceLevel?: number
|
|
76
|
+
): {
|
|
77
|
+
from: number;
|
|
78
|
+
to: number;
|
|
79
|
+
};
|
|
80
|
+
export declare function lonLatCodeRangeForGridex(
|
|
81
|
+
level: number,
|
|
82
|
+
londex: number,
|
|
83
|
+
latdex: number,
|
|
84
|
+
sourceLevel?: number
|
|
85
|
+
): {
|
|
86
|
+
lonCode: {
|
|
87
|
+
from: number;
|
|
88
|
+
to: number;
|
|
89
|
+
};
|
|
90
|
+
latCode: {
|
|
91
|
+
from: number;
|
|
92
|
+
to: number;
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
export declare function gridCodeFromLonLatCodes(level: number, lonCode: number, latCode: number): number;
|
|
96
|
+
export declare function lonLatCodesFromGridCode(
|
|
97
|
+
level: number,
|
|
98
|
+
gridCode: number
|
|
99
|
+
): {
|
|
100
|
+
lonCode: number;
|
|
101
|
+
latCode: number;
|
|
102
|
+
};
|
|
103
|
+
export declare function gridCodeFromGridex(level: number, gridex: Gridex | number, latdex?: number): number;
|
|
104
|
+
export declare function gridexFromGridCode(level: number, gridCode: number): GridexAtLv;
|
|
105
|
+
export declare function gridCodeAtLonLat(level: number, longitude: number, latitude: number): number;
|
|
106
|
+
export declare function gridCodeComponentsAtLonLat(
|
|
107
|
+
level: number,
|
|
108
|
+
longitude: number,
|
|
109
|
+
latitude: number
|
|
110
|
+
): {
|
|
111
|
+
gridex: GridexAtLv;
|
|
112
|
+
lonCode: number;
|
|
113
|
+
latCode: number;
|
|
114
|
+
gridCode: number;
|
|
115
|
+
};
|
package/grid_index.mjs
CHANGED
|
@@ -6,11 +6,12 @@ export const GRID_LV0_UNIT = 30 * INT_COORD_SCALE;
|
|
|
6
6
|
const GRID_LV0_UNIT_FINE = GRID_LV0_UNIT * GRID_FINE_RES;
|
|
7
7
|
const GRID_LV0_LONDEX = 6;
|
|
8
8
|
const GRID_LV0_LATDEX = 3;
|
|
9
|
-
const MAX_LEVEL = 16;
|
|
9
|
+
export const MAX_LEVEL = 16;
|
|
10
10
|
const MAX_LONGITUDE_FINE = 180 * INT_COORD_SCALE * GRID_FINE_RES;
|
|
11
11
|
const MIN_LONGITUDE_FINE = -MAX_LONGITUDE_FINE;
|
|
12
12
|
const MAX_LATITUDE_FINE = 90 * INT_COORD_SCALE * GRID_FINE_RES;
|
|
13
13
|
const MIN_LATITUDE_FINE = -MAX_LATITUDE_FINE;
|
|
14
|
+
export const CANONICAL_CODE_LEVEL = MAX_LEVEL;
|
|
14
15
|
|
|
15
16
|
export class Gridex {
|
|
16
17
|
constructor(londex, latdex) {
|
|
@@ -230,3 +231,208 @@ export class GridUnit {
|
|
|
230
231
|
return { minLondex, maxLondex, minLatdex, maxLatdex };
|
|
231
232
|
}
|
|
232
233
|
}
|
|
234
|
+
|
|
235
|
+
function wrapLongitudeDegrees(longitude) {
|
|
236
|
+
let value = longitude;
|
|
237
|
+
while (value > 180) value -= 360;
|
|
238
|
+
while (value < -180) value += 360;
|
|
239
|
+
return value;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function clampLatitudeDegrees(latitude) {
|
|
243
|
+
return Math.max(-90, Math.min(90, latitude));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function normalizeLonLatDegrees(longitude, latitude) {
|
|
247
|
+
return {
|
|
248
|
+
longitudeInt: Math.round(wrapLongitudeDegrees(longitude) * INT_COORD_SCALE),
|
|
249
|
+
latitudeInt: Math.round(clampLatitudeDegrees(latitude) * INT_COORD_SCALE),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export function gridexAtLonLat(level, longitude, latitude) {
|
|
254
|
+
const unit = new GridUnit(level);
|
|
255
|
+
const { longitudeInt, latitudeInt } = normalizeLonLatDegrees(longitude, latitude);
|
|
256
|
+
const candidates = unit.gridexesAt(longitudeInt, latitudeInt);
|
|
257
|
+
return candidates.find((candidate) => candidate.londex !== 0 && candidate.latdex !== 0)
|
|
258
|
+
?? candidates[0]
|
|
259
|
+
?? unit.makeGridex(0, 0);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function gridexStringAtLonLat(level, longitude, latitude) {
|
|
263
|
+
const gridex = gridexAtLonLat(level, longitude, latitude);
|
|
264
|
+
return `${gridex.londex},${gridex.latdex}`;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function lonCodeMagnitudeBits(level) {
|
|
268
|
+
const unit = new GridUnit(level);
|
|
269
|
+
return Math.ceil(Math.log2(unit.maxLondex));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export function latCodeMagnitudeBits(level) {
|
|
273
|
+
const unit = new GridUnit(level);
|
|
274
|
+
return Math.ceil(Math.log2(unit.maxLatdex));
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export function encodeAxisCode(index, magnitudeBits) {
|
|
278
|
+
if (!Number.isInteger(index) || index === 0) {
|
|
279
|
+
throw new Error(`Grid index must be a non-zero integer: ${index}`);
|
|
280
|
+
}
|
|
281
|
+
const signBit = index > 0 ? 1 : 0;
|
|
282
|
+
const magnitude = Math.abs(index) - 1;
|
|
283
|
+
const maxMagnitude = (1 << magnitudeBits) - 1;
|
|
284
|
+
if (magnitude < 0 || magnitude > maxMagnitude) {
|
|
285
|
+
throw new Error(`Grid index ${index} exceeds ${magnitudeBits} magnitude bits`);
|
|
286
|
+
}
|
|
287
|
+
return (signBit << magnitudeBits) | magnitude;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function decodeAxisCode(code, magnitudeBits) {
|
|
291
|
+
if (!Number.isInteger(code) || code < 0) {
|
|
292
|
+
throw new Error(`Grid code must be a non-negative integer: ${code}`);
|
|
293
|
+
}
|
|
294
|
+
const signBit = code >> magnitudeBits;
|
|
295
|
+
const magnitudeMask = (1 << magnitudeBits) - 1;
|
|
296
|
+
const magnitude = code & magnitudeMask;
|
|
297
|
+
return (magnitude + 1) * (signBit === 1 ? 1 : -1);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export function lonCodeFromLondex(level, londex) {
|
|
301
|
+
return encodeAxisCode(londex, lonCodeMagnitudeBits(level));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export function latCodeFromLatdex(level, latdex) {
|
|
305
|
+
return encodeAxisCode(latdex, latCodeMagnitudeBits(level));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function londexFromLonCode(level, lonCode) {
|
|
309
|
+
return decodeAxisCode(lonCode, lonCodeMagnitudeBits(level));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export function latdexFromLatCode(level, latCode) {
|
|
313
|
+
return decodeAxisCode(latCode, latCodeMagnitudeBits(level));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function axisCodePrefixFromCode(targetLevel, axisCode, sourceLevel, magnitudeBits) {
|
|
317
|
+
if (!Number.isInteger(targetLevel) || targetLevel < 0 || targetLevel > sourceLevel) {
|
|
318
|
+
throw new Error(`targetLevel must be an integer between 0 and ${sourceLevel}: ${targetLevel}`);
|
|
319
|
+
}
|
|
320
|
+
const signBase = 2 ** magnitudeBits;
|
|
321
|
+
const signBit = Math.floor(axisCode / signBase);
|
|
322
|
+
const magnitude = axisCode % signBase;
|
|
323
|
+
const shift = sourceLevel - targetLevel;
|
|
324
|
+
const prefixMagnitude = shift === 0 ? magnitude : Math.floor(magnitude / (2 ** shift)) * (2 ** shift);
|
|
325
|
+
return signBit * signBase + prefixMagnitude;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export function londexPrefixCodeFromLonCode(targetLevel, lonCode, sourceLevel = CANONICAL_CODE_LEVEL) {
|
|
329
|
+
return axisCodePrefixFromCode(targetLevel, lonCode, sourceLevel, lonCodeMagnitudeBits(sourceLevel));
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export function latdexPrefixCodeFromLatCode(targetLevel, latCode, sourceLevel = CANONICAL_CODE_LEVEL) {
|
|
333
|
+
return axisCodePrefixFromCode(targetLevel, latCode, sourceLevel, latCodeMagnitudeBits(sourceLevel));
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function axisCodeRangeForIndex(targetLevel, index, sourceLevel, magnitudeBits) {
|
|
337
|
+
if (!Number.isInteger(sourceLevel) || sourceLevel < 0 || sourceLevel > MAX_LEVEL) {
|
|
338
|
+
throw new Error(`sourceLevel must be an integer between 0 and ${MAX_LEVEL}: ${sourceLevel}`);
|
|
339
|
+
}
|
|
340
|
+
if (!Number.isInteger(targetLevel) || targetLevel < 0 || targetLevel > sourceLevel) {
|
|
341
|
+
throw new Error(`targetLevel must be an integer between 0 and ${sourceLevel}: ${targetLevel}`);
|
|
342
|
+
}
|
|
343
|
+
if (!Number.isInteger(index) || index === 0) {
|
|
344
|
+
throw new Error(`Grid index must be a non-zero integer: ${index}`);
|
|
345
|
+
}
|
|
346
|
+
const signBit = index > 0 ? 1 : 0;
|
|
347
|
+
const shift = sourceLevel - targetLevel;
|
|
348
|
+
const magnitude = Math.abs(index) - 1;
|
|
349
|
+
const fromMagnitude = magnitude << shift;
|
|
350
|
+
const toMagnitude = ((magnitude + 1) << shift) - 1;
|
|
351
|
+
const maxMagnitude = (2 ** magnitudeBits) - 1;
|
|
352
|
+
if (toMagnitude > maxMagnitude) {
|
|
353
|
+
throw new Error(`Grid index ${index} at level ${targetLevel} exceeds source level ${sourceLevel} range`);
|
|
354
|
+
}
|
|
355
|
+
const signBase = 2 ** magnitudeBits;
|
|
356
|
+
return {
|
|
357
|
+
from: signBit * signBase + fromMagnitude,
|
|
358
|
+
to: signBit * signBase + toMagnitude,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export function lonCodeRangeForLondex(level, londex, sourceLevel = CANONICAL_CODE_LEVEL) {
|
|
363
|
+
return axisCodeRangeForIndex(level, londex, sourceLevel, lonCodeMagnitudeBits(sourceLevel));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export function latCodeRangeForLatdex(level, latdex, sourceLevel = CANONICAL_CODE_LEVEL) {
|
|
367
|
+
return axisCodeRangeForIndex(level, latdex, sourceLevel, latCodeMagnitudeBits(sourceLevel));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export function lonLatCodeRangeForGridex(level, londex, latdex, sourceLevel = CANONICAL_CODE_LEVEL) {
|
|
371
|
+
return {
|
|
372
|
+
lonCode: lonCodeRangeForLondex(level, londex, sourceLevel),
|
|
373
|
+
latCode: latCodeRangeForLatdex(level, latdex, sourceLevel),
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
export function gridCodeFromLonLatCodes(level, lonCode, latCode) {
|
|
378
|
+
const latCodeWidth = latCodeMagnitudeBits(level) + 1;
|
|
379
|
+
const latCodeSpan = 2 ** latCodeWidth;
|
|
380
|
+
if (!Number.isInteger(lonCode) || lonCode < 0) {
|
|
381
|
+
throw new Error(`lonCode must be a non-negative integer: ${lonCode}`);
|
|
382
|
+
}
|
|
383
|
+
if (!Number.isInteger(latCode) || latCode < 0 || latCode >= latCodeSpan) {
|
|
384
|
+
throw new Error(`latCode out of range for level ${level}: ${latCode}`);
|
|
385
|
+
}
|
|
386
|
+
return lonCode * latCodeSpan + latCode;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export function lonLatCodesFromGridCode(level, gridCode) {
|
|
390
|
+
if (!Number.isInteger(gridCode) || gridCode < 0) {
|
|
391
|
+
throw new Error(`gridCode must be a non-negative integer: ${gridCode}`);
|
|
392
|
+
}
|
|
393
|
+
const latCodeWidth = latCodeMagnitudeBits(level) + 1;
|
|
394
|
+
const latCodeSpan = 2 ** latCodeWidth;
|
|
395
|
+
return {
|
|
396
|
+
lonCode: Math.floor(gridCode / latCodeSpan),
|
|
397
|
+
latCode: gridCode % latCodeSpan,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export function gridCodeFromGridex(level, gridex, latdex) {
|
|
402
|
+
const londex = typeof gridex === "object" ? gridex.londex : gridex;
|
|
403
|
+
const resolvedLatdex = typeof gridex === "object" ? gridex.latdex : latdex;
|
|
404
|
+
if (!Number.isInteger(londex) || !Number.isInteger(resolvedLatdex)) {
|
|
405
|
+
throw new Error("gridCodeFromGridex expects londex/latdex integers or a Gridex-like object");
|
|
406
|
+
}
|
|
407
|
+
return gridCodeFromLonLatCodes(
|
|
408
|
+
level,
|
|
409
|
+
lonCodeFromLondex(level, londex),
|
|
410
|
+
latCodeFromLatdex(level, resolvedLatdex),
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export function gridexFromGridCode(level, gridCode) {
|
|
415
|
+
const { lonCode, latCode } = lonLatCodesFromGridCode(level, gridCode);
|
|
416
|
+
const unit = new GridUnit(level);
|
|
417
|
+
return unit.makeGridex(
|
|
418
|
+
londexFromLonCode(level, lonCode),
|
|
419
|
+
latdexFromLatCode(level, latCode),
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
export function gridCodeAtLonLat(level, longitude, latitude) {
|
|
424
|
+
const gridex = gridexAtLonLat(level, longitude, latitude);
|
|
425
|
+
return gridCodeFromGridex(level, gridex);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
export function gridCodeComponentsAtLonLat(level, longitude, latitude) {
|
|
429
|
+
const gridex = gridexAtLonLat(level, longitude, latitude);
|
|
430
|
+
const lonCode = lonCodeFromLondex(level, gridex.londex);
|
|
431
|
+
const latCode = latCodeFromLatdex(level, gridex.latdex);
|
|
432
|
+
return {
|
|
433
|
+
gridex,
|
|
434
|
+
lonCode,
|
|
435
|
+
latCode,
|
|
436
|
+
gridCode: gridCodeFromLonLatCodes(level, lonCode, latCode),
|
|
437
|
+
};
|
|
438
|
+
}
|