src/tracking/geofence.service.ts
Methods |
|
constructor(prisma: PrismaService)
|
||||||
|
Defined in src/tracking/geofence.service.ts:6
|
||||||
|
Parameters :
|
| Async checkGeofences |
checkGeofences(vehicleId: string, lat: number, lng: number)
|
|
Defined in src/tracking/geofence.service.ts:14
|
|
Check if a vehicle position is inside any geofence. Called by the tracking service when GPS events come in.
Returns :
Promise<Array<literal type>>
|
import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class GeofenceService {
private readonly logger = new Logger(GeofenceService.name);
constructor(private prisma: PrismaService) {}
/**
* Check if a vehicle position is inside any geofence.
* Called by the tracking service when GPS events come in.
*/
async checkGeofences(
vehicleId: string,
lat: number,
lng: number,
): Promise<
Array<{ geofenceId: string; name: string; event: 'enter' | 'exit' }>
> {
const geofences = await this.prisma.geofence.findMany({
where: { isActive: true },
});
const events: Array<{
geofenceId: string;
name: string;
event: 'enter' | 'exit';
}> = [];
for (const gf of geofences) {
if (!gf.centerLat || !gf.centerLng || !gf.radiusMeters) continue;
const distance = this.haversineMeters(
lat,
lng,
gf.centerLat,
gf.centerLng,
);
const isInside = distance <= gf.radiusMeters;
// Check previous state (was the vehicle inside before?)
const lastEvent = await this.prisma.gpsEvent.findFirst({
where: {
vehicleId,
source: { in: ['geofence_enter', 'geofence_exit'] },
},
orderBy: { timestamp: 'desc' },
});
const wasInside = lastEvent?.source === 'geofence_enter';
if (isInside && !wasInside) {
events.push({ geofenceId: gf.id, name: gf.name, event: 'enter' });
} else if (!isInside && wasInside) {
events.push({ geofenceId: gf.id, name: gf.name, event: 'exit' });
}
}
return events;
}
private haversineMeters(
lat1: number,
lon1: number,
lat2: number,
lon2: number,
): number {
const R = 6371000;
const dLat = ((lat2 - lat1) * Math.PI) / 180;
const dLon = ((lon2 - lon1) * Math.PI) / 180;
const a =
Math.sin(dLat / 2) ** 2 +
Math.cos((lat1 * Math.PI) / 180) *
Math.cos((lat2 * Math.PI) / 180) *
Math.sin(dLon / 2) ** 2;
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}
}