51 lines
1.7 KiB
Python
51 lines
1.7 KiB
Python
import re
|
|
|
|
|
|
def component_to_str(value: float, pos_letter: str, neg_letter: str) -> str:
|
|
"""Convert a coordinate value to a string with a hemisphere indicator."""
|
|
hemi = pos_letter if value >= 0 else neg_letter
|
|
abs_val = abs(value)
|
|
degrees = int(abs_val)
|
|
fraction = int(round((abs_val - degrees) * 100)) # .25 becomes 25
|
|
return f"{hemi}{degrees:02d}{fraction:02d}"
|
|
|
|
|
|
def latitude_to_str(latitude: float) -> str:
|
|
"""Convert a latitude value to a string with a hemisphere indicator."""
|
|
return component_to_str(latitude, "N", "S")
|
|
|
|
|
|
def longitude_to_str(latitude: float) -> str:
|
|
"""Convert a longitude value to a string with a hemisphere indicator."""
|
|
return component_to_str(latitude, "E", "W")
|
|
|
|
|
|
def coordinate_to_str(latitude: float, longitude: float) -> str:
|
|
"""Format latitude and longitude into a string with hemisphere indicators."""
|
|
lat_str = latitude_to_str(latitude)
|
|
lon_str = longitude_to_str(longitude)
|
|
return f"{lat_str}{lon_str}"
|
|
|
|
|
|
def parse_coordinate_str(coord: str) -> tuple[float, float]:
|
|
"""
|
|
Parse a formatted coordinate string (e.g. 'N5225E0040' or 'S1350W12200')
|
|
back into (latitude, longitude) float values.
|
|
"""
|
|
# Match hemisphere + degrees + fractional part
|
|
match = re.match(r"^([NS])(\d{2,3})(\d{2})([EW])(\d{2,3})(\d{2})$", coord)
|
|
if not match:
|
|
raise ValueError(f"Invalid coordinate format: {coord}")
|
|
|
|
lat_hemi, lat_deg, lat_frac, lon_hemi, lon_deg, lon_frac = match.groups()
|
|
|
|
lat = int(lat_deg) + int(lat_frac) / 100.0
|
|
lon = int(lon_deg) + int(lon_frac) / 100.0
|
|
|
|
if lat_hemi == "S":
|
|
lat = -lat
|
|
if lon_hemi == "W":
|
|
lon = -lon
|
|
|
|
return lat, lon
|