Zakladni verze planovace
This commit is contained in:
Vendored
+34
@@ -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
@@ -8,6 +8,7 @@ import aiohttp
|
||||
from sqlalchemy import delete
|
||||
from database import models
|
||||
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
|
||||
@@ -57,40 +58,6 @@ class AirspaceItem:
|
||||
|
||||
|
||||
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
|
||||
def get_arc_coordinates(
|
||||
cls,
|
||||
@@ -98,9 +65,9 @@ class ArcExpander:
|
||||
origin_point: tuple[float, float],
|
||||
end_point: tuple[float, float]
|
||||
) -> list[Coordinates]:
|
||||
initial_bearing = cls.get_bearing(center_point, origin_point)
|
||||
target_bearing = cls.get_bearing(center_point, end_point)
|
||||
distance = cls.get_distance(center_point, origin_point)
|
||||
initial_bearing = get_bearing(center_point, origin_point)
|
||||
target_bearing = get_bearing(center_point, end_point)
|
||||
distance = get_distance(center_point, origin_point)
|
||||
|
||||
print(f"DISTANCE {distance} meters, {center_point=}, {origin_point=}, {end_point=}")
|
||||
|
||||
@@ -122,12 +89,12 @@ class ArcExpander:
|
||||
for bearing in list_bearings:
|
||||
lat1, lon1 = math.radians(center_point[0]), math.radians(center_point[1])
|
||||
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(
|
||||
math.sin(bearing) * math.sin(distance / cls.R) * math.cos(lat1),
|
||||
math.cos(distance / cls.R) - math.sin(lat1) * math.sin(lat2)
|
||||
math.sin(bearing) * math.sin(distance / EARTH_RADIUS) * math.cos(lat1),
|
||||
math.cos(distance / EARTH_RADIUS) - math.sin(lat1) * math.sin(lat2)
|
||||
)
|
||||
|
||||
lat2, lon2 = math.degrees(lat2), math.degrees(lon2)
|
||||
@@ -1,11 +1,10 @@
|
||||
from typing import List, Optional
|
||||
from typing import List
|
||||
import strawberry
|
||||
from graphql import GraphQLError
|
||||
from strawberry.types import Info
|
||||
from database import models
|
||||
from decorators.error_logging import error_logging
|
||||
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.types.mutation_input import CreateFlightPlanInput, EditFlightPlanInput
|
||||
from graphql_schema.entities.types.types import FlightPlan
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from sqlalchemy import delete
|
||||
from database import models
|
||||
from database.transaction import get_session
|
||||
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
|
||||
|
||||
|
||||
@@ -9,22 +10,44 @@ class FlightPlanMutationResolver(BaseMutationResolver):
|
||||
def __init__(self):
|
||||
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:
|
||||
input_data = data.to_dict()
|
||||
input_data['created_by_id'] = context.user_id
|
||||
|
||||
async with get_session() as db:
|
||||
flight_plan = await self._do_create(db, data=input_data)
|
||||
await self.save_markers(db, flight_plan, data.markers)
|
||||
return flight_plan
|
||||
|
||||
position = 0
|
||||
for marker in data.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
|
||||
})
|
||||
async def update(self, id: int, data: EditFlightPlanInput, user_id: int) -> FlightPlan:
|
||||
input_data = data.to_dict()
|
||||
|
||||
async with get_session() as db:
|
||||
flight_plan = await self._do_update(db, id, input_data)
|
||||
|
||||
await self.reset_plan_markers(db, flight_plan)
|
||||
await self.save_markers(db, flight_plan, data.markers)
|
||||
|
||||
return flight_plan
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
import strawberry
|
||||
from database import models
|
||||
from decorators.endpoints import authenticated_user_only
|
||||
from external.gps_utils import get_bearing, get_distance
|
||||
from external.gpx_parser import GPXParser
|
||||
from graphql_schema.dataloaders.flight_duration import flight_duration_dataloader
|
||||
from graphql_schema.dataloaders.multi_models import (
|
||||
@@ -185,11 +188,40 @@ class FlightPlanMarker:
|
||||
pass
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class FlightPlanTrack:
|
||||
bearing: int
|
||||
distance: float
|
||||
from_: FlightPlanMarker = strawberry.field(name="from")
|
||||
to: FlightPlanMarker
|
||||
|
||||
|
||||
@strawberry_sqlalchemy_type(model=models.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(
|
||||
resolver=lambda root: flight_plan_markers_dataloader.load(root.id)
|
||||
)
|
||||
track: Optional[list[FlightPlanTrack]] = strawberry.field(
|
||||
resolver=resolve_track
|
||||
)
|
||||
|
||||
|
||||
@strawberry_sqlalchemy_type(models.Copilot)
|
||||
|
||||
Reference in New Issue
Block a user