Skip to main content
Glama
by zachegner
distance.py4.05 kB
"""Distance calculation utilities for EPA Envirofacts MCP Server.""" import math import logging from typing import List, Tuple from ..models.common import Coordinates, BoundingBox from ..models.facility import FacilityInfo logger = logging.getLogger(__name__) def calculate_bounding_box(lat: float, lon: float, radius_miles: float) -> BoundingBox: """Calculate bounding box for area queries. Args: lat: Center latitude lon: Center longitude radius_miles: Radius in miles Returns: BoundingBox object Raises: ValueError: If coordinates are invalid """ if not (-90 <= lat <= 90): raise ValueError(f"Invalid latitude: {lat}") if not (-180 <= lon <= 180): raise ValueError(f"Invalid longitude: {lon}") if radius_miles <= 0: raise ValueError(f"Radius must be positive: {radius_miles}") # Earth's radius in miles earth_radius_miles = 3959.0 # Convert radius to degrees lat_delta = radius_miles / earth_radius_miles * (180 / math.pi) lon_delta = radius_miles / (earth_radius_miles * math.cos(math.radians(lat))) * (180 / math.pi) # Calculate bounding box min_lat = lat - lat_delta max_lat = lat + lat_delta min_lon = lon - lon_delta max_lon = lon + lon_delta # Ensure coordinates are within valid ranges min_lat = max(min_lat, -90) max_lat = min(max_lat, 90) min_lon = max(min_lon, -180) max_lon = min(max_lon, 180) return BoundingBox( min_latitude=min_lat, max_latitude=max_lat, min_longitude=min_lon, max_longitude=max_lon ) def haversine_distance(coord1: Coordinates, coord2: Coordinates) -> float: """Calculate distance between two coordinates using Haversine formula. Args: coord1: First coordinates coord2: Second coordinates Returns: Distance in miles """ # Earth's radius in miles earth_radius_miles = 3959.0 # Convert to radians lat1_rad = math.radians(coord1.latitude) lat2_rad = math.radians(coord2.latitude) delta_lat_rad = math.radians(coord2.latitude - coord1.latitude) delta_lon_rad = math.radians(coord2.longitude - coord1.longitude) # Haversine formula a = (math.sin(delta_lat_rad / 2) ** 2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(delta_lon_rad / 2) ** 2) c = 2 * math.asin(math.sqrt(a)) return earth_radius_miles * c def filter_by_distance( facilities: List[FacilityInfo], center: Coordinates, max_distance_miles: float ) -> List[FacilityInfo]: """Filter facilities by distance from center point. Args: facilities: List of facilities to filter center: Center coordinates max_distance_miles: Maximum distance in miles Returns: List of facilities within distance, sorted by distance """ filtered_facilities = [] for facility in facilities: if facility.coordinates: distance = haversine_distance(center, facility.coordinates) if distance <= max_distance_miles: # Update distance in facility object facility.distance_miles = distance filtered_facilities.append(facility) # Sort by distance filtered_facilities.sort(key=lambda f: f.distance_miles or float('inf')) return filtered_facilities def calculate_distance_matrix( coordinates: List[Coordinates] ) -> List[List[float]]: """Calculate distance matrix between coordinates. Args: coordinates: List of coordinates Returns: Distance matrix (symmetric) """ n = len(coordinates) matrix = [[0.0] * n for _ in range(n)] for i in range(n): for j in range(i + 1, n): distance = haversine_distance(coordinates[i], coordinates[j]) matrix[i][j] = distance matrix[j][i] = distance return matrix

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zachegner/envirofacts-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server