from fastapi import APIRouter, status, UploadFile, HTTPException from fastapi.responses import StreamingResponse from io import BytesIO, StringIO import simplekml import gpxpy import re router = APIRouter(prefix="/coords", tags=["Координаты для жижи"]) @router.post( "/map.kmz", status_code=status.HTTP_200_OK, ) async def create_chat(track_name: str, file: UploadFile): try: file = await file.read() file = StringIO(file.decode("utf-8")) kml = generate_kml(file, track_name) kml.seek(0) return StreamingResponse( content=kml, media_type="application/vnd.google-earth.kmz", headers={"Content-Disposition": "attachment; filename=generated.kmz"} ) except: raise HTTPException(status_code=409, detail="Ты передал какую-то хуйню") def generate_kml(file: StringIO, track_name: str): buffer = BytesIO() waypoints = [] kml = simplekml.Kml() points = [] for line in file.readlines(): coords = line.split(":") coord = coords[0].strip() current_label = int(coords[1].strip()) lat, lon = parse_dms_string(coord) name = f"Опора №{current_label}" wpt = gpxpy.gpx.GPXWaypoint(latitude=lat, longitude=lon, name=name) waypoints.append(wpt) points.append((lon,lat)) linestring = kml.newlinestring(name=track_name) linestring.coords = points linestring.style.linestyle.width = 3 linestring.style.linestyle.color = simplekml.Color.red for wpt in waypoints: lat = wpt.latitude lon = wpt.longitude name = wpt.name pnt = kml.newpoint(name=name, coords=[(lon, lat)]) # KML ожидает (lon, lat) pnt.style.iconstyle.icon.href = 'http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png' kml.savekmz(buffer) return buffer def parse_dms_string(dms_str): pattern = r"(\d{1,3})°(\d{1,2})'(\d{1,2})\"([NSEW])" matches = re.findall(pattern, dms_str) if len(matches) != 2: raise ValueError("Ожидалось две координаты в формате DMS") def to_decimal(d, m, s, direction): decimal = int(d) + int(m) / 60 + int(s) / 3600 if direction in ['S', 'W']: decimal = -decimal return decimal lat = to_decimal(*matches[0]) lon = to_decimal(*matches[1]) return round(lat, 6), round(lon, 6)