diff --git a/src/backend/app/tasks/task_schemas.py b/src/backend/app/tasks/task_schemas.py index b3bf77a7..2e1c5210 100644 --- a/src/backend/app/tasks/task_schemas.py +++ b/src/backend/app/tasks/task_schemas.py @@ -267,6 +267,7 @@ class TaskDetailsOut(BaseModel): side_overlap: Optional[float] = None gsd_cm_px: Optional[float] = None gimble_angles_degrees: Optional[int] = None + centroid: dict @field_validator("state", mode="after") @classmethod @@ -312,7 +313,8 @@ async def get_task_details(db: Connection, task_id: uuid.UUID): ), 'id', tasks.id ) AS outline, - + -- Calculate the centroid of the outline + ST_AsGeoJSON(ST_Centroid(tasks.outline))::jsonb AS centroid, te.created_at, te.updated_at, te.state, diff --git a/src/backend/app/waypoints/waypoint_routes.py b/src/backend/app/waypoints/waypoint_routes.py index 4613e08c..f038f8cc 100644 --- a/src/backend/app/waypoints/waypoint_routes.py +++ b/src/backend/app/waypoints/waypoint_routes.py @@ -1,3 +1,4 @@ +import os import uuid import geojson import shutil @@ -147,7 +148,9 @@ async def get_task_waypoint( outfile = outfile = f"/tmp/{uuid.uuid4()}" kmz_file = wpml.create_wpml(placemarks, outfile) return FileResponse( - kmz_file, media_type="application/zip", filename="flight_plan.kmz" + kmz_file, + media_type="application/zip", + filename=f"{task_id}_flight_plan.kmz", ) flight_data = calculate_flight_time_from_placemarks(placemarks) return {"results": placemarks, "flight_data": flight_data} @@ -257,3 +260,23 @@ async def generate_kmz( return FileResponse( output_file, media_type="application/zip", filename="output.kmz" ) + + +@router.post("/{task_id}/generate-kmz/") +async def generate_kmz_with_placemarks( + task_id: uuid.UUID, data: waypoint_schemas.PlacemarksFeature +): + try: + outfile = f"/tmp/{task_id}_flight_plan.kmz" + + kmz_file = wpml.create_wpml(data.model_dump(), outfile) + if not os.path.exists(kmz_file): + raise HTTPException(status_code=500, detail="Failed to generate KMZ file.") + return FileResponse( + kmz_file, + media_type="application/zip", + filename=f"{task_id}_flight_plan.kmz", + ) + + except Exception as e: + raise HTTPException(status_code=500, detail=f"Error generating KMZ: {str(e)}") diff --git a/src/backend/app/waypoints/waypoint_schemas.py b/src/backend/app/waypoints/waypoint_schemas.py index e20fd87c..b9299b78 100644 --- a/src/backend/app/waypoints/waypoint_schemas.py +++ b/src/backend/app/waypoints/waypoint_schemas.py @@ -1,5 +1,7 @@ import json +from typing import List, Optional from pydantic import BaseModel, model_validator +from geojson_pydantic import FeatureCollection, Feature, Point class PointField(BaseModel): @@ -12,3 +14,33 @@ def validate_to_json(cls, value): if isinstance(value, str): return cls(**json.loads(value)) return value + + +class Properties(BaseModel): + altitude: float + gimbal_angle: str + heading: float + index: int + speed: float + take_photo: bool + elevation: Optional[float] = None + + +class Geometry(Point): + pass + + +class Feature(Feature): + geometry: Geometry + properties: Properties + + +class CRS(BaseModel): + properties: dict + type: str + + +class PlacemarksFeature(FeatureCollection): + type: str = "FeatureCollection" + crs: Optional[CRS] = None + features: List[Feature]