@xyo-network/quadkey 2.38.7 → 2.38.9

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/src/Quadkey.ts CHANGED
@@ -30,8 +30,13 @@ const RelativeDirectionConstantLookup: Record<string, number> = {
30
30
  }
31
31
 
32
32
  export class Quadkey {
33
+ static Zero = Quadkey.from(0, Buffer.alloc(31, 0))
34
+ static root = new Quadkey()
35
+ static type = 'Quadkey'
36
+
33
37
  public type = Quadkey.type
34
38
 
39
+ private _geoJson?: GeoJson
35
40
  private key = Buffer.alloc(32)
36
41
 
37
42
  constructor(key = Buffer.alloc(32)) {
@@ -39,24 +44,114 @@ export class Quadkey {
39
44
  this.guessZoom()
40
45
  }
41
46
 
42
- public equals(obj: Quadkey): boolean {
43
- return obj.toBase4HashLabel() == this.toBase4HashLabel()
47
+ get base10String() {
48
+ return this.bigNumber.toString(10)
44
49
  }
45
50
 
46
- static root = new Quadkey()
51
+ get base4Hash() {
52
+ const bn = new BigNumber(this.id.toString('hex'), 16)
53
+ const zoom = this.zoom
54
+ if (zoom === 0) {
55
+ return ''
56
+ }
57
+ let quadkeySimple = bn.toString(4)
58
+ while (quadkeySimple.length < zoom) {
59
+ quadkeySimple = `0${quadkeySimple}`
60
+ }
61
+ return quadkeySimple
62
+ }
47
63
 
48
- static type = 'Quadkey'
64
+ get base4HashLabel() {
65
+ const hash = this.base4Hash
66
+ return hash.length === 0 ? 'fhr' : hash
67
+ }
49
68
 
50
- static fromBase4String(value?: string) {
51
- if (value === 'fhr' || value === '') {
52
- return Quadkey.root
69
+ get bigNumber() {
70
+ return new BigNumber(`${this.key.toString('hex')}`, 'hex')
71
+ }
72
+
73
+ get boundingBox(): MercatorBoundingBox {
74
+ return tileToBoundingBox(this.tile)
75
+ }
76
+
77
+ get buffer() {
78
+ return this.key
79
+ }
80
+
81
+ get center() {
82
+ const result = boundingBoxToCenter(this.boundingBox)
83
+ return new LngLat(result[0], result[1])
84
+ }
85
+
86
+ get children() {
87
+ assertEx(this.zoom < MAX_ZOOM - 1, 'Can not get children of bottom tiles')
88
+ const result: Quadkey[] = []
89
+ const shiftedId = bitShiftLeft(bitShiftLeft(this.id))
90
+ for (let i = 0; i < 4; i++) {
91
+ const currentLastByte = shiftedId.readUInt8(shiftedId.length - 1)
92
+ shiftedId.writeUInt8((currentLastByte & 0xfc) | i, shiftedId.length - 1)
93
+ result.push(new Quadkey().setId(shiftedId).setZoom(this.zoom + 1))
53
94
  }
54
- if (value && value.length && value.length > 0) {
55
- const quadkey = new Quadkey(Buffer.from(padHex(new BigNumber(value, 4).toString(16)), 'hex')).setZoom(value.length)
56
- return quadkey.valid() ? quadkey : undefined
95
+ return result
96
+ }
97
+
98
+ get gridLocation() {
99
+ const tileData = tileFromQuadkey(this.base4Hash)
100
+
101
+ return {
102
+ col: 2 ** tileData[2] - tileData[1] - 1,
103
+ row: tileData[0],
104
+ zoom: tileData[2],
57
105
  }
58
106
  }
59
107
 
108
+ get hex() {
109
+ return `0x${this.key.toString('hex')}`
110
+ }
111
+
112
+ get id() {
113
+ return this.buffer.slice(1)
114
+ }
115
+
116
+ get parent(): Quadkey | undefined {
117
+ if (this.zoom > 0) {
118
+ return new Quadkey().setId(bitShiftRight(bitShiftRight(this.id))).setZoom(this.zoom - 1)
119
+ }
120
+ }
121
+
122
+ get siblings() {
123
+ const siblings = assertEx(this.parent?.children, `siblings: parentChildren ${this.base4Hash}`)
124
+ const filteredSiblings = siblings.filter((quadkey) => this.compareTo(quadkey) !== 0)
125
+ assertEx(filteredSiblings.length === 3, `siblings: expected 3 [${filteredSiblings.length}]`)
126
+ return filteredSiblings
127
+ }
128
+
129
+ get tile(): MercatorTile {
130
+ return tileFromQuadkey(this.base4Hash)
131
+ }
132
+
133
+ get valid() {
134
+ const zoom = this.zoom
135
+ const shift = (MAX_ZOOM - zoom) * 2
136
+ const id = this.id
137
+ let testId = id
138
+ for (let i = 0; i < shift; i++) {
139
+ testId = bitShiftLeft(testId)
140
+ }
141
+ for (let i = 0; i < shift; i++) {
142
+ testId = bitShiftRight(testId)
143
+ }
144
+ return testId.compare(id) === 0
145
+ }
146
+
147
+ get zoom() {
148
+ return this.buffer.readUInt8(0)
149
+ }
150
+
151
+ static from(zoom: number, id: Buffer) {
152
+ return new Quadkey().setId(id).setZoom(zoom)
153
+ }
154
+
60
155
  static fromBase10String(value: string) {
61
156
  return new Quadkey(Buffer.from(padHex(new BigNumber(value, 10).toString(16)), 'hex'))
62
157
  }
@@ -66,10 +161,36 @@ export class Quadkey {
66
161
  return new Quadkey(Buffer.from(padHex(valueToUse), 'hex'))
67
162
  }
68
163
 
164
+ static fromBase4String(value?: string) {
165
+ if (value === 'fhr' || value === '') {
166
+ return Quadkey.root
167
+ }
168
+ if (value && value.length && value.length > 0) {
169
+ const quadkey = new Quadkey(Buffer.from(padHex(new BigNumber(value, 4).toString(16)), 'hex')).setZoom(value.length)
170
+ return quadkey.valid ? quadkey : undefined
171
+ }
172
+ }
173
+
174
+ static fromBoundingBox(boundingBox: MercatorBoundingBox, zoom: number) {
175
+ const tiles = tilesFromBoundingBox(boundingBox, Math.floor(zoom))
176
+ const result: Quadkey[] = []
177
+ for (const tile of tiles) {
178
+ result.push(assertEx(Quadkey.fromTile(tile), 'Bad Quadkey'))
179
+ }
180
+
181
+ return result
182
+ }
183
+
69
184
  static fromBuffer(value: Buffer) {
70
185
  return Quadkey.fromBase16String(value.toString('hex'))
71
186
  }
72
187
 
188
+ static fromLngLat(point: LngLatLike, zoom: number) {
189
+ const tile = tileFromPoint(LngLat.convert(point), zoom)
190
+ const quadkeyString = tileToQuadkey(tile)
191
+ return Quadkey.fromBase4String(quadkeyString)
192
+ }
193
+
73
194
  static fromString(zoom: number, id: string, base = 10) {
74
195
  switch (base) {
75
196
  case 10:
@@ -81,42 +202,43 @@ export class Quadkey {
81
202
  }
82
203
  }
83
204
 
84
- public static from(zoom: number, id: Buffer) {
85
- return new Quadkey().setId(id).setZoom(zoom)
205
+ static fromTile(tile: MercatorTile) {
206
+ return Quadkey.fromBase4String(tileToQuadkey(tile))
86
207
  }
87
208
 
88
- public static fromLngLat(point: LngLatLike, zoom: number) {
89
- const tile = tileFromPoint(LngLat.convert(point), zoom)
90
- const quadkeyString = tileToQuadkey(tile)
91
- return Quadkey.fromBase4String(quadkeyString)
209
+ childrenByZoom(zoom: number) {
210
+ // if we are limiting by zoom, and we are already at that limit, just return this quadkey
211
+ if (zoom && zoom === this.zoom) {
212
+ return [this]
213
+ }
214
+
215
+ // recursively get children
216
+ let deepResult: Quadkey[] = []
217
+ for (const quadkey of this.children) {
218
+ deepResult = deepResult.concat(quadkey.childrenByZoom(zoom))
219
+ }
220
+ return deepResult
92
221
  }
93
222
 
94
- public static fromTile(tile: MercatorTile) {
95
- return Quadkey.fromBase4String(tileToQuadkey(tile))
223
+ clone() {
224
+ return Quadkey.fromBase10String(this.base10String)
96
225
  }
97
226
 
98
- public isInBoundingBox(boundingBox: MercatorBoundingBox) {
99
- const tileBoundingBox = tileToBoundingBox(this.toTile())
100
- return (
101
- boundingBox.contains(tileBoundingBox.getNorthEast()) ||
102
- boundingBox.contains(tileBoundingBox.getNorthWest()) ||
103
- boundingBox.contains(tileBoundingBox.getSouthEast()) ||
104
- boundingBox.contains(tileBoundingBox.getSouthWest())
105
- )
227
+ compareTo(quadkey: Quadkey) {
228
+ return this.bigNumber.cmp(quadkey.bigNumber)
106
229
  }
107
230
 
108
- public static fromBoundingBox(boundingBox: MercatorBoundingBox, zoom: number) {
109
- const tiles = tilesFromBoundingBox(boundingBox, Math.floor(zoom))
110
- const result: Quadkey[] = []
111
- for (const tile of tiles) {
112
- result.push(assertEx(Quadkey.fromTile(tile), 'Bad Quadkey'))
113
- }
231
+ equals(obj: Quadkey): boolean {
232
+ return obj.base4HashLabel == this.base4HashLabel
233
+ }
114
234
 
115
- return result
235
+ geoJson() {
236
+ this._geoJson = this._geoJson ?? new GeoJson(this.base4Hash)
237
+ return this._geoJson
116
238
  }
117
239
 
118
- public getGridBoundingBox(size: number) {
119
- const hash = this.toBase4Hash()
240
+ getGridBoundingBox(size: number) {
241
+ const hash = this.base4Hash
120
242
  let index = 0
121
243
  let left = 0
122
244
  let top = 0
@@ -148,27 +270,24 @@ export class Quadkey {
148
270
  }
149
271
  }
150
272
 
151
- public setKey(zoom: number, id: Buffer) {
152
- id.copy(this.key, this.key.length - id.length)
153
- this.key.writeUInt8(zoom, 0)
154
- return this
155
- }
156
-
157
- public setZoom(zoom: number) {
158
- assertEx(zoom < MAX_ZOOM, `Invalid zoom [${zoom}] max=${MAX_ZOOM}`)
159
- this.setKey(zoom, this.id)
160
- return this
273
+ /** @deprecated use .gridLocation instead */
274
+ getGridLocation() {
275
+ return this.gridLocation
161
276
  }
162
277
 
163
- public parent() {
164
- if (this.zoom > 0) {
165
- return new Quadkey().setId(bitShiftRight(bitShiftRight(this.id))).setZoom(this.zoom - 1)
166
- }
278
+ isInBoundingBox(boundingBox: MercatorBoundingBox) {
279
+ const tileBoundingBox = tileToBoundingBox(this.tile)
280
+ return (
281
+ boundingBox.contains(tileBoundingBox.getNorthEast()) ||
282
+ boundingBox.contains(tileBoundingBox.getNorthWest()) ||
283
+ boundingBox.contains(tileBoundingBox.getSouthEast()) ||
284
+ boundingBox.contains(tileBoundingBox.getSouthWest())
285
+ )
167
286
  }
168
287
 
169
- public relative(direction: string) {
288
+ relative(direction: string) {
170
289
  const directionConstant = assertEx(RelativeDirectionConstantLookup[direction], 'Invalid direction')
171
- let quadkey = this.toBase4Hash()
290
+ let quadkey = this.base4Hash
172
291
  if (quadkey.length === 0) {
173
292
  return this
174
293
  }
@@ -191,123 +310,82 @@ export class Quadkey {
191
310
  return Quadkey.fromBase4String(quadkey)
192
311
  }
193
312
 
194
- public childrenByZoom(zoom: number) {
195
- // if we are limiting by zoom, and we are already at that limit, just return this quadkey
196
- if (zoom && zoom === this.zoom) {
197
- return [this]
198
- }
199
-
200
- // recursively get children
201
- let deepResult: Quadkey[] = []
202
- for (const quadkey of this.children()) {
203
- deepResult = deepResult.concat(quadkey.childrenByZoom(zoom))
204
- }
205
- return deepResult
206
- }
207
-
208
- public children() {
209
- assertEx(this.zoom < MAX_ZOOM - 1, 'Can not get children of bottom tiles')
210
- const result: Quadkey[] = []
211
- const shiftedId = bitShiftLeft(bitShiftLeft(this.id))
212
- for (let i = 0; i < 4; i++) {
213
- const currentLastByte = shiftedId.readUInt8(shiftedId.length - 1)
214
- shiftedId.writeUInt8((currentLastByte & 0xfc) | i, shiftedId.length - 1)
215
- result.push(new Quadkey().setId(shiftedId).setZoom(this.zoom + 1))
216
- }
217
- return result
218
- }
219
-
220
- public siblings() {
221
- const siblings = assertEx(this.parent()?.children(), `siblings: parentChildren ${this.toBase4Hash()}`)
222
- const filteredSiblings = siblings.filter((quadkey) => this.compareTo(quadkey) !== 0)
223
- assertEx(filteredSiblings.length === 3, `siblings: expected 3 [${filteredSiblings.length}]`)
224
- return filteredSiblings
225
- }
226
-
227
- public clone() {
228
- return Quadkey.fromBase10String(this.toBase10String())
229
- }
230
-
231
- public get zoom() {
232
- return this.toBuffer().readUInt8(0)
313
+ setId(id: Buffer) {
314
+ this.setKey(this.zoom, id)
315
+ return this
233
316
  }
234
317
 
235
- private _geoJson?: GeoJson
236
-
237
- public geoJson() {
238
- this._geoJson = this._geoJson ?? new GeoJson(this.toBase4Hash())
239
- return this._geoJson
318
+ setKey(zoom: number, id: Buffer) {
319
+ id.copy(this.key, this.key.length - id.length)
320
+ this.key.writeUInt8(zoom, 0)
321
+ return this
240
322
  }
241
323
 
242
- public setId(id: Buffer) {
243
- this.setKey(this.zoom, id)
324
+ setZoom(zoom: number) {
325
+ assertEx(zoom < MAX_ZOOM, `Invalid zoom [${zoom}] max=${MAX_ZOOM}`)
326
+ this.setKey(zoom, this.id)
244
327
  return this
245
328
  }
246
329
 
247
- public toTile(): MercatorTile {
248
- return tileFromQuadkey(this.toBase4Hash())
330
+ /** @deprecated use .base10String*/
331
+ toBase10String() {
332
+ return this.base10String
249
333
  }
250
334
 
251
- public toBoundingBox(): MercatorBoundingBox {
252
- return tileToBoundingBox(this.toTile())
335
+ /** @deprecated use .base4Hash */
336
+ toBase4Hash() {
337
+ return this.base4Hash
253
338
  }
254
339
 
255
- public toCenter() {
256
- const result = boundingBoxToCenter(this.toBoundingBox())
257
- return new LngLat(result[0], result[1])
340
+ /** @deprecated use .base4HashLabel */
341
+ toBase4HashLabel() {
342
+ const hash = this.base4HashLabel
343
+ return hash.length === 0 ? 'fhr' : hash
258
344
  }
259
345
 
260
- public getGridLocation() {
261
- const tileData = tileFromQuadkey(this.toBase4Hash())
262
-
263
- return {
264
- col: 2 ** tileData[2] - tileData[1] - 1,
265
- row: tileData[0],
266
- zoom: tileData[2],
267
- }
346
+ /** @deprecated use .bigNumber */
347
+ toBigNumber() {
348
+ return this.bigNumber
268
349
  }
269
350
 
270
- public valid() {
271
- const zoom = this.zoom
272
- const shift = (MAX_ZOOM - zoom) * 2
273
- const id = this.id
274
- let testId = id
275
- for (let i = 0; i < shift; i++) {
276
- testId = bitShiftLeft(testId)
277
- }
278
- for (let i = 0; i < shift; i++) {
279
- testId = bitShiftRight(testId)
280
- }
281
- return testId.compare(id) === 0
351
+ /** @deprecated use .boundingBox */
352
+ toBoundingBox(): MercatorBoundingBox {
353
+ return this.boundingBox
282
354
  }
283
355
 
284
- public get id() {
285
- return this.toBuffer().slice(1)
356
+ /** @deprecated use .buffer */
357
+ toBuffer() {
358
+ return this.buffer
286
359
  }
287
360
 
288
- public toBuffer() {
289
- return this.key
361
+ /** @deprecated use .center */
362
+ toCenter() {
363
+ return this.center
290
364
  }
291
365
 
292
- public toBigNumber() {
293
- return new BigNumber(`${this.key.toString('hex')}`, 'hex')
366
+ /** @deprecated use .hex instead */
367
+ toHex() {
368
+ return this.hex
294
369
  }
295
370
 
296
- public toString() {
297
- return `0x${padHex(this.toBigNumber().toString(16))}`
371
+ toJSON(): string {
372
+ return this.base4HashLabel
298
373
  }
299
374
 
300
- public toJSON(): string {
301
- return this.toBase4HashLabel()
375
+ toShortString() {
376
+ const buffer = this.buffer
377
+ const part1 = buffer.slice(0, 2)
378
+ const part2 = buffer.slice(buffer.length - 2, buffer.length)
379
+ return `${part1.toString('hex')}...${part2.toString('hex')}`
302
380
  }
303
381
 
304
- public toBase10String() {
305
- return this.toBigNumber().toString(10)
382
+ toString() {
383
+ return `0x${padHex(this.bigNumber.toString(16))}`
306
384
  }
307
385
 
308
- public toBase4HashLabel() {
309
- const hash = this.toBase4Hash()
310
- return hash.length === 0 ? 'fhr' : hash
386
+ /** @deprecated use .tile instead */
387
+ public toTile(): MercatorTile {
388
+ return this.tile
311
389
  }
312
390
 
313
391
  protected guessZoom() {
@@ -315,34 +393,4 @@ export class Quadkey {
315
393
  const quadkeySimple = bn.toString(4)
316
394
  this.setZoom(quadkeySimple.length)
317
395
  }
318
-
319
- public toBase4Hash() {
320
- const bn = new BigNumber(this.id.toString('hex'), 16)
321
- const zoom = this.zoom
322
- if (zoom === 0) {
323
- return ''
324
- }
325
- let quadkeySimple = bn.toString(4)
326
- while (quadkeySimple.length < zoom) {
327
- quadkeySimple = `0${quadkeySimple}`
328
- }
329
- return quadkeySimple
330
- }
331
-
332
- public toHex() {
333
- return `0x${this.key.toString('hex')}`
334
- }
335
-
336
- public toShortString() {
337
- const buffer = this.toBuffer()
338
- const part1 = buffer.slice(0, 2)
339
- const part2 = buffer.slice(buffer.length - 2, buffer.length)
340
- return `${part1.toString('hex')}...${part2.toString('hex')}`
341
- }
342
-
343
- public compareTo(quadkey: Quadkey) {
344
- return this.toBigNumber().cmp(quadkey.toBigNumber())
345
- }
346
-
347
- public static Zero = Quadkey.from(0, Buffer.alloc(31, 0))
348
396
  }