Skip to content

Commit

Permalink
Merge pull request #230 from hotosm/update_take_off_point_in_db
Browse files Browse the repository at this point in the history
Update take off point in database
  • Loading branch information
nrjadkry authored Sep 24, 2024
2 parents bf288df + a1f86b0 commit 4423a0c
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 7 deletions.
3 changes: 3 additions & 0 deletions src/backend/app/db/db_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ class DbTask(Base):
)
project_task_index = cast(int, Column(Integer))
outline = cast(WKBElement, Column(Geometry("POLYGON", srid=4326)))
take_off_point = cast(
WKBElement, Column(Geometry("POINT", srid=4326), nullable=True)
)


class DbProject(Base):
Expand Down
1 change: 0 additions & 1 deletion src/backend/app/drones/drone_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ class DbDrone(BaseDrone):
@staticmethod
async def one(db: Connection, drone_id: int):
"""Get a single drone by it's ID"""
print("drone_id = ", drone_id)
async with db.cursor(row_factory=class_row(DbDrone)) as cur:
await cur.execute(
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""added take_off_point in task
Revision ID: aec0d408df01
Revises: 2b92f8a9bbec
Create Date: 2024-09-24 03:57:03.760365
"""

import geoalchemy2
import sqlalchemy as sa
from alembic import op
from typing import Sequence, Union


# revision identifiers, used by Alembic.
revision: str = "aec0d408df01"
down_revision: Union[str, None] = "2b92f8a9bbec"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("projects", "forward_overlap_percent")
op.drop_column("projects", "side_overlap_percent")
op.add_column(
"tasks",
sa.Column(
"take_off_point",
geoalchemy2.types.Geometry(
geometry_type="POINT",
srid=4326,
from_text="ST_GeomFromEWKT",
name="geometry",
),
nullable=True,
),
)
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("tasks", "take_off_point")
op.add_column(
"projects",
sa.Column(
"side_overlap_percent",
sa.DOUBLE_PRECISION(precision=53),
autoincrement=False,
nullable=True,
),
)
op.add_column(
"projects",
sa.Column(
"forward_overlap_percent",
sa.DOUBLE_PRECISION(precision=53),
autoincrement=False,
nullable=True,
),
)
# ### end Alembic commands ###
47 changes: 46 additions & 1 deletion src/backend/app/tasks/task_logic.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,55 @@
from psycopg import Connection
import uuid
import json
from psycopg import Connection
from app.models.enums import HTTPStatus, State
from fastapi import HTTPException
from psycopg.rows import dict_row


async def update_take_off_point_in_db(
db: Connection, task_id: uuid.UUID, take_off_point: str
):
"""Update take_off_point in the task table"""

async with db.cursor() as cur:
await cur.execute(
"""
UPDATE tasks
SET take_off_point = ST_SetSRID(ST_GeomFromGeoJSON(%(take_off_point)s), 4326)
WHERE id = %(task_id)s;
""",
{
"task_id": str(task_id),
"take_off_point": json.dumps(take_off_point),
},
)


async def get_take_off_point_from_db(db: Connection, task_id: uuid.UUID):
"""Get take_off_point from task table"""

async with db.cursor(row_factory=dict_row) as cur:
await cur.execute(
"""
SELECT ST_AsGeoJSON(take_off_point) as take_off_point
FROM tasks
WHERE id = %(task_id)s;
""",
{"task_id": str(task_id)},
)

data = await cur.fetchone()
if data is None:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Task not found"
)
return (
json.loads(data["take_off_point"])
if data.get("take_off_point") is not None
else None
)


async def get_task_geojson(db: Connection, task_id: uuid.UUID):
async with db.cursor() as cur:
await cur.execute(
Expand Down
27 changes: 22 additions & 5 deletions src/backend/app/waypoints/waypoint_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
waypoints,
)
from app.models.enums import HTTPStatus
from app.tasks.task_logic import get_task_geojson
from app.tasks.task_logic import (
get_task_geojson,
get_take_off_point_from_db,
update_take_off_point_in_db,
)
from app.waypoints.waypoint_logic import check_point_within_buffer
from app.db import database
from app.utils import merge_multipolygon
Expand Down Expand Up @@ -61,16 +65,29 @@ async def get_task_waypoint(
# create a takeoff point in this format ["lon","lat"]
if take_off_point:
take_off_point = [take_off_point.longitude, take_off_point.latitude]

# Validate that the take-off point is within a 200m buffer of the task boundary
if not check_point_within_buffer(take_off_point, task_geojson, 200):
raise HTTPException(
status_code=400,
detail="Take off point should be within 200m of the boundary",
)

# Update take_off_point in tasks table
geojson_point = {"type": "Point", "coordinates": take_off_point}
await update_take_off_point_in_db(db, task_id, geojson_point)

else:
# take the centroid of the task as the takeoff point
task_polygon = shape(task_geojson["features"][0]["geometry"])
task_centroid = task_polygon.centroid
take_off_point = [task_centroid.x, task_centroid.y]
# Retrieve the take-off point from the database if not explicitly provided
take_off_point_from_db = await get_take_off_point_from_db(db, task_id)

if take_off_point_from_db:
take_off_point = take_off_point_from_db["coordinates"]
else:
# Use the centroid of the task polygon as the default take-off point
task_polygon = shape(task_geojson["features"][0]["geometry"])
task_centroid = task_polygon.centroid
take_off_point = [task_centroid.x, task_centroid.y]

forward_overlap = project.front_overlap if project.front_overlap else 70
side_overlap = project.side_overlap if project.side_overlap else 70
Expand Down

0 comments on commit 4423a0c

Please sign in to comment.