forked from PinSpace-Org/GistPin
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgeo.service.ts
More file actions
87 lines (78 loc) · 2 KB
/
Copy pathgeo.service.ts
File metadata and controls
87 lines (78 loc) · 2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import { Injectable } from '@nestjs/common';
@Injectable()
export class GeoService {
private readonly BASE32 = '0123456789bcdefghjkmnpqrstuvwxyz';
/**
* Encode lat/lon into a geohash cell string.
* Precision 7 → ~153m x 153m cells (used for location_cell on-chain).
*/
encode(lat: number, lon: number, precision = 7): string {
let minLat = -90,
maxLat = 90;
let minLon = -180,
maxLon = 180;
let hash = '';
let bits = 0;
let charIndex = 0;
let isEven = true;
while (hash.length < precision) {
if (isEven) {
const mid = (minLon + maxLon) / 2;
if (lon > mid) {
charIndex = (charIndex << 1) + 1;
minLon = mid;
} else {
charIndex = charIndex << 1;
maxLon = mid;
}
} else {
const mid = (minLat + maxLat) / 2;
if (lat > mid) {
charIndex = (charIndex << 1) + 1;
minLat = mid;
} else {
charIndex = charIndex << 1;
maxLat = mid;
}
}
isEven = !isEven;
bits++;
if (bits === 5) {
hash += this.BASE32[charIndex];
bits = 0;
charIndex = 0;
}
}
return hash;
}
/**
* Decode a geohash string back to { lat, lon } center coordinates.
*/
decode(hash: string): { lat: number; lon: number } {
let minLat = -90,
maxLat = 90;
let minLon = -180,
maxLon = 180;
let isEven = true;
for (const char of hash) {
const idx = this.BASE32.indexOf(char);
for (let bits = 4; bits >= 0; bits--) {
const bitN = (idx >> bits) & 1;
if (isEven) {
const mid = (minLon + maxLon) / 2;
if (bitN === 1) minLon = mid;
else maxLon = mid;
} else {
const mid = (minLat + maxLat) / 2;
if (bitN === 1) minLat = mid;
else maxLat = mid;
}
isEven = !isEven;
}
}
return {
lat: (minLat + maxLat) / 2,
lon: (minLon + maxLon) / 2,
};
}
}