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