diff --git a/gen/flights/flightplan.py b/gen/flights/flightplan.py index bbc954d8..a8cccf9a 100644 --- a/gen/flights/flightplan.py +++ b/gen/flights/flightplan.py @@ -7,6 +7,7 @@ generating the waypoints for the mission. """ from __future__ import annotations +import math from datetime import timedelta from functools import cached_property import logging @@ -93,29 +94,31 @@ class PackageWaypointTiming: if group_ground_speed is None: return None - ingress = package.time_over_target - TravelTime.between_points( - package.waypoints.ingress, - package.target.position, - group_ground_speed - ) + # Round each waypoint TOT since DCS doesn't support sub-second timing + # and it's not interesting to the user. + ingress = timedelta(seconds=math.floor( + (package.time_over_target - TravelTime.between_points( + package.waypoints.ingress, + package.target.position, + group_ground_speed)).total_seconds())) - join = ingress - TravelTime.between_points( - package.waypoints.join, - package.waypoints.ingress, - group_ground_speed - ) + join = timedelta(seconds=math.floor( + (ingress - TravelTime.between_points( + package.waypoints.join, + package.waypoints.ingress, + group_ground_speed)).total_seconds())) - egress = package.time_over_target + TravelTime.between_points( - package.target.position, - package.waypoints.egress, - group_ground_speed - ) + egress = timedelta(seconds=math.floor( + (package.time_over_target + TravelTime.between_points( + package.target.position, + package.waypoints.egress, + group_ground_speed)).total_seconds())) - split = egress + TravelTime.between_points( - package.waypoints.egress, - package.waypoints.split, - group_ground_speed - ) + split = timedelta(seconds=math.floor( + (egress + TravelTime.between_points( + package.waypoints.egress, + package.waypoints.split, + group_ground_speed)).total_seconds())) return cls(package, join, ingress, egress, split) diff --git a/gen/flights/traveltime.py b/gen/flights/traveltime.py index 644e9851..ee9a6c7e 100644 --- a/gen/flights/traveltime.py +++ b/gen/flights/traveltime.py @@ -98,7 +98,17 @@ class TotEstimator: takeoff_time = self.takeoff_time_for_flight(flight) startup_time = self.estimate_startup(flight) ground_ops_time = self.estimate_ground_ops(flight) - return takeoff_time - startup_time - ground_ops_time + start_time = takeoff_time - startup_time - ground_ops_time + # In case FP math has given us some barely below zero time, round to + # zero. + if math.isclose(start_time.total_seconds(), 0): + return timedelta() + # Trim microseconds. DCS doesn't handle sub-second resolution for tasks, + # and they're not interesting from a mission planning perspective so we + # don't want them in the UI. + # + # Round down so *barely* above zero start times are just zero. + return timedelta(seconds=math.floor(start_time.total_seconds())) def takeoff_time_for_flight(self, flight: Flight) -> timedelta: travel_time = self.travel_time_to_rendezvous_or_target(flight) @@ -122,10 +132,17 @@ class TotEstimator: return tot - travel_time - self.HOLD_TIME def earliest_tot(self) -> timedelta: - return max(( + earliest_tot = max(( self.earliest_tot_for_flight(f) for f in self.package.flights )) + self.HOLD_TIME + # Trim microseconds. DCS doesn't handle sub-second resolution for tasks, + # and they're not interesting from a mission planning perspective so we + # don't want them in the UI. + # + # Round up so we don't get negative start times. + return timedelta(seconds=math.ceil(earliest_tot.total_seconds())) + def earliest_tot_for_flight(self, flight: Flight) -> timedelta: """Estimate fastest time from mission start to the target position.