webdggrid 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,85 +1,256 @@
1
1
  // @ts-ignore
2
2
  import { loadWasm, unloadWasm } from './libdggrid.wasm.js';
3
3
  import { Feature, FeatureCollection, GeoJsonProperties, Polygon, Position } from 'geojson';
4
+
4
5
  /**
5
- * Cell Topology
6
+ * The shape of each cell in the Discrete Global Grid System.
7
+ *
8
+ * DGGRID supports four cell topologies. The most common choice for geospatial
9
+ * analysis is `HEXAGON` because hexagonal cells have equal adjacency (every
10
+ * neighbour shares an edge), uniform area, and minimal boundary-to-area ratio.
6
11
  *
7
12
  * @export
8
- * @enum {String}
13
+ * @enum {string}
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { Topology } from 'webdggrid';
18
+ *
19
+ * dggs.setDggs({ topology: Topology.HEXAGON, ... }, 4);
20
+ * ```
9
21
  */
10
22
  export enum Topology {
23
+ /** Six-sided cells — the default and most widely used topology. */
11
24
  'HEXAGON' = 'HEXAGON',
25
+ /** Three-sided cells. */
12
26
  'TRIANGLE' = 'TRIANGLE',
13
- 'SQUARE' = 'SQUARE',
27
+ /** Four-sided diamond cells (squares rotated 45°). */
14
28
  'DIAMOND' = 'DIAMOND',
15
29
  }
30
+
16
31
  /**
17
- * Projection type
32
+ * The map projection used to place the polyhedron faces onto the sphere.
33
+ *
34
+ * - **ISEA** (Icosahedral Snyder Equal Area) — preserves cell area at the cost
35
+ * of shape distortion. Recommended for most analytical use-cases.
36
+ * - **FULLER** (Fuller/Dymaxion) — minimises shape distortion but does not
37
+ * preserve equal area.
18
38
  *
19
39
  * @export
20
- * @enum {number}
40
+ * @enum {string}
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * import { Projection } from 'webdggrid';
45
+ *
46
+ * dggs.setDggs({ projection: Projection.ISEA, ... }, 4);
47
+ * ```
21
48
  */
22
49
  export enum Projection {
50
+ /** Icosahedral Snyder Equal Area projection — equal-area cells. */
23
51
  'ISEA' = 'ISEA',
52
+ /** Fuller/Dymaxion projection — shape-preserving cells. */
24
53
  'FULLER' = 'FULLER',
25
54
  }
26
55
 
27
56
  /**
28
- * A geographic coordinate
57
+ * A simple geographic coordinate expressed as latitude and longitude in
58
+ * decimal degrees (WGS-84).
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * const coord: Coordinate = { lat: 51.5, lng: -0.1 };
63
+ * ```
29
64
  */
30
65
  export interface Coordinate {
66
+ /** Latitude in decimal degrees. Range: −90 to 90. */
31
67
  lat: number;
68
+ /** Longitude in decimal degrees. Range: −180 to 180. */
32
69
  lng: number;
33
70
  }
34
71
 
35
72
  /**
36
- * Geojson properties type.
37
- * TODO: Better handeling the types
73
+ * GeoJSON `properties` object attached to every cell feature returned by
74
+ * {@link Webdggrid.sequenceNumToGridFeatureCollection}.
75
+ *
76
+ * All numeric identifiers are `BigInt` because DGGRID cell sequence numbers
77
+ * can exceed the safe integer range of IEEE-754 doubles at high resolutions.
78
+ *
79
+ * > **Note for MapLibre / Mapbox users:** structured-clone (used internally
80
+ * > by these libraries' Web Workers) cannot serialise `BigInt`. Convert `id`
81
+ * > to a string before calling `source.setData()`.
38
82
  */
39
83
  export type DGGSGeoJsonProperty = GeoJsonProperties & {
40
84
  /**
41
- * It stores the seq number if exists
85
+ * The DGGS sequence number (cell ID) of this feature.
86
+ * Unique within a given DGGS configuration and resolution.
42
87
  */
43
88
  id?: BigInt;
89
+ /** Column index in an (i, j) address scheme, if available. */
44
90
  i?: BigInt;
91
+ /** Row index in an (i, j) address scheme, if available. */
45
92
  j?: BigInt;
46
93
  }
47
94
 
95
+ /**
96
+ * Full configuration of a Discrete Global Grid System.
97
+ *
98
+ * A DGGS is fully defined by its polyhedron orientation (`poleCoordinates`,
99
+ * `azimuth`), the subdivision scheme (`aperture`), the cell shape
100
+ * (`topology`), and the map projection (`projection`).
101
+ *
102
+ * Pass this object to {@link Webdggrid.setDggs} to switch between grid
103
+ * configurations at runtime.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * const myDggs: IDGGSProps = {
108
+ * poleCoordinates: { lat: 58.28, lng: 11.25 }, // Snyder orientation
109
+ * azimuth: 0,
110
+ * aperture: 4,
111
+ * topology: Topology.HEXAGON,
112
+ * projection: Projection.ISEA,
113
+ * };
114
+ * dggs.setDggs(myDggs, 5);
115
+ * ```
116
+ */
48
117
  export interface IDGGSProps {
118
+ /**
119
+ * Geographic location of the icosahedron pole used to orient the grid.
120
+ * Changing this rotates the entire grid on the globe, which can be used
121
+ * to minimise cell distortion over a region of interest.
122
+ * Defaults to `{ lat: 0, lng: 0 }`.
123
+ */
49
124
  poleCoordinates: Coordinate;
125
+ /**
126
+ * Azimuth of the icosahedron pole in decimal degrees.
127
+ * Rotates the grid around the pole axis. Defaults to `0`.
128
+ */
50
129
  azimuth: number;
130
+ /**
131
+ * Subdivision aperture — the number of child cells each parent cell is
132
+ * divided into when moving to the next finer resolution.
133
+ *
134
+ * | Aperture | Cells at res *r* (HEXAGON/ISEA) |
135
+ * |---|---|
136
+ * | 3 | 2 + 10 × 3^r |
137
+ * | 4 | 2 + 10 × 4^r |
138
+ * | 7 | 2 + 10 × 7^r |
139
+ *
140
+ * Aperture `4` is the most common choice and is the default.
141
+ */
51
142
  aperture: 3 | 4 | 5 | 7;
143
+ /** Shape of each cell. See {@link Topology}. */
52
144
  topology: Topology;
145
+ /** Projection used to map the polyhedron faces onto the sphere. See {@link Projection}. */
53
146
  projection: Projection;
54
147
  }
55
148
 
149
+ /**
150
+ * Rewraps a polygon ring that crosses the antimeridian so that all longitudes
151
+ * are in a contiguous range (some may exceed 180°). This is the format
152
+ * expected by MapLibre GL / Mapbox GL globe projection for antimeridian cells.
153
+ * For renderers that require standard [-180, 180] coordinates, use the raw
154
+ * output from {@link Webdggrid.sequenceNumToGrid} directly.
155
+ */
156
+ export function unwrapAntimeridianRing(ring: Position[]): Position[] {
157
+ const lons = ring.map((p) => p[0]);
158
+ const minLon = Math.min(...lons);
159
+ const maxLon = Math.max(...lons);
160
+ if (maxLon - minLon <= 180) return ring;
161
+ return ring.map(([lon, lat]) => [lon < 0 ? lon + 360 : lon, lat]);
162
+ }
163
+
56
164
  const DEFAULT_RESOLUTION = 1;
57
165
  const DEFAULT_DGGS = {
58
166
  poleCoordinates: { lat: 0, lng: 0 },
59
167
  azimuth: 0,
60
168
  topology: Topology.HEXAGON,
61
169
  projection: Projection.ISEA,
62
- aperture: 7
170
+ aperture: 4
63
171
  } as IDGGSProps;
64
172
 
173
+ /**
174
+ * Main entry point for the WebDggrid library.
175
+ *
176
+ * `Webdggrid` wraps the DGGRID C++ library compiled to WebAssembly and exposes
177
+ * methods for:
178
+ * - **Grid configuration** — choose topology, projection, aperture, and
179
+ * resolution via {@link setDggs} / {@link setResolution}.
180
+ * - **Coordinate conversion** — convert between geographic coordinates and
181
+ * DGGS cell IDs (sequence numbers) with {@link geoToSequenceNum} and
182
+ * {@link sequenceNumToGeo}.
183
+ * - **Grid geometry** — retrieve the polygon boundary of any cell with
184
+ * {@link sequenceNumToGrid} or export a ready-to-render GeoJSON
185
+ * `FeatureCollection` with {@link sequenceNumToGridFeatureCollection}.
186
+ * - **Grid statistics** — query cell counts, areas, and spacings with
187
+ * {@link nCells}, {@link cellAreaKM}, and {@link cellDistKM}.
188
+ *
189
+ * ## Quick start
190
+ *
191
+ * ```ts
192
+ * import { Webdggrid } from 'webdggrid';
193
+ *
194
+ * const dggs = await Webdggrid.load();
195
+ *
196
+ * // Convert a geographic point to its DGGS cell ID at resolution 5
197
+ * const [cellId] = dggs.geoToSequenceNum([[-73.9857, 40.7484]], 5);
198
+ *
199
+ * // Get the polygon boundary of that cell as GeoJSON
200
+ * const geojson = dggs.sequenceNumToGridFeatureCollection([cellId], 5);
201
+ * ```
202
+ *
203
+ * ## Lifecycle
204
+ *
205
+ * The WASM module is a singleton. Call {@link Webdggrid.load} once and reuse
206
+ * the returned instance throughout your application. Call
207
+ * {@link Webdggrid.unload} when you are completely done to free memory.
208
+ */
65
209
  export class Webdggrid {
66
210
 
211
+ /**
212
+ * The active DGGS configuration used by all conversion and statistics
213
+ * methods. Change it at any time via {@link setDggs}.
214
+ *
215
+ * Defaults to ISEA4H (ISEA projection, aperture 4, hexagon topology,
216
+ * pole at 0° N 0° E, azimuth 0°).
217
+ */
67
218
  dggs: IDGGSProps = DEFAULT_DGGS;
219
+
220
+ /**
221
+ * The active grid resolution. Higher values produce finer, smaller cells.
222
+ * The valid range depends on the aperture — for aperture 4 the practical
223
+ * limit is around resolution 15 before cell counts become unwieldy.
224
+ *
225
+ * Change via {@link setResolution} or pass an explicit `resolution`
226
+ * argument to any conversion method.
227
+ *
228
+ * Defaults to `1`.
229
+ */
68
230
  resolution: number = DEFAULT_RESOLUTION;
69
231
 
70
232
  private constructor(protected _module: any) {
71
233
  this._module = _module;
72
-
73
234
  }
74
235
 
75
236
  /**
76
- * Compiles and instantiates the raw wasm.
77
- *
237
+ * Compiles and instantiates the DGGRID WebAssembly module.
238
+ *
239
+ * This is the only way to construct a `Webdggrid` instance. The method is
240
+ * asynchronous because WebAssembly compilation is prohibited on the main
241
+ * thread for buffers larger than 4 KB.
242
+ *
243
+ * ```ts
244
+ * const dggs = await Webdggrid.load();
245
+ * ```
246
+ *
78
247
  * ::: info
79
- * In general WebAssembly compilation is disallowed on the main thread if the buffer size is larger than 4KB, hence forcing `load` to be asynchronous;
248
+ * In general WebAssembly compilation is disallowed on the main thread if
249
+ * the buffer size is larger than 4 KB, hence forcing `load` to be
250
+ * asynchronous.
80
251
  * :::
81
- *
82
- * @returns A promise to an instance of the Webdggrid class.
252
+ *
253
+ * @returns A promise that resolves to a fully initialised `Webdggrid` instance.
83
254
  */
84
255
  static load(): Promise<typeof Webdggrid> {
85
256
  return loadWasm().then((module: any) => {
@@ -88,22 +259,47 @@ export class Webdggrid {
88
259
  }
89
260
 
90
261
  /**
91
- * Unloades the compiled wasm instance.
262
+ * Releases the compiled WASM instance and frees its memory.
263
+ *
264
+ * Call this when your application no longer needs the library. After
265
+ * calling `unload`, any existing `Webdggrid` instances become unusable —
266
+ * you must call {@link load} again to create a new one.
92
267
  */
93
268
  static unload() {
94
269
  unloadWasm();
95
270
  }
96
271
 
97
272
  /**
98
- * @returns The Webdggrid c++ version
273
+ * Returns the version string of the underlying DGGRID C++ library.
274
+ *
275
+ * ```ts
276
+ * console.log(dggs.version()); // e.g. "8.3b"
277
+ * ```
278
+ *
279
+ * @returns The DGGRID C++ library version string.
99
280
  */
100
281
  version(): string {
101
282
  return this._module.Webdggrid.prototype.version();
102
283
  }
103
284
 
104
285
  /**
105
- * Set the main dggs configuration
106
- * @param dggs A dggs object
286
+ * Sets both the DGGS configuration and the resolution in one call.
287
+ *
288
+ * All subsequent conversion and statistics methods will use this
289
+ * configuration unless they receive an explicit `resolution` argument.
290
+ *
291
+ * ```ts
292
+ * dggs.setDggs({
293
+ * poleCoordinates: { lat: 0, lng: 0 },
294
+ * azimuth: 0,
295
+ * aperture: 4,
296
+ * topology: Topology.HEXAGON,
297
+ * projection: Projection.ISEA,
298
+ * }, 5);
299
+ * ```
300
+ *
301
+ * @param dggs - The new DGGS configuration. Defaults to ISEA4H at pole (0,0).
302
+ * @param resolution - The new resolution level. Defaults to `1`.
107
303
  */
108
304
  setDggs(dggs: IDGGSProps = DEFAULT_DGGS, resolution: number = DEFAULT_RESOLUTION) {
109
305
  this.dggs = dggs;
@@ -111,38 +307,66 @@ export class Webdggrid {
111
307
  }
112
308
 
113
309
  /**
114
- * Get the resolution of the current dggs
115
- * @returns {number} the current dggs resolution
116
- * @memberof WebDggrid
310
+ * Returns the currently active grid resolution.
311
+ *
312
+ * ```ts
313
+ * dggs.setResolution(7);
314
+ * console.log(dggs.getResolution()); // 7
315
+ * ```
316
+ *
317
+ * @returns The current resolution level.
117
318
  */
118
319
  getResolution(): number {
119
320
  return this.resolution;
120
321
  }
322
+
121
323
  /**
122
- * Set the resolution of the dggs
123
- * @param {number} [resolution=DEFAULT_RESOLUTION] the resolution. It should be a valid integer
124
- * @memberof WebDggrid
324
+ * Sets the grid resolution used by default in all conversion and
325
+ * statistics methods.
326
+ *
327
+ * ```ts
328
+ * dggs.setResolution(5);
329
+ * const count = dggs.nCells(); // uses resolution 5
330
+ * ```
331
+ *
332
+ * @param resolution - The new resolution level. Must be a positive integer.
125
333
  */
126
334
  setResolution(resolution: number) {
127
335
  this.resolution = resolution;
128
336
  }
129
337
 
130
338
  /**
131
- * test function
132
- *
133
- * @return {*}
134
- * @memberof WebDggrid
339
+ * Internal test helper that invokes the WASM module's `_main` entry point.
340
+ * Not intended for production use.
341
+ * @internal
135
342
  */
136
343
  _main() {
137
344
  return this._module._main();
138
345
  }
139
346
 
140
347
  /**
141
- * @follow Hi
142
- * Returns the number of the cells in specific resolution
143
- * @param {number} [resolution=DEFAULT_RESOLUTION]
144
- * @return {number}
145
- * @memberof WebDggrid
348
+ * Returns the total number of cells that tile the entire globe at the
349
+ * given resolution under the current DGGS configuration.
350
+ *
351
+ * Cell counts grow exponentially with resolution. For the default ISEA4H
352
+ * grid:
353
+ *
354
+ * | Resolution | Approx. cell count |
355
+ * |---|---|
356
+ * | 1 | 42 |
357
+ * | 2 | 162 |
358
+ * | 3 | 642 |
359
+ * | 4 | 2 562 |
360
+ * | 5 | 10 242 |
361
+ * | 6 | 40 962 |
362
+ *
363
+ * ```ts
364
+ * const total = dggs.nCells(3); // 642
365
+ * ```
366
+ *
367
+ * @param resolution - Resolution level to query. Defaults to the instance's
368
+ * current {@link resolution}.
369
+ * @returns Total number of cells at the given resolution.
146
370
  */
147
371
  nCells(resolution: number = DEFAULT_RESOLUTION): number {
148
372
  const {
@@ -154,8 +378,8 @@ export class Webdggrid {
154
378
  } = this.dggs;
155
379
 
156
380
  const cellCount = this._module.nCells(
157
- lat,
158
381
  lng,
382
+ lat,
159
383
  azimuth,
160
384
  aperture,
161
385
  resolution,
@@ -166,6 +390,21 @@ export class Webdggrid {
166
390
  return cellCount as number;
167
391
  }
168
392
 
393
+ /**
394
+ * Returns the average area of a single cell in square kilometres at the
395
+ * given resolution.
396
+ *
397
+ * Because ISEA guarantees equal-area cells, all cells have the same area
398
+ * when using the `ISEA` projection. With `FULLER` the value is an average.
399
+ *
400
+ * ```ts
401
+ * const areakm2 = dggs.cellAreaKM(5);
402
+ * ```
403
+ *
404
+ * @param resolution - Resolution level to query. Defaults to the instance's
405
+ * current {@link resolution}.
406
+ * @returns Average cell area in km².
407
+ */
169
408
  cellAreaKM(resolution: number = DEFAULT_RESOLUTION): number {
170
409
  const {
171
410
  poleCoordinates: { lat, lng },
@@ -175,9 +414,9 @@ export class Webdggrid {
175
414
  aperture,
176
415
  } = this.dggs;
177
416
 
178
- const cellCount = this._module.nCells(
179
- lat,
417
+ const cellCount = this._module.cellAreaKM(
180
418
  lng,
419
+ lat,
181
420
  azimuth,
182
421
  aperture,
183
422
  resolution,
@@ -188,6 +427,21 @@ export class Webdggrid {
188
427
  return cellCount as number;
189
428
  }
190
429
 
430
+ /**
431
+ * Returns the average centre-to-centre distance between neighbouring cells
432
+ * in kilometres at the given resolution.
433
+ *
434
+ * This is useful for estimating spatial join radii or selecting a
435
+ * resolution that matches a target spatial scale.
436
+ *
437
+ * ```ts
438
+ * const spacingKm = dggs.cellDistKM(5);
439
+ * ```
440
+ *
441
+ * @param resolution - Resolution level to query. Defaults to the instance's
442
+ * current {@link resolution}.
443
+ * @returns Average cell spacing in km.
444
+ */
191
445
  cellDistKM(resolution: number = DEFAULT_RESOLUTION): number {
192
446
  const {
193
447
  poleCoordinates: { lat, lng },
@@ -197,9 +451,9 @@ export class Webdggrid {
197
451
  aperture,
198
452
  } = this.dggs;
199
453
 
200
- const cellCount = this._module.nCells(
201
- lat,
454
+ const cellCount = this._module.cellDistKM(
202
455
  lng,
456
+ lat,
203
457
  azimuth,
204
458
  aperture,
205
459
  resolution,
@@ -210,6 +464,22 @@ export class Webdggrid {
210
464
  return cellCount as number;
211
465
  }
212
466
 
467
+ /**
468
+ * Returns the characteristic length scale (CLS) of the grid at the given
469
+ * resolution — defined as the square root of the average cell area.
470
+ *
471
+ * CLS provides a single scalar that summarises the spatial granularity of
472
+ * the grid, useful for comparing resolutions across different DGGS
473
+ * configurations.
474
+ *
475
+ * ```ts
476
+ * const cls = dggs.gridStatCLS(4);
477
+ * ```
478
+ *
479
+ * @param resolution - Resolution level to query. Defaults to the instance's
480
+ * current {@link resolution}.
481
+ * @returns Grid CLS value.
482
+ */
213
483
  gridStatCLS(resolution: number = DEFAULT_RESOLUTION): number {
214
484
  const {
215
485
  poleCoordinates: { lat, lng },
@@ -219,9 +489,9 @@ export class Webdggrid {
219
489
  aperture,
220
490
  } = this.dggs;
221
491
 
222
- const cellCount = this._module.nCells(
223
- lat,
492
+ const cellCount = this._module.gridStatCLS(
224
493
  lng,
494
+ lat,
225
495
  azimuth,
226
496
  aperture,
227
497
  resolution,
@@ -231,11 +501,35 @@ export class Webdggrid {
231
501
 
232
502
  return cellCount as number;
233
503
  }
504
+
234
505
  /**
235
- * Converts an array of geography coordinates to the list of the sequence numbers AKA DggId
236
- * @param coordinates A 2d array of [[lng, lat]] values
237
- * @param resolution [resolution=DEFAULT_RESOLUTION] The dggs resolution
238
- * @returns An array of the DggIds
506
+ * Converts an array of geographic coordinates to their corresponding DGGS
507
+ * cell sequence numbers (cell IDs) at the given resolution.
508
+ *
509
+ * Each coordinate is mapped to the single cell whose boundary contains it.
510
+ * Multiple coordinates that fall within the same cell will return the same
511
+ * sequence number.
512
+ *
513
+ * Coordinates must be supplied in **`[lng, lat]`** order (GeoJSON
514
+ * convention), **not** `[lat, lng]`.
515
+ *
516
+ * ```ts
517
+ * // New York City
518
+ * const ids = dggs.geoToSequenceNum([[-74.006, 40.7128]], 5);
519
+ * console.log(ids); // [12345n]
520
+ *
521
+ * // Multiple points at once
522
+ * const ids2 = dggs.geoToSequenceNum(
523
+ * [[-74.006, 40.7128], [2.3522, 48.8566]],
524
+ * 5
525
+ * );
526
+ * ```
527
+ *
528
+ * @param coordinates - Array of `[lng, lat]` pairs in decimal degrees.
529
+ * @param resolution - Resolution at which to perform the lookup. Defaults
530
+ * to the instance's current {@link resolution}.
531
+ * @returns Array of `BigInt` sequence numbers, one per input coordinate,
532
+ * in the same order.
239
533
  */
240
534
  geoToSequenceNum(
241
535
  coordinates: number[][],
@@ -253,8 +547,8 @@ export class Webdggrid {
253
547
  const yCoords = coordinates.map((coord) => coord[1]);
254
548
 
255
549
  const resultArray = this._module.DgGEO_to_SEQNUM(
256
- lat,
257
550
  lng,
551
+ lat,
258
552
  azimuth,
259
553
  aperture,
260
554
  resolution,
@@ -266,11 +560,24 @@ export class Webdggrid {
266
560
 
267
561
  return resultArray;
268
562
  }
563
+
269
564
  /**
270
- * Convert a sequence number to the [lng,lat] of the center of the related cell
271
- * @param sequenceNum
272
- * @param resolution [resolution=DEFAULT_RESOLUTION]
273
- * @returns An array of [lng,lat]
565
+ * Converts an array of DGGS cell sequence numbers to the geographic
566
+ * coordinates of their centroids.
567
+ *
568
+ * The returned coordinates are in **`[lng, lat]`** order (GeoJSON
569
+ * convention).
570
+ *
571
+ * ```ts
572
+ * const centroids = dggs.sequenceNumToGeo([1n, 2n, 3n], 3);
573
+ * // [[lng0, lat0], [lng1, lat1], [lng2, lat2]]
574
+ * ```
575
+ *
576
+ * @param sequenceNum - Array of `BigInt` cell IDs to look up.
577
+ * @param resolution - Resolution at which the IDs were generated. Defaults
578
+ * to the instance's current {@link resolution}.
579
+ * @returns Array of `[lng, lat]` centroid positions, one per input ID, in
580
+ * the same order.
274
581
  */
275
582
  sequenceNumToGeo(
276
583
  sequenceNum: bigint[],
@@ -285,8 +592,8 @@ export class Webdggrid {
285
592
  } = this.dggs;
286
593
 
287
594
  const resultArray = this._module.SEQNUM_to_GEO(
288
- lat,
289
595
  lng,
596
+ lat,
290
597
  azimuth,
291
598
  aperture,
292
599
  resolution,
@@ -303,11 +610,33 @@ export class Webdggrid {
303
610
 
304
611
  return arrayOfArrays;
305
612
  }
613
+
306
614
  /**
307
- * Converts a set of coordinates to the cell centroid values
308
- * @param coordinates A 2d array of lng and lat values
309
- * @param resolution [resolution=DEFAULT_RESOLUTION] The resolution of the dggs
310
- * @returns An array of dggs cell centroid coordinates
615
+ * Snaps an array of geographic coordinates to the centroid of the DGGS
616
+ * cell that contains each point.
617
+ *
618
+ * This is equivalent to calling {@link geoToSequenceNum} followed by
619
+ * {@link sequenceNumToGeo} but is more efficient because it avoids
620
+ * returning the intermediate sequence numbers.
621
+ *
622
+ * Useful for spatial aggregation: all points that fall within the same
623
+ * cell will map to the identical centroid coordinate.
624
+ *
625
+ * Coordinates must be in **`[lng, lat]`** order.
626
+ *
627
+ * ```ts
628
+ * const snapped = dggs.geoToGeo(
629
+ * [[-74.006, 40.7128], [-74.010, 40.720]],
630
+ * 5
631
+ * );
632
+ * // Both points snap to the same centroid if they share a cell
633
+ * ```
634
+ *
635
+ * @param coordinates - Array of `[lng, lat]` pairs in decimal degrees.
636
+ * @param resolution - Resolution at which to perform the snapping. Defaults
637
+ * to the instance's current {@link resolution}.
638
+ * @returns Array of `[lng, lat]` cell centroid positions, one per input
639
+ * coordinate, in the same order.
311
640
  */
312
641
  geoToGeo(
313
642
  coordinates: number[][],
@@ -325,8 +654,8 @@ export class Webdggrid {
325
654
  const yCoords = coordinates.map((coord) => coord[1]);
326
655
 
327
656
  const resultArray = this._module.GEO_to_GEO(
328
- lat,
329
657
  lng,
658
+ lat,
330
659
  azimuth,
331
660
  aperture,
332
661
  resolution,
@@ -346,11 +675,27 @@ export class Webdggrid {
346
675
  }
347
676
 
348
677
  /**
349
- * Convert an array of sequence numbers to the grid coordinates with format of `[lng,lat]`. The output is an array with the same
350
- * size as input `sequenceNum` and it includes an array of `CoordinateLike` objects.
351
- * @param sequenceNum
352
- * @param resolution [resolution=DEFAULT_RESOLUTION]
353
- * @returns An array of [lng,lat]
678
+ * Returns the polygon boundary vertices for each cell in `sequenceNum`.
679
+ *
680
+ * Each cell is represented as an array of `[lng, lat]` vertex positions.
681
+ * The ring is **not** automatically closed (the first and last vertex are
682
+ * different) close it yourself if your renderer requires it.
683
+ *
684
+ * Prefer {@link sequenceNumToGridFeatureCollection} when you need
685
+ * GeoJSON output ready for a mapping library.
686
+ *
687
+ * ```ts
688
+ * const rings = dggs.sequenceNumToGrid([1n, 2n], 3);
689
+ * // rings[0] = [[lng0,lat0], [lng1,lat1], ..., [lng5,lat5]] (hexagon)
690
+ * ```
691
+ *
692
+ * @param sequenceNum - Array of `BigInt` cell IDs whose boundaries to
693
+ * retrieve.
694
+ * @param resolution - Resolution at which the IDs were generated. Defaults
695
+ * to the instance's current {@link resolution}.
696
+ * @returns A 2-D array: `result[i]` is the vertex ring of `sequenceNum[i]`.
697
+ * Each vertex is a `[lng, lat]` position.
698
+ * @throws If the WASM module encounters an invalid cell ID.
354
699
  */
355
700
  sequenceNumToGrid(
356
701
  sequenceNum: bigint[],
@@ -364,11 +709,13 @@ export class Webdggrid {
364
709
  aperture,
365
710
  } = this.dggs;
366
711
 
712
+ const inputSize = sequenceNum.length;
713
+
367
714
  let resultArray = [];
368
715
  try {
369
716
  resultArray = this._module.SeqNumGrid(
370
- lat,
371
717
  lng,
718
+ lat,
372
719
  azimuth,
373
720
  aperture,
374
721
  resolution,
@@ -381,8 +728,6 @@ export class Webdggrid {
381
728
  throw(e);
382
729
  }
383
730
 
384
- const inputSize = sequenceNum.length;
385
-
386
731
  const allShapeVertexes = resultArray.slice(0, inputSize);
387
732
 
388
733
  const sumVertexes = allShapeVertexes.reduce((accumulator, currentValue) => {
@@ -403,7 +748,7 @@ export class Webdggrid {
403
748
  for (let i = 0; i < numVertexes; i += 1) {
404
749
  coordinates.push([currentShapeXVertexes[i], currentShapeYVertexes[i]]);
405
750
  }
406
- featureSet.push(coordinates);
751
+ featureSet.push(unwrapAntimeridianRing(coordinates));
407
752
  xOffset += numVertexes;
408
753
  yOffset += numVertexes;
409
754
  }
@@ -411,6 +756,39 @@ export class Webdggrid {
411
756
  return featureSet;
412
757
  }
413
758
 
759
+ /**
760
+ * Converts an array of DGGS cell IDs into a GeoJSON `FeatureCollection`
761
+ * where each `Feature` is a `Polygon` representing the cell boundary.
762
+ *
763
+ * This is the primary method for rendering DGGS cells with mapping
764
+ * libraries such as MapLibre GL JS, Leaflet, or deck.gl.
765
+ *
766
+ * Each feature includes:
767
+ * - `geometry` — a closed `Polygon` in `[lng, lat]` coordinate order.
768
+ * - `id` — the cell sequence number (converted to `string` recommended
769
+ * before passing to MapLibre to avoid BigInt serialisation errors).
770
+ * - `properties.id` — same value as `id`, accessible inside layer
771
+ * expressions.
772
+ *
773
+ * ```ts
774
+ * const ids = dggs.geoToSequenceNum([[-74.006, 40.7128]], 5);
775
+ * const fc = dggs.sequenceNumToGridFeatureCollection(ids, 5);
776
+ *
777
+ * // MapLibre / structured-clone safe: convert BigInt → string
778
+ * fc.features.forEach(f => {
779
+ * if (typeof f.id === 'bigint') f.id = f.id.toString();
780
+ * if (f.properties?.id) f.properties.id = f.properties.id.toString();
781
+ * });
782
+ *
783
+ * map.getSource('grid').setData(fc);
784
+ * ```
785
+ *
786
+ * @param sequenceNum - Array of `BigInt` cell IDs to convert.
787
+ * @param resolution - Resolution at which the IDs were generated. Defaults
788
+ * to the instance's current {@link resolution}.
789
+ * @returns A GeoJSON `FeatureCollection` of `Polygon` features, one per
790
+ * input cell ID.
791
+ */
414
792
  sequenceNumToGridFeatureCollection(
415
793
  sequenceNum: bigint[],
416
794
  resolution: number = DEFAULT_RESOLUTION