chat_back/app/coords/router.py
urec56 bd3b83ea4c
All checks were successful
/ build (push) Successful in 3m6s
/ deploy (push) Successful in 3m17s
Добавил обработку координат для жижи
2025-07-28 22:54:54 +03:00

166 lines
4.2 KiB
Python

from fastapi import APIRouter, status, UploadFile, HTTPException
from fastapi.responses import StreamingResponse
from io import BytesIO, StringIO
import simplekml
import gpxpy
import re
import xml.etree.ElementTree as ET
router = APIRouter(prefix="/coords", tags=["Координаты для жижи"])
@router.post(
"/coords.txt",
status_code=status.HTTP_200_OK,
)
async def create_txt(file: UploadFile):
try:
file = await file.read()
file = StringIO(file.decode("utf-8"))
txt = generate_txt(file)
txt.seek(0)
return StreamingResponse(
content=txt,
media_type="text/plain",
headers={"Content-Disposition": "attachment; filename=dildo.txt", "Content-Type": "application/octet-stream"}
)
except:
raise HTTPException(status_code=409, detail="Ты передал какую-то хуйню")
def generate_txt(file: StringIO):
tree = ET.parse(file)
root = tree.getroot()
# Пространства имён — нужно указать, иначе findall ничего не найдёт
ns = {
'kml': 'http://www.opengis.net/kml/2.2',
'gx': 'http://www.google.com/kml/ext/2.2'
}
placemarks = root.findall('.//kml:Placemark', ns)
points = []
for placemark in placemarks:
# Получаем имя точки
name_elem = placemark.find('kml:name', ns)
name = name_elem.text.strip() if name_elem is not None else "(без названия)"
# Получаем координаты
coord_elem = placemark.find('.//kml:Point/kml:coordinates', ns)
if coord_elem is not None and coord_elem.text:
lon, lat, *_ = map(float, coord_elem.text.strip().split(','))
points.append((name, lat, lon))
buffer = StringIO()
for name, lat, lon in points:
point = (lat, lon)
buffer.write(f"{convert_point_decimal_to_dms(point)}:{name}\n")
return buffer
def decimal_to_dms_str(deg, is_lat=True):
direction = ''
if is_lat:
direction = 'N' if deg >= 0 else 'S'
else:
direction = 'E' if deg >= 0 else 'W'
deg = abs(deg)
d = int(deg)
m_float = (deg - d) * 60
m = int(m_float)
s = round((m_float - m) * 60)
return f"{d}°{m:02d}'{s:02d}\"{direction}"
def convert_point_decimal_to_dms(point):
lat, lon = point
return f"{decimal_to_dms_str(lat, True)} {decimal_to_dms_str(lon, False)}"
@router.post(
"/map.kmz",
status_code=status.HTTP_200_OK,
)
async def create_kmz(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():
if len(line.strip()) == 0:
continue
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)