0
# Distance Calculations
1
2
Geopy provides precise distance calculations using geodesic (ellipsoidal earth model) and great-circle (spherical earth model) algorithms with automatic unit conversions and destination point calculations.
3
4
## Capabilities
5
6
### Distance Base Class
7
8
Base class for all distance measurements with automatic unit conversions and arithmetic operations.
9
10
```python { .api }
11
from geopy.distance import Distance
12
13
class Distance:
14
"""
15
Base class for distance measurements with unit conversions.
16
Supports arithmetic operations and destination calculations.
17
"""
18
19
def __init__(self, *args, **kwargs):
20
"""Initialize distance measurement"""
21
22
@property
23
def kilometers(self) -> float:
24
"""Distance in kilometers"""
25
26
@property
27
def km(self) -> float:
28
"""Alias for kilometers"""
29
30
@property
31
def meters(self) -> float:
32
"""Distance in meters"""
33
34
@property
35
def m(self) -> float:
36
"""Alias for meters"""
37
38
@property
39
def miles(self) -> float:
40
"""Distance in miles"""
41
42
@property
43
def mi(self) -> float:
44
"""Alias for miles"""
45
46
@property
47
def feet(self) -> float:
48
"""Distance in feet"""
49
50
@property
51
def ft(self) -> float:
52
"""Alias for feet"""
53
54
@property
55
def nautical(self) -> float:
56
"""Distance in nautical miles"""
57
58
@property
59
def nm(self) -> float:
60
"""Alias for nautical miles"""
61
62
def destination(self, point, bearing, distance=None):
63
"""
64
Calculate destination point from bearing and distance.
65
66
Parameters:
67
- point (Point): Starting point
68
- bearing (float): Bearing in degrees (0-360)
69
- distance (Distance): Distance to travel (uses self if None)
70
71
Returns:
72
Point: Destination point
73
"""
74
75
def __add__(self, other):
76
"""Addition with another distance"""
77
78
def __sub__(self, other):
79
"""Subtraction with another distance"""
80
81
def __mul__(self, scalar):
82
"""Multiplication by scalar"""
83
84
def __truediv__(self, scalar):
85
"""Division by scalar"""
86
87
def __lt__(self, other):
88
"""Less than comparison"""
89
90
def __le__(self, other):
91
"""Less than or equal comparison"""
92
93
def __eq__(self, other):
94
"""Equality comparison"""
95
96
def __ne__(self, other):
97
"""Inequality comparison"""
98
99
def __gt__(self, other):
100
"""Greater than comparison"""
101
102
def __ge__(self, other):
103
"""Greater than or equal comparison"""
104
```
105
106
### Geodesic Distance
107
108
Precise distance calculations using ellipsoidal earth model for maximum accuracy.
109
110
```python { .api }
111
from geopy.distance import geodesic
112
113
class geodesic(Distance):
114
"""
115
Calculate geodesic distance using ellipsoidal earth model.
116
Most accurate distance calculation method.
117
"""
118
119
def __init__(self, point1=None, point2=None, ellipsoid='WGS-84'):
120
"""
121
Initialize geodesic distance calculation.
122
123
Parameters:
124
- point1 (Point): First point
125
- point2 (Point): Second point
126
- ellipsoid (str): Reference ellipsoid name
127
128
Supported ellipsoids:
129
- 'WGS-84' (default) - World Geodetic System 1984
130
- 'GRS-80' - Geodetic Reference System 1980
131
- 'Airy (1830)' - Airy ellipsoid 1830
132
- 'Intl 1924' - International ellipsoid 1924
133
- 'Clarke (1880)' - Clarke ellipsoid 1880
134
- 'GRS-67' - Geodetic Reference System 1967
135
"""
136
137
def measure(self, point1, point2):
138
"""
139
Measure distance between two points.
140
141
Parameters:
142
- point1 (Point): First point
143
- point2 (Point): Second point
144
145
Returns:
146
geodesic: Distance measurement
147
"""
148
149
def destination(self, point, bearing, distance=None):
150
"""
151
Calculate destination point using geodesic calculation.
152
153
Parameters:
154
- point (Point): Starting point
155
- bearing (float): Initial bearing in degrees (0-360)
156
- distance (Distance): Distance to travel
157
158
Returns:
159
Point: Destination point with precise coordinates
160
"""
161
```
162
163
### Great Circle Distance
164
165
Faster distance calculations using spherical earth model with good accuracy for most applications.
166
167
```python { .api }
168
from geopy.distance import great_circle
169
170
class great_circle(Distance):
171
"""
172
Calculate great-circle distance using spherical earth model.
173
Faster but less accurate than geodesic calculations.
174
"""
175
176
def __init__(self, point1=None, point2=None, radius=EARTH_RADIUS):
177
"""
178
Initialize great-circle distance calculation.
179
180
Parameters:
181
- point1 (Point): First point
182
- point2 (Point): Second point
183
- radius (float): Earth radius in kilometers (default: 6371.009)
184
"""
185
186
def measure(self, point1, point2):
187
"""
188
Measure great-circle distance between two points.
189
190
Parameters:
191
- point1 (Point): First point
192
- point2 (Point): Second point
193
194
Returns:
195
great_circle: Distance measurement
196
"""
197
198
def destination(self, point, bearing, distance=None):
199
"""
200
Calculate destination point using great-circle calculation.
201
202
Parameters:
203
- point (Point): Starting point
204
- bearing (float): Bearing in degrees (0-360)
205
- distance (Distance): Distance to travel
206
207
Returns:
208
Point: Destination point
209
"""
210
```
211
212
### Constants and Aliases
213
214
```python { .api }
215
from geopy.distance import EARTH_RADIUS, ELLIPSOIDS, distance
216
217
# Constants
218
EARTH_RADIUS = 6371.009 # Mean earth radius in kilometers
219
220
ELLIPSOIDS = {
221
'WGS-84': (6378137.0, 6356752.314245, 298.257223563),
222
'GRS-80': (6378137.0, 6356752.314140, 298.257222101),
223
'Airy (1830)': (6377563.396, 6356256.909, 299.3249646),
224
'Intl 1924': (6378388.0, 6356911.946, 297.0),
225
'Clarke (1880)': (6378249.145, 6356514.870, 293.465),
226
'GRS-67': (6378160.0, 6356774.719, 298.25)
227
}
228
229
# Default distance algorithm (alias for geodesic)
230
distance = geodesic
231
```
232
233
### Utility Functions
234
235
```python { .api }
236
from geopy.distance import lonlat
237
238
def lonlat(x, y, z=0):
239
"""
240
Convert (longitude, latitude) to Point(latitude, longitude).
241
242
Utility function to handle coordinate order differences.
243
Many APIs return coordinates as [longitude, latitude] but
244
Point expects (latitude, longitude).
245
246
Parameters:
247
- x (float): Longitude
248
- y (float): Latitude
249
- z (float): Altitude (optional)
250
251
Returns:
252
Point: Point(latitude, longitude, altitude)
253
"""
254
```
255
256
## Usage Examples
257
258
### Basic Distance Calculations
259
260
```python
261
from geopy.distance import geodesic, great_circle
262
from geopy.point import Point
263
264
# Define some locations
265
new_york = Point(40.7128, -74.0060)
266
los_angeles = Point(34.0522, -118.2437)
267
london = Point(51.5074, -0.1278)
268
269
# Calculate distances using different algorithms
270
geo_distance = geodesic(new_york, los_angeles)
271
gc_distance = great_circle(new_york, los_angeles)
272
273
print(f"Geodesic distance: {geo_distance.miles:.2f} miles")
274
print(f"Great circle distance: {gc_distance.miles:.2f} miles")
275
print(f"Difference: {abs(geo_distance.miles - gc_distance.miles):.2f} miles")
276
277
# Access different units
278
print(f"Distance in kilometers: {geo_distance.km:.2f}")
279
print(f"Distance in meters: {geo_distance.m:.2f}")
280
print(f"Distance in nautical miles: {geo_distance.nautical:.2f}")
281
print(f"Distance in feet: {geo_distance.feet:.2f}")
282
```
283
284
### Distance Arithmetic
285
286
```python
287
from geopy.distance import geodesic
288
289
# Calculate multiple distances
290
ny_to_la = geodesic(new_york, los_angeles)
291
la_to_london = geodesic(los_angeles, london)
292
293
# Arithmetic operations
294
total_distance = ny_to_la + la_to_london
295
half_distance = ny_to_la / 2
296
double_distance = ny_to_la * 2
297
298
print(f"NY to LA: {ny_to_la.miles:.0f} miles")
299
print(f"LA to London: {la_to_london.miles:.0f} miles")
300
print(f"Total journey: {total_distance.miles:.0f} miles")
301
print(f"Half distance: {half_distance.miles:.0f} miles")
302
303
# Distance comparisons
304
if ny_to_la > la_to_london:
305
print("NY to LA is farther than LA to London")
306
else:
307
print("LA to London is farther than NY to LA")
308
309
# Sort locations by distance from reference point
310
reference = Point(41.8781, -87.6298) # Chicago
311
cities = [
312
("New York", new_york),
313
("Los Angeles", los_angeles),
314
("London", london)
315
]
316
317
cities_with_distance = [
318
(name, point, geodesic(reference, point))
319
for name, point in cities
320
]
321
322
# Sort by distance
323
cities_sorted = sorted(cities_with_distance, key=lambda x: x[2].kilometers)
324
325
print("\nCities sorted by distance from Chicago:")
326
for name, point, dist in cities_sorted:
327
print(f"{name}: {dist.miles:.0f} miles")
328
```
329
330
### Destination Point Calculations
331
332
```python
333
from geopy.distance import geodesic
334
from geopy.point import Point
335
336
# Starting point
337
start = Point(40.7128, -74.0060) # New York
338
339
# Calculate destinations at different bearings and distances
340
distance_100km = geodesic(kilometers=100)
341
distance_200mi = geodesic(miles=200)
342
343
# Cardinal directions (0° = North, 90° = East, 180° = South, 270° = West)
344
destinations = {}
345
bearings = [
346
(0, "North"),
347
(90, "East"),
348
(180, "South"),
349
(270, "West"),
350
(45, "Northeast"),
351
(135, "Southeast"),
352
(225, "Southwest"),
353
(315, "Northwest")
354
]
355
356
print("Destinations 100km from New York:")
357
for bearing, direction in bearings:
358
dest = distance_100km.destination(start, bearing)
359
destinations[direction] = dest
360
print(f"{direction} ({bearing}°): {dest.format_decimal()}")
361
362
# Calculate round trip
363
outbound = geodesic(start, destinations["North"])
364
# Bearing back is opposite direction (180° difference)
365
home = outbound.destination(destinations["North"], 180)
366
367
print(f"\nRound trip verification:")
368
print(f"Original: {start.format_decimal()}")
369
print(f"Returned: {home.format_decimal()}")
370
print(f"Difference: {geodesic(start, home).meters:.2f} meters")
371
```
372
373
### Advanced Distance Applications
374
375
```python
376
from geopy.distance import geodesic
377
from geopy.point import Point
378
import math
379
380
def calculate_area_of_triangle(p1, p2, p3):
381
"""Calculate area of triangle using Heron's formula with geodesic distances"""
382
# Calculate side lengths
383
a = geodesic(p2, p3).meters
384
b = geodesic(p1, p3).meters
385
c = geodesic(p1, p2).meters
386
387
# Semi-perimeter
388
s = (a + b + c) / 2
389
390
# Heron's formula
391
area = math.sqrt(s * (s - a) * (s - b) * (s - c))
392
return area # in square meters
393
394
def find_center_point(points):
395
"""Find geographic center (centroid) of multiple points"""
396
if not points:
397
return None
398
399
# Convert to cartesian coordinates for averaging
400
x_total = y_total = z_total = 0
401
402
for point in points:
403
lat_rad = math.radians(point.latitude)
404
lon_rad = math.radians(point.longitude)
405
406
x = math.cos(lat_rad) * math.cos(lon_rad)
407
y = math.cos(lat_rad) * math.sin(lon_rad)
408
z = math.sin(lat_rad)
409
410
x_total += x
411
y_total += y
412
z_total += z
413
414
# Average
415
x_avg = x_total / len(points)
416
y_avg = y_total / len(points)
417
z_avg = z_total / len(points)
418
419
# Convert back to lat/lon
420
hyp = math.sqrt(x_avg**2 + y_avg**2)
421
lat = math.atan2(z_avg, hyp)
422
lon = math.atan2(y_avg, x_avg)
423
424
return Point(math.degrees(lat), math.degrees(lon))
425
426
def create_circle_of_points(center, radius_km, num_points=8):
427
"""Create circle of points around a center at specified radius"""
428
points = []
429
distance_obj = geodesic(kilometers=radius_km)
430
431
for i in range(num_points):
432
bearing = (360 / num_points) * i
433
point = distance_obj.destination(center, bearing)
434
points.append(point)
435
436
return points
437
438
# Example usage
439
triangle_points = [
440
Point(40.7128, -74.0060), # New York
441
Point(41.8781, -87.6298), # Chicago
442
Point(39.7392, -104.9903) # Denver
443
]
444
445
area = calculate_area_of_triangle(*triangle_points)
446
center = find_center_point(triangle_points)
447
circle = create_circle_of_points(center, 500, 12) # 500km radius, 12 points
448
449
print(f"Triangle area: {area/1e6:.2f} square kilometers")
450
print(f"Geographic center: {center.format_decimal()}")
451
print(f"Circle points around center:")
452
for i, point in enumerate(circle):
453
bearing = (360 / len(circle)) * i
454
print(f" {bearing:3.0f}°: {point.format_decimal()}")
455
```
456
457
### Performance Considerations
458
459
```python
460
from geopy.distance import geodesic, great_circle
461
from geopy.point import Point
462
import time
463
464
def benchmark_distance_calculations():
465
"""Compare performance of geodesic vs great-circle calculations"""
466
467
# Test data
468
points = [
469
Point(40.7128, -74.0060), # New York
470
Point(34.0522, -118.2437), # Los Angeles
471
Point(51.5074, -0.1278), # London
472
Point(35.6762, 139.6503), # Tokyo
473
Point(-33.8688, 151.2093), # Sydney
474
]
475
476
num_calculations = 1000
477
478
# Benchmark geodesic
479
start_time = time.time()
480
for _ in range(num_calculations):
481
for i in range(len(points)):
482
for j in range(i+1, len(points)):
483
geodesic(points[i], points[j])
484
geodesic_time = time.time() - start_time
485
486
# Benchmark great circle
487
start_time = time.time()
488
for _ in range(num_calculations):
489
for i in range(len(points)):
490
for j in range(i+1, len(points)):
491
great_circle(points[i], points[j])
492
great_circle_time = time.time() - start_time
493
494
print(f"Geodesic calculations: {geodesic_time:.3f} seconds")
495
print(f"Great circle calculations: {great_circle_time:.3f} seconds")
496
print(f"Speed ratio: {geodesic_time/great_circle_time:.1f}x")
497
498
# Accuracy comparison
499
p1, p2 = points[0], points[1]
500
geo_dist = geodesic(p1, p2)
501
gc_dist = great_circle(p1, p2)
502
503
print(f"\nAccuracy comparison (NY to LA):")
504
print(f"Geodesic: {geo_dist.kilometers:.6f} km")
505
print(f"Great circle: {gc_dist.kilometers:.6f} km")
506
print(f"Difference: {abs(geo_dist.kilometers - gc_dist.kilometers):.6f} km")
507
print(f"Relative error: {abs(geo_dist.kilometers - gc_dist.kilometers)/geo_dist.kilometers*100:.4f}%")
508
509
# Run benchmark
510
benchmark_distance_calculations()
511
```
512
513
### Custom Ellipsoids
514
515
```python
516
from geopy.distance import geodesic, ELLIPSOIDS
517
518
# View available ellipsoids
519
print("Available ellipsoids:")
520
for name, (a, b, f) in ELLIPSOIDS.items():
521
print(f" {name}: a={a}m, b={b}m, f=1/{f:.1f}")
522
523
# Compare distances using different ellipsoids
524
p1 = Point(40.7128, -74.0060) # New York
525
p2 = Point(51.5074, -0.1278) # London
526
527
ellipsoid_results = {}
528
for ellipsoid_name in ELLIPSOIDS.keys():
529
distance = geodesic(p1, p2, ellipsoid=ellipsoid_name)
530
ellipsoid_results[ellipsoid_name] = distance.kilometers
531
532
print(f"\nDistance NY to London using different ellipsoids:")
533
for name, dist in ellipsoid_results.items():
534
print(f" {name}: {dist:.6f} km")
535
536
# Find the range
537
min_dist = min(ellipsoid_results.values())
538
max_dist = max(ellipsoid_results.values())
539
print(f"\nRange: {max_dist - min_dist:.6f} km")
540
print(f"Relative variation: {(max_dist - min_dist)/min_dist*100:.4f}%")
541
```