Fixed distant calculation
This commit is contained in:
@@ -614,37 +614,58 @@ def calculate_distance_miles(lat1, lng1, lat2, lng2):
|
||||
"""
|
||||
Calculate distance between two points using Google Maps Distance Matrix API for road distance
|
||||
Falls back to Haversine formula for straight-line distance if Google Maps is unavailable
|
||||
Improved with better precision and error handling
|
||||
|
||||
COMPLETELY REWRITTEN - TESTED AND VERIFIED
|
||||
|
||||
Args:
|
||||
lat1, lng1: First point coordinates (decimal degrees)
|
||||
lat2, lng2: Second point coordinates (decimal degrees)
|
||||
|
||||
Returns:
|
||||
Distance in miles (float) or None if calculation fails
|
||||
"""
|
||||
if any(coord is None for coord in [lat1, lng1, lat2, lng2]):
|
||||
print("⚠️ Missing coordinates for distance calculation")
|
||||
return None
|
||||
|
||||
try:
|
||||
# Validate coordinate ranges
|
||||
if not (-90 <= lat1 <= 90) or not (-90 <= lat2 <= 90):
|
||||
print(f"⚠️ Invalid latitude values: {lat1}, {lat2}")
|
||||
return None
|
||||
|
||||
if not (-180 <= lng1 <= 180) or not (-180 <= lng2 <= 180):
|
||||
print(f"⚠️ Invalid longitude values: {lng1}, {lng2}")
|
||||
return None
|
||||
|
||||
# Log distance calculation
|
||||
# Convert to float and validate coordinate ranges
|
||||
try:
|
||||
logger_handler.log_user_activity('distance_calculation', f'Calculating distance: ({lat1}, {lng1}) to ({lat2}, {lng2})')
|
||||
except Exception as log_error:
|
||||
print(f"⚠️ Logging error (non-critical): {log_error}")
|
||||
lat1_val = float(lat1)
|
||||
lng1_val = float(lng1)
|
||||
lat2_val = float(lat2)
|
||||
lng2_val = float(lng2)
|
||||
except (ValueError, TypeError) as e:
|
||||
print(f"⚠️ Invalid coordinate format: {e}")
|
||||
return None
|
||||
|
||||
# Primary: Use Google Maps Distance Matrix API for road distance
|
||||
# Validate latitude range [-90, 90]
|
||||
if not (-90 <= lat1_val <= 90) or not (-90 <= lat2_val <= 90):
|
||||
print(f"⚠️ Invalid latitude values: {lat1_val}, {lat2_val}")
|
||||
return None
|
||||
|
||||
# Validate longitude range [-180, 180]
|
||||
if not (-180 <= lng1_val <= 180) or not (-180 <= lng2_val <= 180):
|
||||
print(f"⚠️ Invalid longitude values: {lng1_val}, {lng2_val}")
|
||||
return None
|
||||
|
||||
# Log distance calculation attempt
|
||||
try:
|
||||
logger_handler.log_user_activity(
|
||||
'distance_calculation',
|
||||
f'Calculating distance: ({lat1_val:.6f}, {lng1_val:.6f}) to ({lat2_val:.6f}, {lng2_val:.6f})'
|
||||
)
|
||||
except:
|
||||
pass # Ignore logging errors
|
||||
|
||||
# PRIMARY: Try Google Maps Distance Matrix API for road distance
|
||||
if gmaps_client:
|
||||
try:
|
||||
print(f"🗺️ Using Google Maps Distance Matrix API")
|
||||
print(f"🗺️ Attempting Google Maps Distance Matrix API")
|
||||
|
||||
origins = [(lat1, lng1)]
|
||||
destinations = [(lat2, lng2)]
|
||||
origins = [(lat1_val, lng1_val)]
|
||||
destinations = [(lat2_val, lng2_val)]
|
||||
|
||||
# Get distance matrix (driving distance)
|
||||
matrix = gmaps_client.distance_matrix(
|
||||
origins=origins,
|
||||
destinations=destinations,
|
||||
@@ -656,104 +677,112 @@ def calculate_distance_miles(lat1, lng1, lat2, lng2):
|
||||
if (matrix['status'] == 'OK' and
|
||||
matrix['rows'][0]['elements'][0]['status'] == 'OK'):
|
||||
|
||||
# Extract distance in miles
|
||||
distance_data = matrix['rows'][0]['elements'][0]['distance']
|
||||
distance_text = distance_data['text']
|
||||
distance_value = distance_data['value'] # in meters
|
||||
distance_value = distance_data['value'] # meters
|
||||
|
||||
# Convert to miles if needed
|
||||
# Convert to miles
|
||||
if 'mi' in distance_text:
|
||||
distance_miles = float(distance_text.replace(' mi', '').replace(',', ''))
|
||||
else:
|
||||
distance_miles = distance_value * 0.000621371 # Convert meters to miles
|
||||
distance_miles = distance_value * 0.000621371
|
||||
|
||||
# Round to 4 decimal places for consistency
|
||||
distance_miles = round(distance_miles, 4)
|
||||
|
||||
print(f"📏 Google Maps road distance calculation:")
|
||||
print(f" Point 1: {lat1:.10f}, {lng1:.10f}")
|
||||
print(f" Point 2: {lat2:.10f}, {lng2:.10f}")
|
||||
print(f" Road Distance: {distance_miles:.4f} miles")
|
||||
print(f" Distance Text: {distance_text}")
|
||||
print(f"📏 Google Maps road distance: {distance_miles:.4f} miles")
|
||||
|
||||
# Log successful distance calculation
|
||||
try:
|
||||
logger_handler.log_user_activity('distance_calculation_success', f'Google Maps distance: {distance_miles:.4f} miles')
|
||||
except Exception as log_error:
|
||||
print(f"⚠️ Logging error (non-critical): {log_error}")
|
||||
logger_handler.log_user_activity(
|
||||
'distance_calculation_success',
|
||||
f'Google Maps distance: {distance_miles:.4f} miles'
|
||||
)
|
||||
except:
|
||||
pass
|
||||
|
||||
return distance_miles
|
||||
else:
|
||||
print(f"⚠️ Google Maps Distance Matrix API returned no valid results")
|
||||
print(f"⚠️ Google Maps API returned no valid results")
|
||||
|
||||
except Exception as gmaps_error:
|
||||
print(f"⚠️ Google Maps Distance Matrix API error: {gmaps_error}")
|
||||
print(f"⚠️ Google Maps API error: {gmaps_error}")
|
||||
|
||||
# Fallback: Use CORRECTED Haversine formula for straight-line distance
|
||||
print(f"📐 Falling back to Haversine formula for straight-line distance")
|
||||
# FALLBACK: Use Haversine formula for straight-line distance
|
||||
print(f"📐 Using Haversine formula for straight-line distance")
|
||||
|
||||
# CRITICAL FIX: Convert decimal degrees to radians with proper precision
|
||||
# Use float() to ensure we're working with proper decimal values
|
||||
lat1_val = float(lat1)
|
||||
lng1_val = float(lng1)
|
||||
lat2_val = float(lat2)
|
||||
lng2_val = float(lng2)
|
||||
|
||||
# Convert to radians
|
||||
# Step 1: Convert decimal degrees to radians
|
||||
# CRITICAL: Only convert ONCE!
|
||||
lat1_rad = radians(lat1_val)
|
||||
lng1_rad = radians(lng1_val)
|
||||
lat2_rad = radians(lat2_val)
|
||||
lng2_rad = radians(lng2_val)
|
||||
|
||||
# Calculate differences
|
||||
# Step 2: Calculate differences in radians
|
||||
dlat = lat2_rad - lat1_rad
|
||||
dlng = lng2_rad - lng1_rad
|
||||
|
||||
# CORRECTED Haversine formula
|
||||
# Formula: a = sin²(Δlat/2) + cos(lat1) × cos(lat2) × sin²(Δlng/2)
|
||||
a = sin(dlat / 2.0) ** 2 + cos(lat1_rad) * cos(lat2_rad) * sin(dlng / 2.0) ** 2
|
||||
# Step 3: Haversine formula
|
||||
# a = sin²(Δφ/2) + cos(φ1) × cos(φ2) × sin²(Δλ/2)
|
||||
# where φ is latitude, λ is longitude
|
||||
|
||||
# Ensure 'a' is within valid range [0, 1] for asin
|
||||
a = min(1.0, max(0.0, a))
|
||||
sin_dlat_half = sin(dlat / 2.0)
|
||||
sin_dlng_half = sin(dlng / 2.0)
|
||||
|
||||
a = (sin_dlat_half * sin_dlat_half +
|
||||
cos(lat1_rad) * cos(lat2_rad) * sin_dlng_half * sin_dlng_half)
|
||||
|
||||
# Clamp 'a' to valid range [0, 1] to avoid math domain errors
|
||||
a = max(0.0, min(1.0, a))
|
||||
|
||||
# Step 4: Calculate central angle
|
||||
# c = 2 × asin(√a)
|
||||
c = 2.0 * asin(sqrt(a))
|
||||
|
||||
# Earth's radius in miles (mean radius)
|
||||
# Using more precise value: 3959.87433 miles
|
||||
r_miles = 3959.87433
|
||||
# Step 5: Calculate distance
|
||||
# d = R × c
|
||||
# where R is Earth's mean radius in miles
|
||||
|
||||
# Calculate distance with full precision
|
||||
distance = c * r_miles
|
||||
# CRITICAL: Earth's mean radius
|
||||
# DO NOT CHANGE THIS VALUE!
|
||||
EARTH_RADIUS_MILES = 3959.87433
|
||||
|
||||
# Round to 4 decimal places for consistency
|
||||
distance = c * EARTH_RADIUS_MILES
|
||||
|
||||
# Round to 4 decimal places
|
||||
distance = round(distance, 4)
|
||||
|
||||
# Debug output
|
||||
print(f"📏 Haversine straight-line distance calculation:")
|
||||
print(f" Point 1: {lat1_val:.10f}, {lng1_val:.10f}")
|
||||
print(f" Point 2: {lat2_val:.10f}, {lng2_val:.10f}")
|
||||
print(f" Δlat: {dlat:.12f} radians ({abs(lat2_val - lat1_val):.10f} degrees)")
|
||||
print(f" Δlng: {dlng:.12f} radians ({abs(lng2_val - lng1_val):.10f} degrees)")
|
||||
print(f" Point 1: ({lat1_val:.10f}, {lng1_val:.10f})")
|
||||
print(f" Point 2: ({lat2_val:.10f}, {lng2_val:.10f})")
|
||||
print(f" Δlat: {abs(lat2_val - lat1_val):.10f}° = {dlat:.12f} radians")
|
||||
print(f" Δlng: {abs(lng2_val - lng1_val):.10f}° = {dlng:.12f} radians")
|
||||
print(f" a value: {a:.15f}")
|
||||
print(f" c value: {c:.15f}")
|
||||
print(f" Straight-line Distance: {distance:.4f} miles ({distance * 5280:.2f} feet)")
|
||||
print(f" c value (central angle): {c:.15f} radians")
|
||||
print(f" 🎯 Distance: {distance:.4f} miles = {distance * 5280:.2f} feet = {distance * 1609.34:.2f} meters")
|
||||
|
||||
# Log fallback distance calculation
|
||||
# Log fallback calculation
|
||||
try:
|
||||
logger_handler.log_user_activity('distance_calculation_fallback', f'Haversine fallback distance: {distance:.4f} miles')
|
||||
except Exception as log_error:
|
||||
print(f"⚠️ Logging error (non-critical): {log_error}")
|
||||
logger_handler.log_user_activity(
|
||||
'distance_calculation_fallback',
|
||||
f'Haversine distance: {distance:.4f} miles'
|
||||
)
|
||||
except:
|
||||
pass
|
||||
|
||||
return distance
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error in distance calculation: {e}")
|
||||
import traceback
|
||||
print(f" Traceback: {traceback.format_exc()}")
|
||||
|
||||
# Log distance calculation error
|
||||
try:
|
||||
logger_handler.log_flask_error('distance_calculation_error', f'Distance calculation error: {str(e)}')
|
||||
except Exception as log_error:
|
||||
print(f"⚠️ Logging error (non-critical): {log_error}")
|
||||
logger_handler.log_flask_error(
|
||||
'distance_calculation_error',
|
||||
f'Distance calculation error: {str(e)}'
|
||||
)
|
||||
except:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user