Files
maps-saas/apps/api/dist/maps/traffic-grid.service.js
T

124 lines
4.7 KiB
JavaScript

"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var TrafficGridService_1;
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TrafficGridService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("typeorm");
let TrafficGridService = TrafficGridService_1 = class TrafficGridService {
dataSource;
logger = new common_1.Logger(TrafficGridService_1.name);
grid = new Map();
GEOHASH_PRECISION = 6;
constructor(dataSource) {
this.dataSource = dataSource;
}
async onModuleInit() {
await this.refreshGrid();
}
async refreshGrid() {
this.logger.log('📡 Rebuilding Traffic Grid v3 (In-Memory Lookup)...');
try {
const startTime = Date.now();
const data = await this.dataSource.query(`
SELECT
ST_X(ST_Centroid(geometry::geometry)) as lng,
ST_Y(ST_Centroid(geometry::geometry)) as lat,
p."hourOfDay", p."dayOfWeek", p."averageSpeed",
s."averageSpeed" as base_speed
FROM road_speed_profiles p
JOIN road_segment_stats s ON p."segmentId" = s."segmentId"
WHERE s.geometry IS NOT NULL
`);
this.grid.clear();
let count = 0;
for (const row of data) {
const gh = this.encodeGeohash(row.lat, row.lng, this.GEOHASH_PRECISION);
const factor = row.base_speed / Math.max(row.averageSpeed, 1);
const key = `${gh}:${row.hourOfDay}:${row.dayOfWeek}`;
this.grid.set(key, factor);
count++;
}
this.logger.log(`✅ Grid rebuilt in ${Date.now() - startTime}ms. Cached ${count} cells (${this.grid.size} unique keys).`);
}
catch (e) {
this.logger.error('❌ Failed to refresh traffic grid:', e.message);
}
}
getTrafficFactor(coords, hr, dow) {
if (this.grid.size === 0)
return 1.0;
let totalFactor = 0;
let matches = 0;
for (let i = 0; i < coords.length; i += 2) {
const [lng, lat] = coords[i];
const gh = this.encodeGeohash(lat, lng, this.GEOHASH_PRECISION);
const key = `${gh}:${hr}:${dow}`;
const factor = this.grid.get(key);
if (factor) {
totalFactor += factor;
matches++;
}
}
if (matches === 0)
return 1.0;
let finalFactor = totalFactor / matches;
return Math.min(Math.max(finalFactor, 0.8), 3.0);
}
encodeGeohash(lat, lng, precision) {
const BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz";
let minLat = -90, maxLat = 90;
let minLng = -180, maxLng = 180;
let result = "";
let isEven = true;
let bit = 0;
let ch = 0;
while (result.length < precision) {
if (isEven) {
let mid = (minLng + maxLng) / 2;
if (lng > mid) {
ch |= (1 << (4 - bit));
minLng = mid;
}
else {
maxLng = mid;
}
}
else {
let mid = (minLat + maxLat) / 2;
if (lat > mid) {
ch |= (1 << (4 - bit));
minLat = mid;
}
else {
maxLat = mid;
}
}
isEven = !isEven;
if (bit < 4) {
bit++;
}
else {
result += BASE32[ch];
bit = 0;
ch = 0;
}
}
return result;
}
};
exports.TrafficGridService = TrafficGridService;
exports.TrafficGridService = TrafficGridService = TrafficGridService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [typeof (_a = typeof typeorm_1.DataSource !== "undefined" && typeorm_1.DataSource) === "function" ? _a : Object])
], TrafficGridService);
//# sourceMappingURL=traffic-grid.service.js.map