4 releases
| 0.2.2 | Nov 20, 2025 |
|---|---|
| 0.2.1 | Oct 4, 2025 |
| 0.2.0 | Sep 2, 2025 |
| 0.1.1 | Sep 1, 2025 |
#52 in Geospatial
343 downloads per month
Used in 3 crates
330KB
4K
SLoC
rapidgeo-distance
Geographic and planar distance calculations.
All coordinates use longitude, latitude ordering (lng, lat).
Installation
[dependencies]
rapidgeo-distance = "0.2"
# Or with optional features
rapidgeo-distance = { version = "0.2", features = ["batch", "vincenty"] }
Quick Start
use rapidgeo_distance::{LngLat, geodesic, euclid};
let sf = LngLat::new_deg(-122.4194, 37.7749); // San Francisco
let nyc = LngLat::new_deg(-74.0060, 40.7128); // New York City
// Haversine: ±0.5% accuracy for distances <1000km
let distance = geodesic::haversine(sf, nyc);
println!("Distance: {:.1} km", distance / 1000.0);
// Vincenty: Sub-meter accuracy globally (requires "vincenty" feature)
let precise = geodesic::vincenty_distance_m(sf, nyc)?;
println!("Precise: {:.3} km", precise / 1000.0);
// Euclidean: Fast but inaccurate for large distances
let euclidean = euclid::distance_euclid(sf, nyc);
println!("Euclidean: {:.6}°", euclidean);
What This Crate Does
This crate calculates distances between geographic coordinates using three approaches:
- Geodesic algorithms - Account for Earth's shape (haversine, Vincenty)
- Euclidean distance - Treats coordinates as flat plane points
- Batch operations - Process many points efficiently with optional parallelization
All geodesic calculations use the WGS84 ellipsoid.
API Overview
Core Types
// All functions work with LngLat coordinates
let point = LngLat::new_deg(longitude, latitude);
let (lng_rad, lat_rad) = point.to_radians();
Coordinate Format Detection
The crate automatically detects and converts coordinate data from various formats (tuples, flat arrays, GeoJSON) to the internal LngLat representation:
use rapidgeo_distance::formats::{coords_to_lnglat_vec, CoordinateInput};
// Automatically detects lng,lat vs lat,lng ordering
let coords = vec![
(37.7749, -122.4194), // Latitude,longitude format (detected)
(40.7128, -74.0060), // Automatically corrected to lng,lat
];
let input = CoordinateInput::Tuples(coords);
let lnglat_coords = coords_to_lnglat_vec(&input);
See Coordinate Format Documentation for detailed examples of supported formats.
Geodesic Distances (Earth-Aware)
use rapidgeo_distance::geodesic::{haversine, vincenty_distance_m, VincentyError};
// Haversine: Fast, good accuracy for distances <1000km
let distance_m = haversine(point1, point2);
// Vincenty: Slower, very accurate, may fail for antipodal points
match vincenty_distance_m(point1, point2) {
Ok(distance) => println!("{:.3} m", distance),
Err(VincentyError::DidNotConverge) => {
// Use haversine as fallback
let fallback = haversine(point1, point2);
}
Err(VincentyError::Domain) => {
// Invalid coordinates (NaN/infinite)
}
}
Euclidean Distances (Flat Plane)
use rapidgeo_distance::euclid::{distance_euclid, distance_squared, point_to_segment};
// Basic distance in degrees (not meters)
let dist_deg = distance_euclid(point1, point2);
// Squared distance (avoids sqrt for performance)
let dist_sq = distance_squared(point1, point2);
// Point to line segment distance
let segment = (point1, point2);
let distance = point_to_segment(test_point, segment);
Point-to-Segment Distances
use rapidgeo_distance::geodesic::{point_to_segment_enu_m, great_circle_point_to_seg};
let segment = (start_point, end_point);
// ENU projection (good for small areas)
let distance = point_to_segment_enu_m(point, segment);
// Great circle method (accurate but slower)
let distance = great_circle_point_to_seg(point, segment);
Batch Operations
use rapidgeo_distance::batch::{
pairwise_haversine, path_length_haversine,
pairwise_haversine_into, distances_to_point_into
};
let path = vec![point1, point2, point3];
// Process consecutive pairs
let distances: Vec<f64> = pairwise_haversine(&path).collect();
// Total path length
let total = path_length_haversine(&path);
// Write to pre-allocated buffer (no allocation)
let mut buffer = vec![0.0; path.len() - 1];
pairwise_haversine_into(&path, &mut buffer);
Parallel Processing (requires "batch" feature)
#[cfg(feature = "batch")]
use rapidgeo_distance::batch::{
pairwise_haversine_par, path_length_haversine_par,
distances_to_point_par
};
let large_dataset = load_many_points();
// Parallel processing (beneficial for >1000 points)
let distances = pairwise_haversine_par(&large_dataset);
let total = path_length_haversine_par(&large_dataset);
Algorithm Selection
| Algorithm | Speed | Accuracy | Best For |
|---|---|---|---|
| Haversine | 46ns | ±0.5% | Distances <1000km |
| Vincenty | 271ns | ±1mm | High precision, any distance |
| Euclidean | 1ns | Poor at scale | Small areas, relative comparisons |
Accuracy Details
Haversine: Uses spherical approximation with ellipsoidal correction for the WGS84 ellipsoid. Good tradeoff for accuracy vs speed.
Vincenty: Implements Vincenty's inverse formula on WGS84 ellipsoid. May fail to converge for nearly antipodal points.
Euclidean: Simple Pythagorean theorem in degree space. Ignores Earth curvature. Error increases with distance and latitude.
Features
- Default: Haversine and Euclidean functions
vincenty: Enables high-precision Vincenty calculationsbatch: Enables Rayon-based parallel processing
Performance Notes
Serial vs Parallel: Parallel functions are faster for large datasets (>1000 points) but have overhead. Use serial for small datasets.
Memory Allocation: Functions ending in _into write to pre-allocated buffers, avoiding allocation overhead.
Benchmarks: On Intel i9-10900F:
- Euclidean: ~1ns per calculation
- Haversine: ~46ns per calculation
- Vincenty: ~271ns per calculation
- Pre-allocated buffers: ~60% faster than allocating
Coordinate System
All coordinates use longitude, latitude ordering:
- Longitude: -180.0 to +180.0° (West to East)
- Latitude: -90.0 to +90.0° (South to North)
let coord = LngLat::new_deg(lng, lat); // Note: lng first
Limitations
- Vincenty may fail for nearly antipodal points
- Euclidean accuracy degrades significantly with distance and latitude
- Parallel functions require the
batchfeature - All geodesic calculations assume WGS84 ellipsoid
- Point-to-segment functions assume segments shorter than hemisphere
License
Licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or https://opensource.org/licenses/MIT)
at your option.
Dependencies
~0–255KB