Hadlock

Untitled

Sep 24th, 2025
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 12.31 KB | Gaming | 0 0
  1. // flight_model.rs
  2. use crate::aircraft::AircraftConfig;
  3. use crate::consts::PHYSICS_DT;
  4.  
  5. #[derive(Clone)]
  6. pub struct FlightModel {
  7.     // Airplane position in flight model coordinate system
  8.     // Note: airplane_x = North direction, airplane_y = East direction
  9.     // This differs from standard ENU where X=East, Y=North
  10.     pub airplane_x: f64,  // North position (feet)
  11.     pub airplane_y: f64,  // East position (feet)
  12.     pub airplane_z: f64,  // Altitude (feet)
  13.  
  14.     // Angles
  15.     pub side_tilt: f64,      // sideTiltRadians in banks.c
  16.     pub forward_tilt: f64,   // forwardTiltRadians in banks.c
  17.     pub compass: f64,        // compassRadians in banks.c
  18.  
  19.     // Flight parameters
  20.     pub speed: f64,         // target speed (throttle setting)
  21.     pub speed_feet: f64,    // current speed in feet/sec    // User inputs
  22.     pub left_right: f64,    // for turning
  23.     pub up_down: f64,       // for pitch
  24.  
  25.     // Autopilot system
  26.     pub autopilot_enabled: bool,
  27.     pub target_altitude: f64,
  28.     pub target_heading: f64,
  29.     // new state for the PD controller
  30.     pub autopilot_prev_hdg_error: f64,
  31.     pub autopilot_prev_alt_error: f64,
  32.     pub autopilot_filtered_hdg_deriv: f64,  // Filtered derivative term to reduce noise
  33.  
  34.     // Waypoint navigation
  35.     pub waypoint_enabled: bool,
  36.     pub waypoints: Vec<crate::config::Waypoint>,
  37.     pub current_waypoint_index: usize,
  38.     pub waypoint_target_heading: f64,  // The actual bearing to waypoint (for HUD display)    // HUD display options
  39.     pub show_coordinates: bool,  // Toggle coordinate display with X key
  40.     pub show_scene_labels: bool, // Toggle scene origin labels with M key
  41.  
  42.     // Global coordinate system (set by event loop during recentering)
  43.     pub current_lat: f64,
  44.     pub current_lon: f64,
  45.  
  46.     // Reference coordinates for ENU conversion (set by event loop)
  47.     pub ref_lat: f64,
  48.     pub ref_lon: f64,
  49.  
  50.     engine_count: u32,
  51.     power_hp: f64,
  52.     mass_slugs: f64,
  53.     cd0: f64,
  54.     cl_max: f64,
  55.     aspect_ratio: f64,
  56.     critical_aoa_rad: f64,
  57.     stall_pitch_down_rad: f64,
  58.     stall_speed_fps: f64,
  59.     thrust_lbf: f64,
  60.  
  61.     // Rotation matrix (camera transform)
  62.     pub r11: f64, pub r12: f64, pub r13: f64,
  63.     pub r21: f64, pub r22: f64, pub r23: f64,
  64.     pub r31: f64, pub r32: f64, pub r33: f64,
  65.  
  66.     // Additional physics variables from banks.c
  67.     d: f64,
  68.     f: f64,
  69.     p: f64,
  70.     t: f64,
  71.     v: f64,
  72.     w: f64,
  73.     m: f64,
  74.     e: f64,
  75.     i: f64,
  76.     h: f64,
  77.     x: f64,
  78.  
  79.     gravity_accel: f64,
  80.     s: f64,
  81. }
  82.  
  83. impl FlightModel {
  84.     pub fn new(config: AircraftConfig) -> Self {
  85.         let mut model = Self {
  86.             airplane_x: 0.0,
  87.             airplane_y: 0.0,
  88.             airplane_z: config.initial_altitude_ft,
  89.  
  90.             side_tilt: 0.0,
  91.             forward_tilt: config.initial_forward_tilt_rad,
  92.             compass: 0.0,
  93.  
  94.             speed: 8.0,  // Still fixed throttle steps for now
  95.             speed_feet: config.initial_speed_fps,
  96.  
  97.             left_right: 0.0,
  98.             up_down: 0.0,            // Initialize autopilot system
  99.             autopilot_enabled: false,
  100.             target_altitude: 0.0,
  101.             target_heading: 0.0,
  102.             autopilot_prev_hdg_error: 0.0,
  103.             autopilot_prev_alt_error: 0.0,
  104.             autopilot_filtered_hdg_deriv: 0.0,
  105.             // Initialize waypoint navigation
  106.             waypoint_enabled: false,
  107.             waypoints: Vec::new(),
  108.             current_waypoint_index: 0,
  109.             waypoint_target_heading: 0.0,
  110.  
  111.             // HUD display options
  112.             show_coordinates: true,  // Enabled by default, toggle with X key
  113.             show_scene_labels: true, // Enabled by default, toggle with M key
  114.  
  115.             // Global coordinate system (set by event loop during recentering)
  116.             current_lat: 37.6213,  // Default SFO coordinates
  117.             current_lon: -122.3790,
  118.  
  119.             // Reference coordinates for ENU conversion (set by event loop)
  120.             ref_lat: 37.6213,  // Default SFO coordinates
  121.             ref_lon: -122.3790,
  122.  
  123.             r11: 1.0, r12: 0.0, r13: 0.0,
  124.             r21: 0.0, r22: 1.0, r23: 0.0,
  125.             r31: 0.0, r32: 0.0, r33: 1.0,
  126.  
  127.             d: 0.0,
  128.             f: 0.0,
  129.             p: 0.0,
  130.             t: 0.0,
  131.             v: 0.0,
  132.             w: 0.0,
  133.             m: 0.0,
  134.             e: 0.0,
  135.             i: 0.0,
  136.             h: 0.0,
  137.             x: config.initial_lift_param,
  138.  
  139.             gravity_accel: config.gravity_accel,
  140.             s: config.wing_area_ft2,
  141.  
  142.             mass_slugs: config.mass_lb / 32.174,
  143.             engine_count: config.engine_count,
  144.  
  145.              // Aircraft config
  146.             power_hp: config.power_hp,
  147.             cd0: config.cd0,
  148.             cl_max: config.cl_max,
  149.             aspect_ratio: config.aspect_ratio,
  150.             critical_aoa_rad: config.critical_aoa_rad,
  151.             stall_pitch_down_rad: config.stall_pitch_down_rad,
  152.             stall_speed_fps: config.stall_speed_kts * 1.68781,
  153.             thrust_lbf: config.thrust_lbf,
  154.         };
  155.  
  156.         model.calculate_angles();
  157.         model
  158.     }
  159.  
  160.     // Throttle control - increases target speed (directly impacts acceleration)
  161.     pub fn increase_throttle(&mut self) {
  162.         self.speed += 1.0;
  163.     }
  164.  
  165.     // Throttle control - decreases target speed
  166.     pub fn decrease_throttle(&mut self) {
  167.         self.speed -= 1.0;
  168.         if self.speed < 0.0 {
  169.             self.speed = 0.0; // Prevent negative speed
  170.         }
  171.     }
  172.  
  173.     /// Calculate the new orientation angles and rotation matrix
  174.     pub fn calculate_angles(&mut self) {
  175.         // Trigonometric precomputations
  176.         let cos_fwd = self.forward_tilt.cos();
  177.         let sin_fwd = self.forward_tilt.sin();
  178.         let cos_cmp = self.compass.cos();
  179.         let cos_side = self.side_tilt.cos();
  180.         let sin_side = self.side_tilt.sin();
  181.         let sin_cmp = self.compass.sin();
  182.  
  183.         // Update F (moment arm)
  184.         self.f += PHYSICS_DT * self.p;
  185.  
  186.         // Yaw (compass heading)
  187.         self.compass += cos_side * PHYSICS_DT * self.f / cos_fwd
  188.                       + self.d / cos_fwd * sin_side * PHYSICS_DT;
  189.  
  190.         // Pitch (forward/back tilt)
  191.         self.forward_tilt += self.d * PHYSICS_DT * cos_side
  192.                            - PHYSICS_DT * self.f * sin_side;
  193.         // Optional: crude stall behavior (nose drop)
  194.         if self.speed_feet < self.stall_speed_fps && self.forward_tilt > self.critical_aoa_rad {
  195.             self.forward_tilt = self.stall_pitch_down_rad;
  196.         }
  197.  
  198.         // Roll (sideways tilt)
  199.         self.side_tilt += (sin_side * self.d / cos_fwd * sin_fwd
  200.                          + self.v
  201.                          + sin_fwd / cos_fwd * self.f * cos_side) * PHYSICS_DT;
  202.  
  203.         // Build rotation matrix
  204.         self.r11 = cos_fwd * cos_cmp;
  205.         self.r12 = cos_fwd * sin_cmp;
  206.         self.r13 = -sin_fwd;
  207.  
  208.         self.r21 = cos_cmp * sin_side * sin_fwd - sin_cmp * cos_side;
  209.         self.r22 = cos_side * cos_cmp + sin_side * sin_cmp * sin_fwd;
  210.         self.r23 = sin_side * cos_fwd;
  211.  
  212.         self.r31 = sin_cmp * sin_side + cos_side * sin_fwd * cos_cmp;
  213.         self.r32 = sin_fwd * sin_cmp * cos_side - sin_side * cos_cmp;
  214.         self.r33 = cos_side * cos_fwd;
  215.     }
  216.  
  217.     /// Update physics: momentum, position, forces, and rates
  218.     pub fn update_physics(&mut self) {
  219.         // 1) Momentum
  220.         let local_momentum = self.h * PHYSICS_DT;
  221.         self.m += local_momentum;
  222.  
  223.         // 2) Inertia
  224.         self.i = self.m / self.speed_feet;
  225.  
  226.         // 3) Position update (world → airplane reference)
  227.         self.airplane_x += (self.r11 * self.speed_feet + self.r21 * self.m + self.r31 * self.x) * PHYSICS_DT;
  228.         self.airplane_y += (self.r12 * self.speed_feet + self.i    * self.m + self.r32 * self.x) * PHYSICS_DT;
  229.         self.airplane_z += (-self.r13 * self.speed_feet - self.r23 * self.m - self.r33 * self.x) * PHYSICS_DT;
  230.  
  231.         // 4) Intermediate values
  232.         let local_intermediate = 15.0 * self.f / self.speed_feet;
  233.         self.e = 0.1 + self.x * 4.9 / self.speed_feet;
  234.         self.t = self.x * self.x
  235.                + self.speed_feet * self.speed_feet
  236.                + self.m * self.m;           // now using momentum squared
  237.         let t_temp = self.t * local_intermediate / 32.0
  238.                    - self.i * self.t / 24.0;
  239.  
  240.         // 5) H (for next momentum)
  241.         self.h = self.gravity_accel * self.r23
  242.                + self.v * self.x
  243.                - self.f * self.speed_feet
  244.                + t_temp / self.s;
  245.  
  246.         // 6) Acceleration along fuselage
  247.         // Atmospheric constants
  248.         let rho = 0.0023769; // slugs/ft³ at sea level
  249.         let q = 0.5 * rho * self.speed_feet.powi(2); // dynamic pressure
  250.  
  251.         // Approximate angle of attack from pitch angle (forward_tilt)
  252.         let aoa = self.forward_tilt;
  253.  
  254.         // Clamp CL to critical AoA
  255.         let cl = if aoa.abs() > self.critical_aoa_rad {
  256.             self.cl_max * (1.0 - ((aoa.abs() - self.critical_aoa_rad) / self.critical_aoa_rad).min(1.0))
  257.         } else {
  258.             self.cl_max * aoa / self.critical_aoa_rad
  259.         };
  260.  
  261.         // Drag = q * S * (cd0 + cl² / (π * AR))
  262.         let induced_drag = cl.powi(2) / (std::f64::consts::PI * self.aspect_ratio);
  263.         // Reduce drag coefficient to make it more realistic - small planes have less drag
  264.         let drag_coefficient = self.cd0 + induced_drag * 0.5; // Apply 50% factor to induced drag
  265.         let drag_force = q * self.s * drag_coefficient;
  266.  
  267.         // Use the configured thrust directly instead of calculating from power
  268.         // Scale with throttle (range 0-10)
  269.         let throttle_ratio = (self.speed / 10.0).min(1.0).max(0.0);
  270.  
  271.         // Use direct thrust with throttle control
  272.         let thrust_force = self.thrust_lbf * throttle_ratio * self.engine_count as f64;
  273.  
  274.         // We can also calculate additional thrust from power for more realistic engine modeling
  275.         // Power = Force * Velocity, so Force = Power / Velocity
  276.         let power_thrust = if self.speed_feet > 20.0 {  // Only apply at reasonable speeds
  277.             self.power_hp * 550.0 * throttle_ratio / self.speed_feet
  278.         } else {
  279.             0.0 // Avoid division by small numbers
  280.         };
  281.  
  282.         // Use the greater of the two thrust values - at low speed use configured thrust,
  283.         // at higher speeds might transition to power-based thrust
  284.         let thrust_force = thrust_force.max(power_thrust);
  285.  
  286.         // Gravity force in body X (forward) direction
  287.         let gravity_force = -self.mass_slugs * self.gravity_accel * self.forward_tilt.sin();
  288.  
  289.         // Net force = thrust - drag + gravity component
  290.         let net_force = thrust_force - drag_force + gravity_force;
  291.  
  292.         // F = ma ⇒ a = F / m
  293.         let accel = net_force / self.mass_slugs;
  294.  
  295.         // 7) Speed update
  296.         self.speed_feet += accel * PHYSICS_DT;
  297.         if self.speed_feet < 0.1 {
  298.             self.speed_feet = 0.1;
  299.         }
  300.  
  301.         // 8) Next‐step states
  302.         let a = 2.63 / self.speed_feet * self.d;
  303.         let m_momentum = self.m;  // ← accumulate momentum from step 1
  304.         self.x += (self.d * self.speed_feet
  305.                    - self.t / self.s * (0.19 * self.e + a * 0.64 + self.up_down / 1e3)
  306.                    - m_momentum * self.v          // now matches banks.c’s M * v
  307.                    + self.gravity_accel * self.r33) * PHYSICS_DT;
  308.  
  309.         self.w = self.d;
  310.         self.d += self.t * (0.45 - 14.0 / self.speed_feet * self.x - a * 130.0 - self.up_down * 0.14)
  311.                    * PHYSICS_DT / 125e2
  312.                + self.f * PHYSICS_DT * self.v;
  313.  
  314.         let d_param = self.v / self.speed_feet * 15.0;
  315.  
  316.         // 9) Turn rate P
  317.         self.p = (self.t * (47.0 * self.i
  318.                     - local_intermediate * 52.0
  319.                     + self.e * 94.0 * d_param
  320.                     - t_temp * 0.38
  321.                     + self.left_right * 0.21 * self.e) / 1e2
  322.                + self.w * 179.0 * self.v) / 2312.0;
  323.  
  324.         // 10) Sideslip v
  325.         self.v -= (self.w * self.f
  326.                    - self.t * (0.63 * local_intermediate
  327.                               - self.i * 0.086
  328.                               + local_intermediate * self.e * 19.0
  329.                               - d_param * 25.0
  330.                               - 0.11 * self.left_right) / 107e2) * PHYSICS_DT;
  331.     }
  332.  
  333. }
Advertisement
Add Comment
Please, Sign In to add comment