Differentiate total time and travel time.

There's an ugly special case in flight simulation to handle hold points
because we don't differentiate between the total time between two
waypoints (which can include delays from actions like holding) and
travel time. Split those up and remove the special case.
This commit is contained in:
Dan Albert 2023-08-13 11:16:14 -07:00
parent bf1e559a41
commit 59756ce14c
6 changed files with 21 additions and 19 deletions

View File

@ -214,7 +214,7 @@ class FlightPlan(ABC, Generic[LayoutT]):
) )
for previous_waypoint, waypoint in self.edges(until=destination): for previous_waypoint, waypoint in self.edges(until=destination):
total += self.travel_time_between_waypoints(previous_waypoint, waypoint) total += self.total_time_between_waypoints(previous_waypoint, waypoint)
# Trim microseconds. Our simulation tick rate is 1 second, so anything that # Trim microseconds. Our simulation tick rate is 1 second, so anything that
# takes 100.1 or 100.9 seconds will take 100 seconds. DCS doesn't handle # takes 100.1 or 100.9 seconds will take 100 seconds. DCS doesn't handle
@ -223,6 +223,16 @@ class FlightPlan(ABC, Generic[LayoutT]):
# model. # model.
return timedelta(seconds=math.floor(total.total_seconds())) return timedelta(seconds=math.floor(total.total_seconds()))
def total_time_between_waypoints(
self, a: FlightWaypoint, b: FlightWaypoint
) -> timedelta:
"""Returns the total time spent between a and b.
The total time between waypoints differs from the travel time in that it may
include additional time for actions such as loitering.
"""
return self.travel_time_between_waypoints(a, b)
def travel_time_between_waypoints( def travel_time_between_waypoints(
self, a: FlightWaypoint, b: FlightWaypoint self, a: FlightWaypoint, b: FlightWaypoint
) -> timedelta: ) -> timedelta:

View File

@ -57,17 +57,17 @@ class FormationAttackFlightPlan(FormationFlightPlan, ABC):
@property @property
def join_time(self) -> datetime: def join_time(self) -> datetime:
travel_time = self.travel_time_between_waypoints( travel_time = self.total_time_between_waypoints(
self.layout.join, self.layout.ingress self.layout.join, self.layout.ingress
) )
return self.ingress_time - travel_time return self.ingress_time - travel_time
@property @property
def split_time(self) -> datetime: def split_time(self) -> datetime:
travel_time_ingress = self.travel_time_between_waypoints( travel_time_ingress = self.total_time_between_waypoints(
self.layout.ingress, self.target_area_waypoint self.layout.ingress, self.target_area_waypoint
) )
travel_time_egress = self.travel_time_between_waypoints( travel_time_egress = self.total_time_between_waypoints(
self.target_area_waypoint, self.layout.split self.target_area_waypoint, self.layout.split
) )
minutes_at_target = 0.75 * len(self.layout.targets) minutes_at_target = 0.75 * len(self.layout.targets)
@ -82,7 +82,7 @@ class FormationAttackFlightPlan(FormationFlightPlan, ABC):
@property @property
def ingress_time(self) -> datetime: def ingress_time(self) -> datetime:
tot = self.tot tot = self.tot
travel_time = self.travel_time_between_waypoints( travel_time = self.total_time_between_waypoints(
self.layout.ingress, self.target_area_waypoint self.layout.ingress, self.target_area_waypoint
) )
return tot - travel_time return tot - travel_time

View File

@ -33,10 +33,10 @@ class LoiterFlightPlan(StandardFlightPlan[Any], ABC):
return self.push_time return self.push_time
return None return None
def travel_time_between_waypoints( def total_time_between_waypoints(
self, a: FlightWaypoint, b: FlightWaypoint self, a: FlightWaypoint, b: FlightWaypoint
) -> timedelta: ) -> timedelta:
travel_time = super().travel_time_between_waypoints(a, b) travel_time = super().total_time_between_waypoints(a, b)
if a != self.layout.hold: if a != self.layout.hold:
return travel_time return travel_time
return travel_time + self.hold_duration return travel_time + self.hold_duration

View File

@ -59,10 +59,10 @@ class PackageRefuelingFlightPlan(RefuelingFlightPlan):
"REFUEL", FlightWaypointType.REFUEL, refuel, altitude "REFUEL", FlightWaypointType.REFUEL, refuel, altitude
) )
delay_target_to_split: timedelta = self.travel_time_between_waypoints( delay_target_to_split: timedelta = self.total_time_between_waypoints(
self.target_area_waypoint(), split_waypoint self.target_area_waypoint(), split_waypoint
) )
delay_split_to_refuel: timedelta = self.travel_time_between_waypoints( delay_split_to_refuel: timedelta = self.total_time_between_waypoints(
split_waypoint, refuel_waypoint split_waypoint, refuel_waypoint
) )

View File

@ -55,7 +55,7 @@ class SweepFlightPlan(LoiterFlightPlan):
@property @property
def sweep_start_time(self) -> datetime: def sweep_start_time(self) -> datetime:
travel_time = self.travel_time_between_waypoints( travel_time = self.total_time_between_waypoints(
self.layout.sweep_start, self.layout.sweep_end self.layout.sweep_start, self.layout.sweep_end
) )
return self.sweep_end_time - travel_time return self.sweep_end_time - travel_time

View File

@ -51,17 +51,9 @@ class InFlight(FlightState, ABC):
return index <= self.waypoint_index return index <= self.waypoint_index
def travel_time_between_waypoints(self) -> timedelta: def travel_time_between_waypoints(self) -> timedelta:
travel_time = self.flight.flight_plan.travel_time_between_waypoints( return self.flight.flight_plan.travel_time_between_waypoints(
self.current_waypoint, self.next_waypoint self.current_waypoint, self.next_waypoint
) )
if self.current_waypoint.waypoint_type is FlightWaypointType.LOITER:
# Loiter time is already built into travel_time_between_waypoints. If we're
# at a loiter point but still a regular InFlight (Loiter overrides this
# method) that means we're traveling from the loiter point but no longer
# loitering.
assert self.flight.flight_plan.is_loiter(self.flight.flight_plan)
travel_time -= self.flight.flight_plan.hold_duration
return travel_time
@abstractmethod @abstractmethod
def estimate_position(self) -> Point: def estimate_position(self) -> Point: