69 lines
1.8 KiB
TypeScript
69 lines
1.8 KiB
TypeScript
/**
|
|
* Utility class for geographic calculations
|
|
*/
|
|
export class GeographicUtils {
|
|
/**
|
|
* Check if a point is inside a polygon using ray-casting algorithm
|
|
* @param point - [longitude, latitude]
|
|
* @param polygon - Array of [longitude, latitude] pairs
|
|
*/
|
|
static isPointInPolygon(point: [number, number], polygon: [number, number][]): boolean {
|
|
const x = point[0];
|
|
const y = point[1];
|
|
let inside = false;
|
|
|
|
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
const xi = polygon[i][0];
|
|
const yi = polygon[i][1];
|
|
const xj = polygon[j][0];
|
|
const yj = polygon[j][1];
|
|
|
|
const intersect =
|
|
yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi + Number.EPSILON) + xi;
|
|
if (intersect) inside = !inside;
|
|
}
|
|
|
|
return inside;
|
|
}
|
|
|
|
/**
|
|
* Convert degrees to radians
|
|
*/
|
|
private static toRad(value: number): number {
|
|
return (value * Math.PI) / 180;
|
|
}
|
|
|
|
/**
|
|
* Calculate distance between two points in kilometers using Haversine formula
|
|
*/
|
|
static getDistanceKm(lat1: number, lng1: number, lat2: number, lng2: number): number {
|
|
const R = 6371; // Earth radius in KM
|
|
|
|
const dLat = this.toRad(lat2 - lat1);
|
|
const dLng = this.toRad(lng2 - lng1);
|
|
|
|
const a =
|
|
Math.sin(dLat / 2) ** 2 +
|
|
Math.cos(this.toRad(lat1)) * Math.cos(this.toRad(lat2)) * Math.sin(dLng / 2) ** 2;
|
|
|
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
|
|
return R * c;
|
|
}
|
|
|
|
/**
|
|
* Calculate distance between two points in kilometers (rounded)
|
|
*/
|
|
static getDistanceKmRounded(
|
|
lat1: number,
|
|
lng1: number,
|
|
lat2: number,
|
|
lng2: number,
|
|
precision = 2,
|
|
): number {
|
|
const distance = this.getDistanceKm(lat1, lng1, lat2, lng2);
|
|
return Number(distance.toFixed(precision));
|
|
}
|
|
}
|
|
|