Distance Calculations

The rapidgeo.distance module provides fast geographic and planar distance calculations with multiple algorithms optimized for different use cases.

Core Types

class rapidgeo.distance.LngLat(lng, lat)

Geographic coordinate representing longitude and latitude in decimal degrees.

Coordinates use longitude, latitude ordering (x, y convention). All functions expect coordinates in decimal degrees.

Examples

>>> from rapidgeo import LngLat
>>> sf = LngLat(-122.4194, 37.7749)  # San Francisco
>>> print(sf.lng, sf.lat)
-122.4194 37.7749
lat

Latitude in decimal degrees.

Returns:

Latitude coordinate (-90 to +90)

Return type:

float

lng

Longitude in decimal degrees.

Returns:

Longitude coordinate (-180 to +180)

Return type:

float

The LngLat type represents a coordinate pair in longitude, latitude order. All rapidgeo functions use this consistent ordering.

Example:

from rapidgeo.distance import LngLat

# Create coordinates (longitude first, latitude second)
sf = LngLat.new_deg(-122.4194, 37.7749)   # San Francisco
nyc = LngLat.new_deg(-74.0060, 40.7128)   # New York City

print(f"San Francisco: {sf}")
print(f"New York City: {nyc}")

Geographic Distance

Geographic distances calculate the actual distance between points on Earth’s surface.

Geographic distance functions

rapidgeo.distance.geo.haversine(a, b)

Calculate the great-circle distance between two points using the Haversine formula.

Uses spherical Earth approximation for fast distance calculations. Accurate to within 0.5% for distances under 1000km.

Parameters:
  • a (LngLat) – First coordinate

  • b (LngLat) – Second coordinate

Returns:

Distance in meters

Return type:

float

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.distance.geo import haversine
>>> sf = LngLat(-122.4194, 37.7749)
>>> nyc = LngLat(-74.0060, 40.7128)
>>> distance = haversine(sf, nyc)
>>> print(f"Distance: {distance/1000:.0f} km")
Distance: 4135 km
rapidgeo.distance.geo.haversine_km(a, b)

Calculate distance in kilometers using the Haversine formula.

Convenient wrapper that returns distance in kilometers instead of meters. Fast spherical approximation accurate to within 0.5% for distances under 1000km.

Parameters:
  • a (LngLat) – First coordinate

  • b (LngLat) – Second coordinate

Returns:

Distance in kilometers

Return type:

float

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.distance.geo import haversine_km
>>> sf = LngLat(-122.4194, 37.7749)
>>> nyc = LngLat(-74.0060, 40.7128)
>>> distance = haversine_km(sf, nyc)
>>> print(f"Distance: {distance:.0f} km")
Distance: 4135 km
rapidgeo.distance.geo.haversine_miles(a, b)

Calculate distance in statute miles using the Haversine formula.

Convenient wrapper that returns distance in statute miles. Fast spherical approximation accurate to within 0.5% for distances under 1000km.

Parameters:
  • a (LngLat) – First coordinate

  • b (LngLat) – Second coordinate

Returns:

Distance in statute miles

Return type:

float

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.distance.geo import haversine_miles
>>> sf = LngLat(-122.4194, 37.7749)
>>> nyc = LngLat(-74.0060, 40.7128)
>>> distance = haversine_miles(sf, nyc)
>>> print(f"Distance: {distance:.0f} miles")
Distance: 2570 miles
rapidgeo.distance.geo.haversine_nautical(a, b)

Calculate distance in nautical miles using the Haversine formula.

Convenient wrapper that returns distance in nautical miles. Fast spherical approximation accurate to within 0.5% for distances under 1000km.

Parameters:
  • a (LngLat) – First coordinate

  • b (LngLat) – Second coordinate

Returns:

Distance in nautical miles

Return type:

float

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.distance.geo import haversine_nautical
>>> sf = LngLat(-122.4194, 37.7749)
>>> nyc = LngLat(-74.0060, 40.7128)
>>> distance = haversine_nautical(sf, nyc)
>>> print(f"Distance: {distance:.0f} nm")
Distance: 2232 nm
rapidgeo.distance.geo.bearing(from_point, to_point)

Calculate the initial bearing from one point to another.

Returns the compass bearing (azimuth) in degrees from the first point to the second point along the great circle path.

Parameters:
  • from_point (LngLat) – Starting coordinate

  • to_point (LngLat) – Destination coordinate

Returns:

Initial bearing in degrees (0-360°, where 0° is North)

Return type:

float

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.distance.geo import bearing
>>> sf = LngLat(-122.4194, 37.7749)
>>> nyc = LngLat(-74.0060, 40.7128)
>>> bearing_deg = bearing(sf, nyc)
>>> print(f"Bearing: {bearing_deg:.1f}°")
Bearing: 65.4°
rapidgeo.distance.geo.destination(origin, distance_m, bearing_deg)

Calculate the destination point given origin, distance, and bearing.

Uses spherical trigonometry to find the point that is at the specified distance and bearing from the origin point.

Parameters:
  • origin (LngLat) – Starting coordinate

  • distance_m (float) – Distance to travel in meters

  • bearing_deg (float) – Compass bearing in degrees (0-360°, where 0° is North)

Returns:

Destination coordinate

Return type:

LngLat

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.distance.geo import destination
>>> london = LngLat(-0.1278, 51.5074)
>>> dest = destination(london, 100000, 90)  # 100km due east
>>> print(f"Destination: {dest.lng:.4f}, {dest.lat:.4f}")
Destination: 1.2644, 51.5074
rapidgeo.distance.geo.vincenty_distance(a, b)

Calculate high-precision distance using Vincenty’s formulae for the WGS84 ellipsoid.

Provides millimeter accuracy for geodesic distances but slower than Haversine. May fail for nearly antipodal points (opposite sides of Earth).

Parameters:
  • a (LngLat) – First coordinate

  • b (LngLat) – Second coordinate

Returns:

Distance in meters with millimeter precision

Return type:

float

Raises:

ValueError – If the algorithm fails to converge for antipodal points

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.distance.geo import vincenty_distance
>>> sf = LngLat(-122.4194, 37.7749)
>>> nyc = LngLat(-74.0060, 40.7128)
>>> distance = vincenty_distance(sf, nyc)
>>> print(f"Precise distance: {distance:.1f} m")
Precise distance: 4134785.2 m

Algorithm Selection:

  • Haversine: Good for most applications. Assumes spherical Earth.

  • Vincenty: Higher precision using ellipsoidal Earth model. More computation required.

Example:

from rapidgeo.distance import LngLat
from rapidgeo.distance.geo import haversine, vincenty_distance

sf = LngLat.new_deg(-122.4194, 37.7749)
nyc = LngLat.new_deg(-74.0060, 40.7128)

# Fast, good accuracy for most use cases
distance = haversine(sf, nyc)
print(f"Haversine: {distance / 1000:.1f} km")

# High precision, slower
precise = vincenty_distance(sf, nyc)
print(f"Vincenty: {precise / 1000:.3f} km")

Planar Distance

Planar distances treat coordinates as points on a flat plane, ignoring Earth’s curvature.

Euclidean distance functions

rapidgeo.distance.euclid.euclid(a, b)

Calculate Euclidean distance between coordinates treating them as points on a flat plane.

Uses the Pythagorean theorem: d = √[(x₂-x₁)² + (y₂-y₁)²] Fast but only accurate for small geographic areas or projected coordinates.

Parameters:
  • a (LngLat) – First coordinate

  • b (LngLat) – Second coordinate

Returns:

Euclidean distance in decimal degrees

Return type:

float

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.distance.euclid import euclid
>>> p1 = LngLat(0.0, 0.0)
>>> p2 = LngLat(1.0, 1.0)
>>> distance = euclid(p1, p2)
>>> print(f"Distance: {distance:.4f} degrees")
Distance: 1.4142 degrees
rapidgeo.distance.euclid.squared(a, b)

Calculate squared Euclidean distance (avoids expensive square root).

Useful for distance comparisons where you don’t need the actual distance value. Faster than euclid() when you only need to compare relative distances.

Parameters:
  • a (LngLat) – First coordinate

  • b (LngLat) – Second coordinate

Returns:

Squared distance in decimal degrees²

Return type:

float

Examples

>>> from rapidgeo.distance.euclid import squared
>>> from rapidgeo import LngLat
>>> p1 = LngLat(0.0, 0.0)
>>> p2 = LngLat(3.0, 4.0)
>>> dist_sq = squared(p1, p2)
>>> print(f"Squared distance: {dist_sq}")
Squared distance: 25.0
rapidgeo.distance.euclid.point_to_segment(point, seg_start, seg_end)

Calculate the minimum Euclidean distance from a point to a line segment.

Projects the point onto the line segment and returns the shortest distance. Uses flat-plane geometry - not suitable for long geographic distances.

Parameters:
  • point (LngLat) – Point to measure from

  • seg_start (LngLat) – Start of line segment

  • seg_end (LngLat) – End of line segment

Returns:

Minimum distance in decimal degrees

Return type:

float

Examples

>>> from rapidgeo.distance.euclid import point_to_segment
>>> from rapidgeo import LngLat
>>> point = LngLat(1.0, 1.0)
>>> seg_start = LngLat(0.0, 0.0)
>>> seg_end = LngLat(2.0, 0.0)
>>> dist = point_to_segment(point, seg_start, seg_end)
>>> print(f"Distance to segment: {dist:.1f}")
Distance to segment: 1.0
rapidgeo.distance.euclid.point_to_segment_squared(point, seg_start, seg_end)

Calculate squared distance from point to line segment (avoids square root).

Faster version of point_to_segment() when you only need relative distances. Useful for finding the closest segment among many options.

Parameters:
  • point (LngLat) – Point to measure from

  • seg_start (LngLat) – Start of line segment

  • seg_end (LngLat) – End of line segment

Returns:

Squared minimum distance in decimal degrees²

Return type:

float

Examples

>>> from rapidgeo.distance.euclid import point_to_segment_squared
>>> from rapidgeo import LngLat
>>> point = LngLat(0.0, 1.0)
>>> seg_start = LngLat(0.0, 0.0)
>>> seg_end = LngLat(1.0, 0.0)
>>> dist_sq = point_to_segment_squared(point, seg_start, seg_end)
>>> print(f"Squared distance: {dist_sq}")
Squared distance: 1.0

Use Cases:

  • Comparing distances when you only need relative ordering

  • Small geographic areas where Earth’s curvature doesn’t matter

  • Point-to-line segment calculations

Example:

from rapidgeo.distance import LngLat
from rapidgeo.distance.euclid import euclid, squared, point_to_segment

p1 = LngLat.new_deg(-122.0, 37.0)
p2 = LngLat.new_deg(-121.0, 37.0)

# Euclidean distance in degrees
distance = euclid(p1, p2)
print(f"Euclidean: {distance:.6f} degrees")

# Squared distance (faster, avoid sqrt)
distance_sq = squared(p1, p2)
print(f"Squared: {distance_sq:.6f} degrees²")

# Distance from point to line segment
point = LngLat.new_deg(-121.5, 37.1)
seg_distance = point_to_segment(point, p1, p2)
print(f"Point to segment: {seg_distance:.6f} degrees")

Batch Operations

Batch operations process multiple coordinates efficiently.

Batch distance and bearing functions

rapidgeo.distance.batch.pairwise_haversine(points)

Calculate haversine distances between consecutive points in a path.

Computes the great-circle distance between each pair of consecutive points using the Haversine formula. Returns a list of distances with length len(points) - 1.

Parameters:

points (list[LngLat]) – List of coordinates representing a path

Returns:

Distances in meters between consecutive points. Length is len(points) - 1.

Return type:

list[float]

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.distance.batch import pairwise_haversine
>>> path = [
...     LngLat(-122.4194, 37.7749),  # San Francisco
...     LngLat(-87.6298, 41.8781),   # Chicago
...     LngLat(-74.0060, 40.7128),   # New York
... ]
>>> distances = pairwise_haversine(path)
>>> [f"{d/1000:.0f} km" for d in distances]
['2984 km', '1145 km']

Notes

  • Uses spherical Earth approximation (accurate to ±0.5% for distances <1000km)

  • Releases GIL during computation

  • For high precision, use Vincenty-based functions

See also

path_length_haversine

Sum of all consecutive distances

pairwise_bearings

Bearings between consecutive points

rapidgeo.distance.batch.path_length_haversine(points)

Calculate the total haversine distance along a path.

Computes the sum of great-circle distances between all consecutive points using the Haversine formula.

Parameters:

points (list[LngLat]) – List of coordinates representing a path (minimum 2 points)

Returns:

Total path length in meters

Return type:

float

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.distance.batch import path_length_haversine
>>> route = [
...     LngLat(-122.4194, 37.7749),  # San Francisco
...     LngLat(-87.6298, 41.8781),   # Chicago
...     LngLat(-74.0060, 40.7128),   # New York
... ]
>>> total_km = path_length_haversine(route) / 1000
>>> print(f"Total route: {total_km:.0f} km")
Total route: 4129 km

Notes

  • Uses spherical Earth approximation (accurate to ±0.5% for distances <1000km)

  • Releases Python GIL during computation

  • Returns 0.0 for paths with fewer than 2 points

  • For millimeter precision, use path_length_vincenty()

See also

pairwise_haversine

Get individual segment distances

pairwise_bearings

Get bearings between consecutive points

rapidgeo.distance.batch.path_length_haversine_batch(paths)
rapidgeo.distance.batch.pairwise_bearings(points)

Calculate initial bearings between consecutive points in a path.

Computes the compass bearing (azimuth) from each point to the next point along the great circle path. Returns a list of bearings with length len(points) - 1.

Bearings are measured in degrees (0-360°) clockwise from North: 0° = North, 90° = East, 180° = South, 270° = West

Parameters:

points (list[LngLat]) – List of coordinates representing a path

Returns:

Initial bearings in degrees (0-360°). Length is len(points) - 1.

Return type:

list[float]

Examples

>>> from rapidgeo import LngLat
>>> from rapidgeo.distance.batch import pairwise_bearings
>>> path = [
...     LngLat(0.0, 0.0),    # Origin
...     LngLat(1.0, 0.0),    # East
...     LngLat(1.0, 1.0),    # North
... ]
>>> bearings = pairwise_bearings(path)
>>> [f"{b:.1f}°" for b in bearings]
['90.0°', '0.0°']

Notes

  • Returns initial bearing at each point (bearing changes along great circles)

  • Releases Python GIL during computation

  • Returns empty list for paths with fewer than 2 points

  • Handles antimeridian crossing correctly

See also

pairwise_haversine

Distances between consecutive points

bearing

Single bearing calculation

Example:

from rapidgeo.distance import LngLat
from rapidgeo.distance.batch import pairwise_haversine, path_length_haversine

# Define a path
path = [
    LngLat.new_deg(-122.4194, 37.7749),  # San Francisco
    LngLat.new_deg(-87.6298, 41.8781),   # Chicago
    LngLat.new_deg(-74.0060, 40.7128),   # New York City
]

# Calculate distances between consecutive points
distances = list(pairwise_haversine(path))
print(f"Segment distances: {[d/1000 for d in distances]} km")

# Calculate total path length
total_length = path_length_haversine(path)
print(f"Total path length: {total_length / 1000:.1f} km")

NumPy Integration

When rapidgeo is compiled with NumPy support, additional functions are available for processing NumPy arrays efficiently.

# Check if NumPy support is available
try:
    from rapidgeo.distance import numpy as rgeo_numpy
    print("NumPy support available")
except ImportError:
    print("NumPy support not available")

Performance Notes

Algorithm Speed:

  • Euclidean is fastest

  • Haversine is moderate speed

  • Vincenty takes the most computation

Batch Operations:

  • Process multiple items at once for better efficiency

  • Iterator-based results to manage memory

Memory:

  • Each LngLat uses 16 bytes (two 64-bit floats)

  • Batch operations don’t duplicate input data unnecessarily