Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update the flight plan time & waypoints counts if user terrian #390

Merged
merged 1 commit into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions src/backend/app/projects/project_routes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import os
import shutil
import uuid
from typing import Annotated, Optional
from uuid import UUID
Expand Down Expand Up @@ -39,7 +40,7 @@
)
from app.users import user_schemas
from minio.deleteobjects import DeleteObject
from drone_flightplan import waypoints
from drone_flightplan import waypoints, add_elevation_from_dem

router = APIRouter(
prefix=f"{settings.API_PREFIX}/projects",
Expand Down Expand Up @@ -668,6 +669,7 @@ async def get_project_waypoints_counts(
meters: float = 100,
project_geojson: UploadFile = File(...),
is_terrain_follow: bool = False,
dem: UploadFile = File(None),
user_data: AuthUser = Depends(login_required),
):
"""
Expand Down Expand Up @@ -708,6 +710,32 @@ async def get_project_waypoints_counts(
generate_3d=generate_3d,
take_off_point=None,
)

# Handle terrain-following logic if a DEM is provided
points_with_elevation = points
if is_terrain_follow and dem:
temp_dir = f"/tmp/{uuid.uuid4()}"
try:
os.makedirs(temp_dir, exist_ok=True)
dem_path = os.path.join(temp_dir, "dem.tif")
outfile_with_elevation = os.path.join(
temp_dir, "output_file_with_elevation.geojson"
)

with open(dem_path, "wb") as dem_file:
dem_file.write(await dem.read())

add_elevation_from_dem(dem_path, points, outfile_with_elevation)

with open(outfile_with_elevation, "r") as inpointsfile:
points_with_elevation = inpointsfile.read()
except Exception as e:
log.error(f"Error processing DEM: {e}")

finally:
if os.path.exists(temp_dir):
shutil.rmtree(temp_dir)

return {
"avg_no_of_waypoints": len(json.loads(points)["features"]),
"avg_no_of_waypoints": len(json.loads(points_with_elevation)["features"]),
}
51 changes: 50 additions & 1 deletion src/backend/app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import json
import base64
from datetime import datetime, timezone
from typing import Optional, Union, Any
from typing import Dict, Optional, Union, Any
from geojson_pydantic import Feature, MultiPolygon, Polygon
from geojson_pydantic import FeatureCollection as FeatCol
from geoalchemy2 import WKBElement
Expand All @@ -21,6 +21,9 @@
from email.mime.text import MIMEText
from email.utils import formataddr
from aiosmtplib import send as send_email
from shapely.geometry import Point
from shapely.ops import transform
from pyproj import Transformer


log = logging.getLogger(__name__)
Expand Down Expand Up @@ -551,3 +554,49 @@ async def send_project_approval_email_to_regulator(
subject="Project Review Request for Drone Operations Approval",
html_content=html_content,
)


def calculate_flight_time_from_placemarks(placemarks: Dict) -> Dict:
"""
Calculate the total and average flight time based on placemarks and dynamically format the output.

Args:
placemarks (Dict): GeoJSON-like data structure with flight plan.

Returns:
Dict: Contains formatted total flight time and segment times.
"""
total_time = 0
features = placemarks["features"]
transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857", always_xy=True)
for i in range(1, len(features)):
# Extract current and previous coordinates
prev_coords = features[i - 1]["geometry"]["coordinates"][:2]
curr_coords = features[i]["geometry"]["coordinates"][:2]
speed = features[i]["properties"]["speed"] # Speed in m/s

# Create Shapely Points and transform to planar coordinates for distance calculation
prev_point = Point(transform(transformer.transform, Point(prev_coords)))
curr_point = Point(transform(transformer.transform, Point(curr_coords)))

# Calculate distance (meters) and time (seconds)
distance = prev_point.distance(curr_point)
segment_time = distance / speed
total_time += segment_time

# Dynamically format the total flight time
hours = int(total_time // 3600)
minutes = int((total_time % 3600) // 60)
seconds = round(total_time % 60, 2)

if total_time < 60:
formatted_time = f"{seconds} seconds"
elif total_time < 3600:
formatted_time = f"{minutes} minutes {seconds:.2f} seconds"
else:
formatted_time = f"{hours} hours {minutes} minutes {seconds:.2f} seconds"

return {
"total_flight_time": formatted_time,
"total_flight_time_seconds": round(total_time, 2),
}
11 changes: 7 additions & 4 deletions src/backend/app/waypoints/waypoint_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@
get_take_off_point_from_db,
update_take_off_point_in_db,
)
from app.waypoints.waypoint_logic import check_point_within_buffer
from app.waypoints.waypoint_logic import (
check_point_within_buffer,
)
from app.db import database
from app.utils import merge_multipolygon
from app.utils import calculate_flight_time_from_placemarks, merge_multipolygon
from app.s3 import get_file_from_bucket
from typing import Annotated
from psycopg import Connection
from app.projects import project_deps
from shapely.geometry import shape
from app.waypoints import waypoint_schemas


# Constant to convert gsd to Altitude above ground level
GSD_to_AGL_CONST = 29.7 # For DJI Mini 4 Pro

Expand Down Expand Up @@ -146,8 +149,8 @@ async def get_task_waypoint(
return FileResponse(
kmz_file, media_type="application/zip", filename="flight_plan.kmz"
)

return placemarks
flight_data = calculate_flight_time_from_placemarks(placemarks)
return {"results": placemarks, "flight_data": flight_data}


@router.post("/")
Expand Down
Loading