Zakladni verze planovace

This commit is contained in:
Michal Kváček
2024-04-15 18:13:37 +02:00
parent 5f0a1da052
commit cee5de003f
5 changed files with 109 additions and 54 deletions
+34
View File
@@ -0,0 +1,34 @@
import math
EARTH_RADIUS = 6378.1 # Radius of the Earth
def get_bearing(center_point: tuple[float, float], end_point: tuple[float, float]):
lat3 = math.radians(end_point[0])
long3 = math.radians(end_point[1])
lat1 = math.radians(center_point[0])
long1 = math.radians(center_point[1])
dLon = long3 - long1
X = math.cos(lat3) * math.sin(dLon)
Y = math.cos(lat1) * math.sin(lat3) - math.sin(lat1) * math.cos(lat3) * math.cos(dLon)
end_brng = math.atan2(X, Y)
return end_brng
def get_distance(a: tuple[float, float], b: tuple[float, float]):
lat1 = math.radians(a[0])
lon1 = math.radians(a[1])
lat2 = math.radians(b[0])
lon2 = math.radians(b[1])
dlon = lon2 - lon1
dlat = lat2 - lat1
a = math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
return EARTH_RADIUS * c
+7 -40
View File
@@ -8,6 +8,7 @@ import aiohttp
from sqlalchemy import delete from sqlalchemy import delete
from database import models from database import models
from database.transaction import get_session from database.transaction import get_session
from external.gps_utils import get_distance, get_bearing, EARTH_RADIUS
# https://pyopenair.readthedocs.io/en/latest/openair.html # https://pyopenair.readthedocs.io/en/latest/openair.html
@@ -57,40 +58,6 @@ class AirspaceItem:
class ArcExpander: class ArcExpander:
R = 6378.1 # Radius of the Earth
@staticmethod
def get_bearing(center_point, end_point):
lat3 = math.radians(end_point[0])
long3 = math.radians(end_point[1])
lat1 = math.radians(center_point[0])
long1 = math.radians(center_point[1])
dLon = long3 - long1
X = math.cos(lat3) * math.sin(dLon)
Y = math.cos(lat1) * math.sin(lat3) - math.sin(lat1) * math.cos(lat3) * math.cos(dLon)
end_brng = math.atan2(X, Y)
return end_brng
@classmethod
def get_distance(cls, a, b):
lat1 = math.radians(a[0])
lon1 = math.radians(a[1])
lat2 = math.radians(b[0])
lon2 = math.radians(b[1])
dlon = lon2 - lon1
dlat = lat2 - lat1
a = math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
return cls.R * c
@classmethod @classmethod
def get_arc_coordinates( def get_arc_coordinates(
cls, cls,
@@ -98,9 +65,9 @@ class ArcExpander:
origin_point: tuple[float, float], origin_point: tuple[float, float],
end_point: tuple[float, float] end_point: tuple[float, float]
) -> list[Coordinates]: ) -> list[Coordinates]:
initial_bearing = cls.get_bearing(center_point, origin_point) initial_bearing = get_bearing(center_point, origin_point)
target_bearing = cls.get_bearing(center_point, end_point) target_bearing = get_bearing(center_point, end_point)
distance = cls.get_distance(center_point, origin_point) distance = get_distance(center_point, origin_point)
print(f"DISTANCE {distance} meters, {center_point=}, {origin_point=}, {end_point=}") print(f"DISTANCE {distance} meters, {center_point=}, {origin_point=}, {end_point=}")
@@ -122,12 +89,12 @@ class ArcExpander:
for bearing in list_bearings: for bearing in list_bearings:
lat1, lon1 = math.radians(center_point[0]), math.radians(center_point[1]) lat1, lon1 = math.radians(center_point[0]), math.radians(center_point[1])
lat2 = math.asin( lat2 = math.asin(
math.sin(lat1) * math.cos(distance / cls.R) + math.cos(lat1) * math.sin(distance / cls.R) * math.cos(bearing) math.sin(lat1) * math.cos(distance / EARTH_RADIUS) + math.cos(lat1) * math.sin(distance / EARTH_RADIUS) * math.cos(bearing)
) )
lon2 = lon1 + math.atan2( lon2 = lon1 + math.atan2(
math.sin(bearing) * math.sin(distance / cls.R) * math.cos(lat1), math.sin(bearing) * math.sin(distance / EARTH_RADIUS) * math.cos(lat1),
math.cos(distance / cls.R) - math.sin(lat1) * math.sin(lat2) math.cos(distance / EARTH_RADIUS) - math.sin(lat1) * math.sin(lat2)
) )
lat2, lon2 = math.degrees(lat2), math.degrees(lon2) lat2, lon2 = math.degrees(lat2), math.degrees(lon2)
+2 -3
View File
@@ -1,11 +1,10 @@
from typing import List, Optional from typing import List
import strawberry import strawberry
from graphql import GraphQLError
from strawberry.types import Info from strawberry.types import Info
from database import models from database import models
from decorators.error_logging import error_logging from decorators.error_logging import error_logging
from decorators.endpoints import authenticated_user_only, allow_public from decorators.endpoints import authenticated_user_only, allow_public
from graphql_schema.entities.resolvers.base import BaseMutationResolver, BaseQueryResolver from graphql_schema.entities.resolvers.base import BaseQueryResolver
from graphql_schema.entities.resolvers.flight_plan import FlightPlanMutationResolver from graphql_schema.entities.resolvers.flight_plan import FlightPlanMutationResolver
from graphql_schema.entities.types.mutation_input import CreateFlightPlanInput, EditFlightPlanInput from graphql_schema.entities.types.mutation_input import CreateFlightPlanInput, EditFlightPlanInput
from graphql_schema.entities.types.types import FlightPlan from graphql_schema.entities.types.types import FlightPlan
@@ -1,7 +1,8 @@
from sqlalchemy import delete
from database import models from database import models
from database.transaction import get_session from database.transaction import get_session
from graphql_schema.entities.resolvers.base import BaseMutationResolver from graphql_schema.entities.resolvers.base import BaseMutationResolver
from graphql_schema.entities.types.mutation_input import CreateFlightPlanInput from graphql_schema.entities.types.mutation_input import CreateFlightPlanInput, EditFlightPlanInput
from graphql_schema.entities.types.types import FlightPlan from graphql_schema.entities.types.types import FlightPlan
@@ -9,22 +10,44 @@ class FlightPlanMutationResolver(BaseMutationResolver):
def __init__(self): def __init__(self):
super().__init__(graphql_type=FlightPlan, model=models.FlightPlan) super().__init__(graphql_type=FlightPlan, model=models.FlightPlan)
@staticmethod
async def save_markers(db, flight_plan: models.FlightPlan, markers: list):
position = 0
for marker in markers:
await models.FlightPlanMarker.create(db, data={
"position": position,
"flight_plan_id": flight_plan.id,
"type": marker.type,
"name": marker.name,
"gps_latitude": marker.gps_latitude,
"gps_longitude": marker.gps_longitude
})
position += 1
@staticmethod
async def reset_plan_markers(db, flight_plan: models.FlightPlan):
await db.execute(
delete(models.FlightPlanMarker)
.filter(models.FlightPlanMarker.flight_plan_id == flight_plan.id)
)
async def create(self, context, data: CreateFlightPlanInput) -> FlightPlan: async def create(self, context, data: CreateFlightPlanInput) -> FlightPlan:
input_data = data.to_dict() input_data = data.to_dict()
input_data['created_by_id'] = context.user_id input_data['created_by_id'] = context.user_id
async with get_session() as db: async with get_session() as db:
flight_plan = await self._do_create(db, data=input_data) flight_plan = await self._do_create(db, data=input_data)
await self.save_markers(db, flight_plan, data.markers)
return flight_plan
position = 0 async def update(self, id: int, data: EditFlightPlanInput, user_id: int) -> FlightPlan:
for marker in data.markers: input_data = data.to_dict()
await models.FlightPlanMarker.create(db, data={
"position": position, async with get_session() as db:
"flight_plan_id": flight_plan.id, flight_plan = await self._do_update(db, id, input_data)
"type": marker.type,
"name": marker.name, await self.reset_plan_markers(db, flight_plan)
"gps_latitude": marker.gps_latitude, await self.save_markers(db, flight_plan, data.markers)
"gps_longitude": marker.gps_longitude
})
return flight_plan return flight_plan
@@ -1,9 +1,12 @@
from __future__ import annotations from __future__ import annotations
import math
from datetime import datetime from datetime import datetime
from typing import Optional, List from typing import Optional, List
import strawberry import strawberry
from database import models from database import models
from decorators.endpoints import authenticated_user_only from decorators.endpoints import authenticated_user_only
from external.gps_utils import get_bearing, get_distance
from external.gpx_parser import GPXParser from external.gpx_parser import GPXParser
from graphql_schema.dataloaders.flight_duration import flight_duration_dataloader from graphql_schema.dataloaders.flight_duration import flight_duration_dataloader
from graphql_schema.dataloaders.multi_models import ( from graphql_schema.dataloaders.multi_models import (
@@ -185,11 +188,40 @@ class FlightPlanMarker:
pass pass
@strawberry.type
class FlightPlanTrack:
bearing: int
distance: float
from_: FlightPlanMarker = strawberry.field(name="from")
to: FlightPlanMarker
@strawberry_sqlalchemy_type(model=models.FlightPlan) @strawberry_sqlalchemy_type(model=models.FlightPlan)
class FlightPlan: class FlightPlan:
async def resolve_track(self):
markers = await self.markers()
navigation = []
for i in range(len(markers) - 1):
from_ = markers[i]
to = markers[i + 1]
point_from = (from_.gps_latitude, from_.gps_longitude)
point_to = (to.gps_latitude, to.gps_longitude)
navigation.append(FlightPlanTrack(
bearing=round(math.degrees(get_bearing(point_from, point_to)) % 360),
distance=round(get_distance(point_from, point_to), 1),
from_=from_,
to=to)
)
return navigation
markers: list[FlightPlanMarker] = strawberry.field( markers: list[FlightPlanMarker] = strawberry.field(
resolver=lambda root: flight_plan_markers_dataloader.load(root.id) resolver=lambda root: flight_plan_markers_dataloader.load(root.id)
) )
track: Optional[list[FlightPlanTrack]] = strawberry.field(
resolver=resolve_track
)
@strawberry_sqlalchemy_type(models.Copilot) @strawberry_sqlalchemy_type(models.Copilot)