| Crates.io | rapidgeo-distance |
| lib.rs | rapidgeo-distance |
| version | 0.2.0 |
| created_at | 2025-09-01 05:13:11.090158+00 |
| updated_at | 2025-09-02 16:23:11.328175+00 |
| description | Fast and accurate geographic distance calculations with geodesic, haversine, and euclidean algorithms |
| homepage | https://github.com/gaker/rapidgeo |
| repository | https://github.com/gaker/rapidgeo |
| max_upload_size | |
| id | 1819134 |
| size | 320,635 |
Geographic and planar distance calculations.
All coordinates use longitude, latitude ordering (lng, lat).
[dependencies]
rapidgeo-distance = "0.1"
# Or with optional features
rapidgeo-distance = { version = "0.1", features = ["batch", "vincenty"] }
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);
This crate calculates distances between geographic coordinates using three approaches:
All geodesic calculations use the WGS84 ellipsoid.
// All functions work with LngLat coordinates
let point = LngLat::new_deg(longitude, latitude);
let (lng_rad, lat_rad) = point.to_radians();
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.
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)
}
}
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);
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);
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);
#[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 | 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 |
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.
vincenty: Enables high-precision Vincenty calculationsbatch: Enables Rayon-based parallel processingSerial 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:
All coordinates use longitude, latitude ordering:
let coord = LngLat::new_deg(lng, lat); // Note: lng first
batch featureLicensed under either of
at your option.