@xyo-network/quadkey 2.81.7 → 2.81.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
@@ -1,6 +1,5 @@
1
1
  import { assertEx } from '@xylabs/assert'
2
- import { BigNumber } from '@xylabs/bignumber'
3
- import { Buffer } from '@xylabs/buffer'
2
+ import { asHex } from '@xylabs/hex'
4
3
  import {
5
4
  boundingBoxToCenter,
6
5
  GeoJson,
@@ -15,44 +14,39 @@ import {
15
14
  import { LngLat, LngLatLike } from 'mapbox-gl'
16
15
 
17
16
  import { RelativeDirectionConstantLookup } from './RelativeDirectionConstantLookup'
18
- import { bitShiftLeft, bitShiftRight, padHex } from './utils'
19
-
20
- export * from './utils'
21
17
 
22
18
  const MAX_ZOOM = 124
23
19
 
24
20
  export const isQuadkey = (obj: { type: string }) => obj?.type === Quadkey.type
25
21
 
22
+ const FULL_MASK = 2n ** 256n - 1n
23
+ const ZOOM_MASK = 0xffn << 248n
24
+ const ID_MASK = ZOOM_MASK ^ FULL_MASK
25
+
26
+ const assertMaxBitUint = (value: bigint, bits = 256n) => {
27
+ assertEx(value < 2n ** bits && value >= 0, 'Not a 256 Bit Uint!')
28
+ }
29
+
26
30
  export class Quadkey {
27
- static Zero = Quadkey.from(0, Buffer.alloc(31, 0))
31
+ static Zero = Quadkey.from(0, 0n)
28
32
  static root = new Quadkey()
29
33
  static type = 'Quadkey'
30
34
 
31
35
  type = Quadkey.type
32
36
 
33
37
  private _geoJson?: GeoJson
34
- private key = Buffer.alloc(32)
35
38
 
36
- constructor(key = Buffer.alloc(32)) {
37
- key.copy(this.key, this.key.length - key.length)
39
+ constructor(private key = 0n) {
40
+ assertMaxBitUint(key)
38
41
  this.guessZoom()
39
42
  }
40
43
 
41
- get base10String() {
42
- return this.bigNumber.toString(10)
44
+ get base16String() {
45
+ return this.id.toString(16).padStart(62, '0')
43
46
  }
44
47
 
45
48
  get base4Hash() {
46
- const bn = new BigNumber(this.id.toString('hex'), 16)
47
- const zoom = this.zoom
48
- if (zoom === 0) {
49
- return ''
50
- }
51
- let quadkeySimple = bn.toString(4)
52
- while (quadkeySimple.length < zoom) {
53
- quadkeySimple = `0${quadkeySimple}`
54
- }
55
- return quadkeySimple
49
+ return this.id.toString(4).padStart(this.zoom, '0')
56
50
  }
57
51
 
58
52
  get base4HashLabel() {
@@ -60,10 +54,6 @@ export class Quadkey {
60
54
  return hash.length === 0 ? 'fhr' : hash
61
55
  }
62
56
 
63
- get bigNumber() {
64
- return new BigNumber(`${this.key.toString('hex')}`, 'hex')
65
- }
66
-
67
57
  get boundingBox(): MercatorBoundingBox {
68
58
  return tileToBoundingBox(this.tile)
69
59
  }
@@ -80,11 +70,9 @@ export class Quadkey {
80
70
  get children() {
81
71
  assertEx(this.zoom < MAX_ZOOM - 1, 'Can not get children of bottom tiles')
82
72
  const result: Quadkey[] = []
83
- const shiftedId = bitShiftLeft(bitShiftLeft(this.id))
84
- for (let i = 0; i < 4; i++) {
85
- const currentLastByte = shiftedId.readUInt8(shiftedId.length - 1)
86
- shiftedId.writeUInt8((currentLastByte & 0xfc) | i, shiftedId.length - 1)
87
- result.push(new Quadkey().setId(shiftedId).setZoom(this.zoom + 1))
73
+ const shiftedId = this.id << 2n
74
+ for (let i = 0n; i < 4n; i++) {
75
+ result.push(new Quadkey().setId(shiftedId | i).setZoom(this.zoom + 1))
88
76
  }
89
77
  return result
90
78
  }
@@ -99,23 +87,19 @@ export class Quadkey {
99
87
  }
100
88
  }
101
89
 
102
- get hex() {
103
- return `0x${this.key.toString('hex')}`
104
- }
105
-
106
90
  get id() {
107
- return this.buffer.slice(1)
91
+ return this.key & ID_MASK
108
92
  }
109
93
 
110
94
  get parent(): Quadkey | undefined {
111
95
  if (this.zoom > 0) {
112
- return new Quadkey().setId(bitShiftRight(bitShiftRight(this.id))).setZoom(this.zoom - 1)
96
+ return new Quadkey().setId(this.id >> 2n).setZoom(this.zoom - 1)
113
97
  }
114
98
  }
115
99
 
116
100
  get siblings() {
117
101
  const siblings = assertEx(this.parent?.children, `siblings: parentChildren ${this.base4Hash}`)
118
- const filteredSiblings = siblings.filter((quadkey) => this.compareTo(quadkey) !== 0)
102
+ const filteredSiblings = siblings.filter((quadkey) => quadkey.key !== this.key)
119
103
  assertEx(filteredSiblings.length === 3, `siblings: expected 3 [${filteredSiblings.length}]`)
120
104
  return filteredSiblings
121
105
  }
@@ -125,44 +109,38 @@ export class Quadkey {
125
109
  }
126
110
 
127
111
  get valid() {
128
- const zoom = this.zoom
129
- const shift = (MAX_ZOOM - zoom) * 2
130
- const id = this.id
131
- let testId = id
132
- for (let i = 0; i < shift; i++) {
133
- testId = bitShiftLeft(testId)
134
- }
135
- for (let i = 0; i < shift; i++) {
136
- testId = bitShiftRight(testId)
137
- }
138
- return testId.compare(id) === 0
112
+ //check for additional data outside zoom scope
113
+ return this.id.toString(4) === this.base4Hash.padStart(64, '0')
139
114
  }
140
115
 
141
116
  get zoom() {
142
- return this.buffer.readUInt8(0)
117
+ //zoom is stored in top byte
118
+ return Number((this.key & ZOOM_MASK) >> 248n)
143
119
  }
144
120
 
145
- static from(zoom: number, id: Buffer) {
121
+ static from(zoom: number, id: bigint) {
146
122
  return new Quadkey().setId(id).setZoom(zoom)
147
123
  }
148
124
 
149
- static fromBase10String(value: string) {
150
- return new Quadkey(Buffer.from(padHex(new BigNumber(value, 10).toString(16)), 'hex'))
125
+ static fromArrayBuffer(zoom: number, id: ArrayBuffer) {
126
+ return new Quadkey().setId(BigInt(`0x${asHex(id, 256, true)}`)).setZoom(zoom)
151
127
  }
152
128
 
153
129
  static fromBase16String(value: string) {
154
- const valueToUse = value.startsWith('0x') ? value.slice(2) : value
155
- return new Quadkey(Buffer.from(padHex(valueToUse), 'hex'))
130
+ return new Quadkey(BigInt(`0x${asHex(value, 256, true)}`))
156
131
  }
157
132
 
158
133
  static fromBase4String(value?: string) {
159
- if (value === 'fhr' || value === '') {
134
+ if (value === 'fhr' || value === '' || value === undefined) {
160
135
  return Quadkey.root
161
136
  }
162
- if (value && value.length && value.length > 0) {
163
- const quadkey = new Quadkey(Buffer.from(padHex(new BigNumber(value, 4).toString(16)), 'hex')).setZoom(value.length)
164
- return quadkey.valid ? quadkey : undefined
137
+ let id = 0n
138
+ for (let i = 0; i < value.length; i++) {
139
+ const nibble = parseInt(value[i])
140
+ assertEx(nibble < 4 && nibble >= 0, `Invalid Base4 String: ${value}`)
141
+ id = (id << 2n) | BigInt(nibble)
165
142
  }
143
+ return new Quadkey().setId(id).setZoom(value.length)
166
144
  }
167
145
 
168
146
  static fromBoundingBox(boundingBox: MercatorBoundingBox, zoom: number) {
@@ -175,20 +153,14 @@ export class Quadkey {
175
153
  return result
176
154
  }
177
155
 
178
- static fromBuffer(value: Buffer) {
179
- return Quadkey.fromBase16String(value.toString('hex'))
180
- }
181
-
182
156
  static fromLngLat(point: LngLatLike, zoom: number) {
183
157
  const tile = tileFromPoint(LngLat.convert(point), zoom)
184
158
  const quadkeyString = tileToQuadkey(tile)
185
159
  return Quadkey.fromBase4String(quadkeyString)
186
160
  }
187
161
 
188
- static fromString(zoom: number, id: string, base = 10) {
162
+ static fromString(zoom: number, id: string, base = 16) {
189
163
  switch (base) {
190
- case 10:
191
- return Quadkey.fromBase10String(id)?.setZoom(zoom)
192
164
  case 16:
193
165
  return Quadkey.fromBase16String(id).setZoom(zoom)
194
166
  default:
@@ -215,15 +187,11 @@ export class Quadkey {
215
187
  }
216
188
 
217
189
  clone() {
218
- return Quadkey.fromBase10String(this.base10String)
219
- }
220
-
221
- compareTo(quadkey: Quadkey) {
222
- return this.bigNumber.cmp(quadkey.bigNumber)
190
+ return new Quadkey(this.key)
223
191
  }
224
192
 
225
193
  equals(obj: Quadkey): boolean {
226
- return obj.base4HashLabel == this.base4HashLabel
194
+ return obj.key == this.key
227
195
  }
228
196
 
229
197
  geoJson() {
@@ -304,87 +272,35 @@ export class Quadkey {
304
272
  return Quadkey.fromBase4String(quadkey)
305
273
  }
306
274
 
307
- setId(id: Buffer) {
275
+ setId(id: bigint) {
276
+ assertMaxBitUint(id, 248n)
308
277
  this.setKey(this.zoom, id)
309
278
  return this
310
279
  }
311
280
 
312
- setKey(zoom: number, id: Buffer) {
313
- id.copy(this.key, this.key.length - id.length)
314
- this.key.writeUInt8(zoom, 0)
281
+ setKey(zoom: number, key: bigint) {
282
+ assertMaxBitUint(key)
283
+ this.key = key
284
+ this.setZoom(zoom)
315
285
  return this
316
286
  }
317
287
 
318
288
  setZoom(zoom: number) {
319
289
  assertEx(zoom < MAX_ZOOM, `Invalid zoom [${zoom}] max=${MAX_ZOOM}`)
320
- this.setKey(zoom, this.id)
290
+ this.key = (this.key & ID_MASK) | (BigInt(zoom) << 248n)
321
291
  return this
322
292
  }
323
293
 
324
- /** @deprecated use .base10String*/
325
- toBase10String() {
326
- return this.base10String
327
- }
328
-
329
- /** @deprecated use .base4Hash */
330
- toBase4Hash() {
331
- return this.base4Hash
332
- }
333
-
334
- /** @deprecated use .base4HashLabel */
335
- toBase4HashLabel() {
336
- const hash = this.base4HashLabel
337
- return hash.length === 0 ? 'fhr' : hash
338
- }
339
-
340
- /** @deprecated use .bigNumber */
341
- toBigNumber() {
342
- return this.bigNumber
343
- }
344
-
345
- /** @deprecated use .boundingBox */
346
- toBoundingBox(): MercatorBoundingBox {
347
- return this.boundingBox
348
- }
349
-
350
- /** @deprecated use .buffer */
351
- toBuffer() {
352
- return this.buffer
353
- }
354
-
355
- /** @deprecated use .center */
356
- toCenter() {
357
- return this.center
358
- }
359
-
360
- /** @deprecated use .hex instead */
361
- toHex() {
362
- return this.hex
363
- }
364
-
365
294
  toJSON(): string {
366
295
  return this.base4HashLabel
367
296
  }
368
297
 
369
- toShortString() {
370
- const buffer = this.buffer
371
- const part1 = buffer.slice(0, 2)
372
- const part2 = buffer.slice(buffer.length - 2, buffer.length)
373
- return `${part1.toString('hex')}...${part2.toString('hex')}`
374
- }
375
-
376
298
  toString() {
377
- return `0x${padHex(this.bigNumber.toString(16))}`
378
- }
379
-
380
- /** @deprecated use .tile instead */
381
- toTile(): MercatorTile {
382
- return this.tile
299
+ return this.base4Hash
383
300
  }
384
301
 
385
302
  protected guessZoom() {
386
- const bn = new BigNumber(this.id.toString('hex'), 16)
387
- const quadkeySimple = bn.toString(4)
303
+ const quadkeySimple = this.id.toString(4)
388
304
  this.setZoom(quadkeySimple.length)
389
305
  }
390
306
  }
@@ -1,6 +0,0 @@
1
- /// <reference types="node" />
2
- import { Buffer } from '@xylabs/buffer';
3
- export declare const padHex: (hex: string, byteCount?: number) => string;
4
- export declare const bitShiftLeft: (buffer: Buffer) => Buffer;
5
- export declare const bitShiftRight: (buffer: Buffer) => Buffer;
6
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEvC,eAAO,MAAM,MAAM,QAAS,MAAM,cAAc,MAAM,WAWrD,CAAA;AAED,eAAO,MAAM,YAAY,WAAY,MAAM,WAW1C,CAAA;AAED,eAAO,MAAM,aAAa,WAAY,MAAM,WAW3C,CAAA"}
@@ -1,6 +0,0 @@
1
- /// <reference types="node" />
2
- import { Buffer } from '@xylabs/buffer';
3
- export declare const padHex: (hex: string, byteCount?: number) => string;
4
- export declare const bitShiftLeft: (buffer: Buffer) => Buffer;
5
- export declare const bitShiftRight: (buffer: Buffer) => Buffer;
6
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEvC,eAAO,MAAM,MAAM,QAAS,MAAM,cAAc,MAAM,WAWrD,CAAA;AAED,eAAO,MAAM,YAAY,WAAY,MAAM,WAW1C,CAAA;AAED,eAAO,MAAM,aAAa,WAAY,MAAM,WAW3C,CAAA"}
@@ -1,6 +0,0 @@
1
- /// <reference types="node" />
2
- import { Buffer } from '@xylabs/buffer';
3
- export declare const padHex: (hex: string, byteCount?: number) => string;
4
- export declare const bitShiftLeft: (buffer: Buffer) => Buffer;
5
- export declare const bitShiftRight: (buffer: Buffer) => Buffer;
6
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEvC,eAAO,MAAM,MAAM,QAAS,MAAM,cAAc,MAAM,WAWrD,CAAA;AAED,eAAO,MAAM,YAAY,WAAY,MAAM,WAW1C,CAAA;AAED,eAAO,MAAM,aAAa,WAAY,MAAM,WAW3C,CAAA"}
@@ -1,6 +0,0 @@
1
- /// <reference types="node" />
2
- import { Buffer } from '@xylabs/buffer';
3
- export declare const padHex: (hex: string, byteCount?: number) => string;
4
- export declare const bitShiftLeft: (buffer: Buffer) => Buffer;
5
- export declare const bitShiftRight: (buffer: Buffer) => Buffer;
6
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEvC,eAAO,MAAM,MAAM,QAAS,MAAM,cAAc,MAAM,WAWrD,CAAA;AAED,eAAO,MAAM,YAAY,WAAY,MAAM,WAW1C,CAAA;AAED,eAAO,MAAM,aAAa,WAAY,MAAM,WAW3C,CAAA"}
@@ -1,6 +0,0 @@
1
- /// <reference types="node" />
2
- import { Buffer } from '@xylabs/buffer';
3
- export declare const padHex: (hex: string, byteCount?: number) => string;
4
- export declare const bitShiftLeft: (buffer: Buffer) => Buffer;
5
- export declare const bitShiftRight: (buffer: Buffer) => Buffer;
6
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEvC,eAAO,MAAM,MAAM,QAAS,MAAM,cAAc,MAAM,WAWrD,CAAA;AAED,eAAO,MAAM,YAAY,WAAY,MAAM,WAW1C,CAAA;AAED,eAAO,MAAM,aAAa,WAAY,MAAM,WAW3C,CAAA"}
@@ -1,6 +0,0 @@
1
- /// <reference types="node" />
2
- import { Buffer } from '@xylabs/buffer';
3
- export declare const padHex: (hex: string, byteCount?: number) => string;
4
- export declare const bitShiftLeft: (buffer: Buffer) => Buffer;
5
- export declare const bitShiftRight: (buffer: Buffer) => Buffer;
6
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEvC,eAAO,MAAM,MAAM,QAAS,MAAM,cAAc,MAAM,WAWrD,CAAA;AAED,eAAO,MAAM,YAAY,WAAY,MAAM,WAW1C,CAAA;AAED,eAAO,MAAM,aAAa,WAAY,MAAM,WAW3C,CAAA"}
package/src/utils.ts DELETED
@@ -1,40 +0,0 @@
1
- import { Buffer } from '@xylabs/buffer'
2
-
3
- export const padHex = (hex: string, byteCount?: number) => {
4
- let result = hex
5
- if (hex.length % 2 !== 0) {
6
- result = `0${hex}`
7
- }
8
- if (byteCount) {
9
- while (result.length / 2 < byteCount) {
10
- result = `00${result}`
11
- }
12
- }
13
- return result
14
- }
15
-
16
- export const bitShiftLeft = (buffer: Buffer) => {
17
- const shifted = Buffer.alloc(buffer.length)
18
- const last = buffer.length - 1
19
- for (let index = 0; index < last; index++) {
20
- shifted[index] = buffer[index] << 1
21
- if (buffer[index + 1] & 0x80) {
22
- shifted[index] += 0x01
23
- }
24
- }
25
- shifted[last] = buffer[last] << 1
26
- return shifted
27
- }
28
-
29
- export const bitShiftRight = (buffer: Buffer) => {
30
- const shifted = Buffer.alloc(buffer.length)
31
- const last = buffer.length - 1
32
- for (let index = last; index > 0; index--) {
33
- shifted[index] = buffer[index] >> 1
34
- if (buffer[index - 1] & 0x01) {
35
- shifted[index] += 0x80
36
- }
37
- }
38
- shifted[0] = buffer[0] >> 1
39
- return shifted
40
- }