Haversine Distance
Calculates the great-circle (geodesic) distance between two latitude/longitude points in meters. Used throughout syncc wherever a straight-line geographic distance is needed.
Where It Is Used
| File | Purpose |
|---|---|
apps/passengers-app/src/app/core/services/lines.service.ts |
Walk distance to boarding/alighting stops |
apps/api-server/src/passenger/gtfs.service.ts |
GTFS nearest-stop search |
apps/api-server/src/trips/trips.service.ts |
Active trip ETA and transfer matching |
apps/api-server/src/lines/lines.service.ts |
Nearby stops backend endpoint |
apps/mobile-driver/src/app/core/services/location.service.ts |
Driver checkpoint proximity |
apps/api-server/src/location/location.service.ts |
Server-side checkpoint detection (SQL fallback) |
Formula
Given two points $(\phi_1, \lambda_1)$ and $(\phi_2, \lambda_2)$ in decimal degrees:
$$a = \sin^2!\left(\frac{\Delta\phi}{2}\right) + \cos\phi_1 \cdot \cos\phi_2 \cdot \sin^2!\left(\frac{\Delta\lambda}{2}\right)$$
$$d = 2R \cdot \arctan2!\left(\sqrt{a},\, \sqrt{1 - a}\right)$$
Constants: - $R = 6{,}371{,}000\ \text{m}$ (Earth's mean radius) - All angles in radians: multiply decimal degrees by $\pi / 180$
Accuracy: ±0.5% for typical urban distances — sufficient for public transit routing.
TypeScript Implementation
function haversineMeters(lat1: number, lng1: number, lat2: number, lng2: number): number {
const R = 6_371_000;
const φ1 = lat1 * Math.PI / 180;
const φ2 = lat2 * Math.PI / 180;
const Δφ = (lat2 - lat1) * Math.PI / 180;
const Δλ = (lng2 - lng1) * Math.PI / 180;
const a = Math.sin(Δφ / 2) ** 2
+ Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) ** 2;
return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}
Road Distance Correction
Haversine returns straight-line geodesic distance. For estimating actual road travel distance, services multiply by a road factor of 1.3× to approximate urban street network detours:
const roadDistance = haversineMeters(lat1, lng1, lat2, lng2) * 1.3;
SQL Variant
Used in location.service.ts as a PostGIS fallback for checkpoint proximity queries:
6371000 * acos(
cos(radians(:lat)) * cos(radians(checkpoint_lat))
* cos(radians(checkpoint_lng) - radians(:lng))
+ sin(radians(:lat)) * sin(radians(checkpoint_lat))
) <= radiusMeters
See also: Checkpoint Proximity Detection