diff --git a/game/data/doctrine.py b/game/data/doctrine.py index fce67b1b..2b385f2c 100644 --- a/game/data/doctrine.py +++ b/game/data/doctrine.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from datetime import timedelta -from game.utils import nm_to_meter, feet_to_meter +from game.utils import Distance, feet, nm_to_meter, feet_to_meter @dataclass(frozen=True) @@ -15,13 +15,13 @@ class Doctrine: strike_max_range: int sead_max_range: int - rendezvous_altitude: int + rendezvous_altitude: Distance hold_distance: int push_distance: int join_distance: int split_distance: int ingress_egress_distance: int - ingress_altitude: int + ingress_altitude: Distance egress_altitude: int min_patrol_altitude: int @@ -47,13 +47,13 @@ MODERN_DOCTRINE = Doctrine( antiship=True, strike_max_range=1500000, sead_max_range=1500000, - rendezvous_altitude=feet_to_meter(25000), + rendezvous_altitude=feet(25000), hold_distance=nm_to_meter(15), push_distance=nm_to_meter(20), join_distance=nm_to_meter(20), split_distance=nm_to_meter(20), ingress_egress_distance=nm_to_meter(45), - ingress_altitude=feet_to_meter(20000), + ingress_altitude=feet(20000), egress_altitude=feet_to_meter(20000), min_patrol_altitude=feet_to_meter(15000), max_patrol_altitude=feet_to_meter(33000), @@ -75,13 +75,13 @@ COLDWAR_DOCTRINE = Doctrine( antiship=True, strike_max_range=1500000, sead_max_range=1500000, - rendezvous_altitude=feet_to_meter(22000), + rendezvous_altitude=feet(22000), hold_distance=nm_to_meter(10), push_distance=nm_to_meter(10), join_distance=nm_to_meter(10), split_distance=nm_to_meter(10), ingress_egress_distance=nm_to_meter(30), - ingress_altitude=feet_to_meter(18000), + ingress_altitude=feet(18000), egress_altitude=feet_to_meter(18000), min_patrol_altitude=feet_to_meter(10000), max_patrol_altitude=feet_to_meter(24000), @@ -107,9 +107,9 @@ WWII_DOCTRINE = Doctrine( push_distance=nm_to_meter(5), join_distance=nm_to_meter(5), split_distance=nm_to_meter(5), - rendezvous_altitude=feet_to_meter(10000), + rendezvous_altitude=feet(10000), ingress_egress_distance=nm_to_meter(7), - ingress_altitude=feet_to_meter(8000), + ingress_altitude=feet(8000), egress_altitude=feet_to_meter(8000), min_patrol_altitude=feet_to_meter(4000), max_patrol_altitude=feet_to_meter(15000), diff --git a/game/utils.py b/game/utils.py index b570e355..37ec4eae 100644 --- a/game/utils.py +++ b/game/utils.py @@ -1,65 +1,18 @@ -def meter_to_feet(value_in_meter: float) -> int: - """Converts meters to feets +from __future__ import annotations - :arg value_in_meter Value in meters - """ - return int(3.28084 * value_in_meter) +import math +from dataclasses import dataclass +from typing import Union +METERS_TO_FEET = 3.28084 +FEET_TO_METERS = 1 / METERS_TO_FEET +NM_TO_METERS = 1852 +METERS_TO_NM = 1 / NM_TO_METERS -def feet_to_meter(value_in_feet: float) -> int: - """Converts feets to meters - - :arg value_in_feet Value in feets - """ - return int(value_in_feet / 3.28084) - - -def meter_to_nm(value_in_meter: float) -> int: - """Converts meters to nautic miles - - :arg value_in_meter Value in meters - """ - return int(value_in_meter / 1852) - - -def nm_to_meter(value_in_nm: float) -> int: - """Converts nautic miles to meters - - :arg value_in_nm Value in nautic miles - """ - return int(value_in_nm * 1852) - - -def knots_to_kph(value_in_knots: float) -> int: - """Converts Knots to Kilometer Per Hour - - :arg value_in_knots Knots - """ - return int(value_in_knots * 1.852) - - -def mps_to_knots(value_in_mps: float) -> int: - """Converts Meters Per Second To Knots - - :arg value_in_mps Meters Per Second - """ - return int(value_in_mps * 1.943) - - -def mps_to_kph(speed: float) -> int: - """Converts meters per second to kilometers per hour. - - :arg speed Speed in m/s. - """ - return int(speed * 3.6) - - -def kph_to_mps(speed: float) -> int: - """Converts kilometers per hour to meters per second. - - :arg speed Speed in KPH. - """ - return int(speed / 3.6) +KNOTS_TO_KPH = 1.852 +KPH_TO_KNOTS = 1 / KNOTS_TO_KPH +MS_TO_KPH = 3.6 +KPH_TO_MS = 1 / MS_TO_KPH def heading_sum(h, a) -> int: @@ -71,5 +24,171 @@ def heading_sum(h, a) -> int: else: return h + def opposite_heading(h): - return heading_sum(h, 180) \ No newline at end of file + return heading_sum(h, 180) + + +def meter_to_feet(value: float) -> int: + return int(meters(value).feet) + + +def feet_to_meter(value: float) -> int: + return int(feet(value).meters) + + +def meter_to_nm(value: float) -> int: + return int(meters(value).nautical_miles) + + +def nm_to_meter(value: float) -> int: + return int(nautical_miles(value).meters) + + +def knots_to_kph(value: float) -> int: + return int(knots(value).kph) + + +def kph_to_mps(value: float) -> int: + return int(kph(value).meters_per_second) + + +def mps_to_kph(value: float) -> int: + return int(mps(value).kph) + + +def mps_to_knots(value: float) -> int: + return int(mps(value).knots) + + +@dataclass(frozen=True, order=True) +class Distance: + distance_in_meters: float + + @property + def feet(self) -> float: + return self.distance_in_meters * METERS_TO_FEET + + @property + def meters(self) -> float: + return self.distance_in_meters + + @property + def nautical_miles(self) -> float: + return self.distance_in_meters * METERS_TO_NM + + @classmethod + def from_feet(cls, value: float) -> Distance: + return cls(value * FEET_TO_METERS) + + @classmethod + def from_meters(cls, value: float) -> Distance: + return cls(value) + + @classmethod + def from_nautical_miles(cls, value: float) -> Distance: + return cls(value * NM_TO_METERS) + + def __mul__(self, other: Union[float, int]) -> Distance: + return Distance(self.meters * other) + + def __truediv__(self, other: Union[float, int]) -> Distance: + return Distance(self.meters / other) + + def __floordiv__(self, other: Union[float, int]) -> Distance: + return Distance(self.meters // other) + + +def feet(value: float) -> Distance: + return Distance.from_feet(value) + + +def meters(value: float) -> Distance: + return Distance.from_meters(value) + + +def nautical_miles(value: float) -> Distance: + return Distance.from_nautical_miles(value) + + +@dataclass(frozen=True, order=True) +class Speed: + speed_in_kph: float + + @property + def knots(self) -> float: + return self.speed_in_kph * KPH_TO_KNOTS + + @property + def kph(self) -> float: + return self.speed_in_kph + + @property + def meters_per_second(self) -> float: + return self.speed_in_kph * KPH_TO_MS + + def mach(self, altitude: Distance = meters(0)) -> float: + c_sound = mach(1, altitude) + return self.speed_in_kph / c_sound.kph + + @classmethod + def from_knots(cls, value: float) -> Speed: + return cls(value * KNOTS_TO_KPH) + + @classmethod + def from_kph(cls, value: float) -> Speed: + return cls(value) + + @classmethod + def from_meters_per_second(cls, value: float) -> Speed: + return cls(value * MS_TO_KPH) + + @classmethod + def from_mach(cls, value: float, altitude: Distance) -> Speed: + # https://www.grc.nasa.gov/WWW/K-12/airplane/atmos.html + if altitude <= feet(36152): + temperature_f = 59 - 0.00356 * altitude.feet + else: + # There's another formula for altitudes over 82k feet, but we better + # not be planning waypoints that high... + temperature_f = -70 + + temperature_k = (temperature_f + 459.67) * (5 / 9) + + # https://www.engineeringtoolbox.com/specific-heat-ratio-d_602.html + # Dependent on temperature, but varies very little (+/-0.001) + # between -40F and 180F. + heat_capacity_ratio = 1.4 + + # https://www.grc.nasa.gov/WWW/K-12/airplane/sound.html + gas_constant = 286 # m^2/s^2/K + c_sound = math.sqrt(heat_capacity_ratio * gas_constant * temperature_k) + return mps(c_sound) * value + + def __mul__(self, other: Union[float, int]) -> Speed: + return Speed(self.kph * other) + + def __truediv__(self, other: Union[float, int]) -> Speed: + return Speed(self.kph / other) + + def __floordiv__(self, other: Union[float, int]) -> Speed: + return Speed(self.kph // other) + + +def knots(value: float) -> Speed: + return Speed.from_knots(value) + + +def kph(value: float) -> Speed: + return Speed.from_kph(value) + + +def mps(value: float) -> Speed: + return Speed.from_meters_per_second(value) + + +def mach(value: float, altitude: Distance) -> Speed: + return Speed.from_mach(value, altitude) + + +SPEED_OF_SOUND_AT_SEA_LEVEL = knots(661.5) diff --git a/gen/aircraft.py b/gen/aircraft.py index 87233d35..fa3c9a9c 100644 --- a/gen/aircraft.py +++ b/gen/aircraft.py @@ -85,7 +85,7 @@ from game.theater.controlpoint import ( ) from game.theater.theatergroundobject import TheaterGroundObject from game.unitmap import UnitMap -from game.utils import knots_to_kph, nm_to_meter +from game.utils import Distance, Speed, knots_to_kph, kph, meters, nm_to_meter from gen.airsupportgen import AirSupport from gen.ato import AirTaskingOrder, Package from gen.callsigns import create_group_callsign_from_unit @@ -110,12 +110,12 @@ from .naming import namegen if TYPE_CHECKING: from game import Game -WARM_START_HELI_AIRSPEED = 120 -WARM_START_HELI_ALT = 500 -WARM_START_ALTITUDE = 3000 -WARM_START_AIRSPEED = 550 +WARM_START_HELI_AIRSPEED = kph(120) +WARM_START_HELI_ALT = meters(500) +WARM_START_ALTITUDE = meters(3000) +WARM_START_AIRSPEED = kph(550) -RTB_ALTITUDE = 800 +RTB_ALTITUDE = meters(800) RTB_DISTANCE = 5000 HELI_ALT = 500 @@ -867,7 +867,9 @@ class AircraftConflictGenerator: start_type=self._start_type(start_type), group_size=count) - def _add_radio_waypoint(self, group: FlyingGroup, position, altitude: int, airspeed: int = 600): + def _add_radio_waypoint(self, group: FlyingGroup, position, + altitude: Distance, + airspeed: int = 600) -> MovingPoint: point = group.add_waypoint(position, altitude, airspeed) point.alt_type = "RADIO" return point @@ -884,7 +886,8 @@ class AircraftConflictGenerator: tod_location = position.point_from_heading(heading, RTB_DISTANCE) self._add_radio_waypoint(group, tod_location, last_waypoint.alt) - destination_waypoint = self._add_radio_waypoint(group, position, RTB_ALTITUDE) + destination_waypoint = self._add_radio_waypoint(group, position, + RTB_ALTITUDE) if isinstance(at, Airport): group.land_at(at) return destination_waypoint @@ -1380,7 +1383,8 @@ class PydcsWaypointBuilder: def build(self) -> MovingPoint: waypoint = self.group.add_waypoint( - Point(self.waypoint.x, self.waypoint.y), self.waypoint.alt, + Point(self.waypoint.x, self.waypoint.y), + self.waypoint.alt.meters, name=self.mission.string(self.waypoint.name)) if self.waypoint.flyover: diff --git a/gen/flights/flight.py b/gen/flights/flight.py index b3f5c286..b1768d54 100644 --- a/gen/flights/flight.py +++ b/gen/flights/flight.py @@ -10,6 +10,7 @@ from dcs.unittype import FlyingType from game import db from game.theater.controlpoint import ControlPoint, MissionTarget +from game.utils import Distance, meters if TYPE_CHECKING: from gen.ato import Package @@ -67,7 +68,7 @@ class FlightWaypointType(Enum): class FlightWaypoint: def __init__(self, waypoint_type: FlightWaypointType, x: float, y: float, - alt: int = 0) -> None: + alt: Distance = meters(0)) -> None: """Creates a flight waypoint. Args: diff --git a/gen/flights/flightplan.py b/gen/flights/flightplan.py index 478275cc..6e809a9e 100644 --- a/gen/flights/flightplan.py +++ b/gen/flights/flightplan.py @@ -28,7 +28,7 @@ from game.theater import ( TheaterGroundObject, ) from game.theater.theatergroundobject import EwrGroundObject -from game.utils import nm_to_meter, meter_to_nm +from game.utils import Distance, meters, nm_to_meter, meter_to_nm from .closestairfields import ObjectiveDistanceCache from .flight import Flight, FlightType, FlightWaypoint, FlightWaypointType from .traveltime import GroundSpeed, TravelTime @@ -537,7 +537,8 @@ class StrikeFlightPlan(FormationFlightPlan): def target_area_waypoint(self) -> FlightWaypoint: return FlightWaypoint(FlightWaypointType.TARGET_GROUP_LOC, self.package.target.position.x, - self.package.target.position.y, 0) + self.package.target.position.y, + meters(0)) @property def travel_time_to_target(self) -> timedelta: @@ -863,10 +864,10 @@ class FlightPlanBuilder: raise InvalidObjectiveLocation(flight.flight_type, location) start, end = self.racetrack_for_objective(location) - patrol_alt = random.randint( + patrol_alt = meters(random.randint( self.doctrine.min_patrol_altitude, self.doctrine.max_patrol_altitude - ) + )) builder = WaypointBuilder(self.game.conditions, flight, self.doctrine) start, end = builder.race_track(start, end, patrol_alt) @@ -983,8 +984,8 @@ class FlightPlanBuilder: """ location = self.package.target - patrol_alt = random.randint(self.doctrine.min_patrol_altitude, - self.doctrine.max_patrol_altitude) + patrol_alt = meters(random.randint(self.doctrine.min_patrol_altitude, + self.doctrine.max_patrol_altitude)) # Create points builder = WaypointBuilder(self.game.conditions, flight, self.doctrine) diff --git a/gen/flights/traveltime.py b/gen/flights/traveltime.py index 078dabc7..82e5b45b 100644 --- a/gen/flights/traveltime.py +++ b/gen/flights/traveltime.py @@ -8,7 +8,13 @@ from typing import Optional, TYPE_CHECKING from dcs.mapping import Point from dcs.unittype import FlyingType -from game.utils import meter_to_nm +from game.utils import ( + Distance, + SPEED_OF_SOUND_AT_SEA_LEVEL, + Speed, + kph, mach, meter_to_nm, + meters, +) from gen.flights.flight import Flight if TYPE_CHECKING: @@ -18,7 +24,7 @@ if TYPE_CHECKING: class GroundSpeed: @classmethod - def for_flight(cls, flight: Flight, altitude: int) -> int: + def for_flight(cls, flight: Flight, altitude: Distance) -> int: if not issubclass(flight.unit_type, FlyingType): raise TypeError("Flight has non-flying unit") @@ -27,56 +33,20 @@ class GroundSpeed: # on fuel, but mission speed will be fast enough to keep the flight # safer. - c_sound_sea_level = 661.5 - - # DCS's max speed is in kph at 0 MSL. Convert to knots. - max_speed = flight.unit_type.max_speed * 0.539957 - if max_speed > c_sound_sea_level: + # DCS's max speed is in kph at 0 MSL. + max_speed = kph(flight.unit_type.max_speed) + if max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL: # Aircraft is supersonic. Limit to mach 0.8 to conserve fuel and # account for heavily loaded jets. - return int(cls.from_mach(0.8, altitude)) + return int(mach(0.8, altitude).knots) # For subsonic aircraft, assume the aircraft can reasonably perform at # 80% of its maximum, and that it can maintain the same mach at altitude # as it can at sea level. This probably isn't great assumption, but # might. be sufficient given the wiggle room. We can come up with # another heuristic if needed. - mach = max_speed * 0.8 / c_sound_sea_level - return int(cls.from_mach(mach, altitude)) # knots - - @staticmethod - def from_mach(mach: float, altitude_m: int) -> float: - """Returns the ground speed in knots for the given mach and altitude. - - Args: - mach: The mach number to convert to ground speed. - altitude_m: The altitude in meters. - - Returns: - The ground speed corresponding to the given altitude and mach number - in knots. - """ - # https://www.grc.nasa.gov/WWW/K-12/airplane/atmos.html - altitude_ft = altitude_m * 3.28084 - if altitude_ft <= 36152: - temperature_f = 59 - 0.00356 * altitude_ft - else: - # There's another formula for altitudes over 82k feet, but we better - # not be planning waypoints that high... - temperature_f = -70 - - temperature_k = (temperature_f + 459.67) * (5 / 9) - - # https://www.engineeringtoolbox.com/specific-heat-ratio-d_602.html - # Dependent on temperature, but varies very little (+/-0.001) - # between -40F and 180F. - heat_capacity_ratio = 1.4 - - # https://www.grc.nasa.gov/WWW/K-12/airplane/sound.html - gas_constant = 286 # m^2/s^2/K - c_sound = math.sqrt(heat_capacity_ratio * gas_constant * temperature_k) - # c_sound is in m/s, convert to knots. - return (c_sound * 1.944) * mach + cruise_mach = max_speed.mach() * 0.8 + return int(mach(cruise_mach, altitude).knots) class TravelTime: diff --git a/gen/flights/waypointbuilder.py b/gen/flights/waypointbuilder.py index 85a83d08..7eccc96a 100644 --- a/gen/flights/waypointbuilder.py +++ b/gen/flights/waypointbuilder.py @@ -14,6 +14,7 @@ from game.theater import ( OffMapSpawn, TheaterGroundObject, ) +from game.utils import Distance, meters from game.weather import Conditions from .flight import Flight, FlightWaypoint, FlightWaypointType @@ -53,7 +54,9 @@ class WaypointBuilder: FlightWaypointType.NAV, position.x, position.y, - 500 if self.is_helo else self.doctrine.rendezvous_altitude + meters( + 500 + ) if self.is_helo else self.doctrine.rendezvous_altitude ) waypoint.name = "NAV" waypoint.alt_type = "BARO" @@ -64,7 +67,7 @@ class WaypointBuilder: FlightWaypointType.TAKEOFF, position.x, position.y, - 0 + meters(0) ) waypoint.name = "TAKEOFF" waypoint.alt_type = "RADIO" @@ -84,7 +87,9 @@ class WaypointBuilder: FlightWaypointType.NAV, position.x, position.y, - 500 if self.is_helo else self.doctrine.rendezvous_altitude + meters( + 500 + ) if self.is_helo else self.doctrine.rendezvous_altitude ) waypoint.name = "NAV" waypoint.alt_type = "BARO" @@ -95,7 +100,7 @@ class WaypointBuilder: FlightWaypointType.LANDING_POINT, position.x, position.y, - 0 + meters(0) ) waypoint.name = "LANDING" waypoint.alt_type = "RADIO" @@ -116,12 +121,12 @@ class WaypointBuilder: position = divert.position if isinstance(divert, OffMapSpawn): if self.is_helo: - altitude = 500 + altitude = meters(500) else: altitude = self.doctrine.rendezvous_altitude altitude_type = "BARO" else: - altitude = 0 + altitude = meters(0) altitude_type = "RADIO" waypoint = FlightWaypoint( @@ -142,7 +147,9 @@ class WaypointBuilder: FlightWaypointType.LOITER, position.x, position.y, - 500 if self.is_helo else self.doctrine.rendezvous_altitude + meters( + 500 + ) if self.is_helo else self.doctrine.rendezvous_altitude ) waypoint.pretty_name = "Hold" waypoint.description = "Wait until push time" @@ -154,7 +161,9 @@ class WaypointBuilder: FlightWaypointType.JOIN, position.x, position.y, - 500 if self.is_helo else self.doctrine.ingress_altitude + meters( + 500 + ) if self.is_helo else self.doctrine.ingress_altitude ) waypoint.pretty_name = "Join" waypoint.description = "Rendezvous with package" @@ -166,7 +175,9 @@ class WaypointBuilder: FlightWaypointType.SPLIT, position.x, position.y, - 500 if self.is_helo else self.doctrine.ingress_altitude + meters( + 500 + ) if self.is_helo else self.doctrine.ingress_altitude ) waypoint.pretty_name = "Split" waypoint.description = "Depart from package" @@ -179,7 +190,9 @@ class WaypointBuilder: ingress_type, position.x, position.y, - 500 if self.is_helo else self.doctrine.ingress_altitude + meters( + 500 + ) if self.is_helo else self.doctrine.ingress_altitude ) waypoint.pretty_name = "INGRESS on " + objective.name waypoint.description = "INGRESS on " + objective.name @@ -193,7 +206,9 @@ class WaypointBuilder: FlightWaypointType.EGRESS, position.x, position.y, - 500 if self.is_helo else self.doctrine.ingress_altitude + meters( + 500 + ) if self.is_helo else self.doctrine.ingress_altitude ) waypoint.pretty_name = "EGRESS from " + target.name waypoint.description = "EGRESS from " + target.name @@ -218,7 +233,7 @@ class WaypointBuilder: FlightWaypointType.TARGET_POINT, target.target.position.x, target.target.position.y, - 0 + meters(0) ) waypoint.description = description waypoint.pretty_name = description @@ -249,7 +264,7 @@ class WaypointBuilder: FlightWaypointType.TARGET_GROUP_LOC, location.position.x, location.position.y, - 0 + meters(0) ) waypoint.description = name waypoint.pretty_name = name @@ -274,7 +289,7 @@ class WaypointBuilder: FlightWaypointType.CAS, position.x, position.y, - 500 if self.is_helo else 1000 + meters(500) if self.is_helo else meters(1000) ) waypoint.alt_type = "RADIO" waypoint.description = "Provide CAS" @@ -283,12 +298,12 @@ class WaypointBuilder: return waypoint @staticmethod - def race_track_start(position: Point, altitude: int) -> FlightWaypoint: + def race_track_start(position: Point, altitude: Distance) -> FlightWaypoint: """Creates a racetrack start waypoint. Args: position: Position of the waypoint. - altitude: Altitude of the racetrack in meters. + altitude: Altitude of the racetrack. """ waypoint = FlightWaypoint( FlightWaypointType.PATROL_TRACK, @@ -302,12 +317,12 @@ class WaypointBuilder: return waypoint @staticmethod - def race_track_end(position: Point, altitude: int) -> FlightWaypoint: + def race_track_end(position: Point, altitude: Distance) -> FlightWaypoint: """Creates a racetrack end waypoint. Args: position: Position of the waypoint. - altitude: Altitude of the racetrack in meters. + altitude: Altitude of the racetrack. """ waypoint = FlightWaypoint( FlightWaypointType.PATROL, @@ -321,7 +336,7 @@ class WaypointBuilder: return waypoint def race_track(self, start: Point, end: Point, - altitude: int) -> Tuple[FlightWaypoint, FlightWaypoint]: + altitude: Distance) -> Tuple[FlightWaypoint, FlightWaypoint]: """Creates two waypoint for a racetrack orbit. Args: @@ -333,7 +348,7 @@ class WaypointBuilder: self.race_track_end(end, altitude)) @staticmethod - def sweep_start(position: Point, altitude: int) -> FlightWaypoint: + def sweep_start(position: Point, altitude: Distance) -> FlightWaypoint: """Creates a sweep start waypoint. Args: @@ -352,7 +367,7 @@ class WaypointBuilder: return waypoint @staticmethod - def sweep_end(position: Point, altitude: int) -> FlightWaypoint: + def sweep_end(position: Point, altitude: Distance) -> FlightWaypoint: """Creates a sweep end waypoint. Args: @@ -371,7 +386,7 @@ class WaypointBuilder: return waypoint def sweep(self, start: Point, end: Point, - altitude: int) -> Tuple[FlightWaypoint, FlightWaypoint]: + altitude: Distance) -> Tuple[FlightWaypoint, FlightWaypoint]: """Creates two waypoint for a racetrack orbit. Args: @@ -404,7 +419,9 @@ class WaypointBuilder: FlightWaypointType.TARGET_GROUP_LOC, target.position.x, target.position.y, - 500 if self.is_helo else self.doctrine.ingress_altitude + meters( + 500 + ) if self.is_helo else self.doctrine.ingress_altitude ) waypoint.name = "TARGET" waypoint.description = "Escort the package" diff --git a/gen/kneeboard.py b/gen/kneeboard.py index 61f0af9a..4ee3aa28 100644 --- a/gen/kneeboard.py +++ b/gen/kneeboard.py @@ -153,7 +153,7 @@ class FlightPlanBuilder: self.rows.append([ str(waypoint.number), waypoint.waypoint.pretty_name, - str(int(units.meters_to_feet(waypoint.waypoint.alt))), + str(int(waypoint.waypoint.alt.feet)), self._waypoint_distance(waypoint.waypoint), self._ground_speed(waypoint.waypoint), self._format_time(waypoint.waypoint.tot), diff --git a/qt_ui/widgets/map/QLiberationMap.py b/qt_ui/widgets/map/QLiberationMap.py index 8b49077c..3c3be38e 100644 --- a/qt_ui/widgets/map/QLiberationMap.py +++ b/qt_ui/widgets/map/QLiberationMap.py @@ -441,7 +441,7 @@ class QLiberationMap(QGraphicsView): waypoint: FlightWaypoint, position: Tuple[int, int], flight_plan: FlightPlan) -> None: - altitude = meter_to_feet(waypoint.alt) + altitude = int(waypoint.alt.feet) altitude_type = "AGL" if waypoint.alt_type == "RADIO" else "MSL" prefix = "TOT" diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py index ee72d8c0..137b70b7 100644 --- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py +++ b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py @@ -12,7 +12,7 @@ class QFlightWaypointInfoBox(QGroupBox): self.flight_wpt = FlightWaypoint(0,0,0) self.x_position_label = QLabel(str(self.flight_wpt.x)) self.y_position_label = QLabel(str(self.flight_wpt.y)) - self.alt_label = QLabel(str(self.flight_wpt.alt)) + self.alt_label = QLabel(str(int(self.flight_wpt.alt.feet))) self.name_label = QLabel(str(self.flight_wpt.name)) self.desc_label = QLabel(str(self.flight_wpt.description)) self.init_ui() @@ -60,7 +60,7 @@ class QFlightWaypointInfoBox(QGroupBox): self.flight_wpt = FlightWaypoint(0,0,0) self.x_position_label.setText(str(self.flight_wpt.x)) self.y_position_label.setText(str(self.flight_wpt.y)) - self.alt_label.setText(str(self.flight_wpt.alt)) + self.alt_label.setText(str(int(self.flight_wpt.alt.feet))) self.name_label.setText(str(self.flight_wpt.name)) self.desc_label.setText(str(self.flight_wpt.description)) self.setTitle(self.flight_wpt.name) diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py index 4aa3683c..61fa8cc9 100644 --- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py +++ b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py @@ -49,7 +49,7 @@ class QFlightWaypointList(QTableView): self.model.setItem(row, 0, QWaypointItem(waypoint, row)) - altitude = meter_to_feet(waypoint.alt) + altitude = int(waypoint.alt.feet) altitude_type = "AGL" if waypoint.alt_type == "RADIO" else "MSL" altitude_item = QStandardItem(f"{altitude} ft {altitude_type}") altitude_item.setEditable(False)