radar2.nas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. # Radar2 and RWR routines.
  2. # Alexis Bory (xiii)
  3. # Every 1 second (Edited - Alex Barrett 171011):
  4. # [1] Generates a sweep scan pattern and when sweep direction changes, scans
  5. # /AI/models for (aircrafts), (carriers), multiplayers. Creates a list of
  6. # these targets, whenever they are in radar overall range and are valid.
  7. # [2] RWR (Radar Warning Receiver) signals are then computed. RWR is included
  8. # within the radar stuff to avoid redundancy.
  9. # [3] At each loop the targets list is scanned and each target bearing is checked
  10. # against the radar beam heading. If the target is within the radar beam, its
  11. # display properties are updated. Two different displays are possible:
  12. # B-scan like and PPI like.
  13. # The target distance is then scored so the radar system can autotrack the
  14. # nearest target.
  15. # Every 0.1 seconde:
  16. # [4] Computes HUD marker position and closure rate for the nearest target.
  17. var ElapsedSec = props.globals.getNode("sim/time/elapsed-sec");
  18. var DisplayRdr = props.globals.getNode("instrumentation/radar/display-rdr");
  19. var AzField = props.globals.getNode("instrumentation/radar/az-field");
  20. var RangeSelected = props.globals.getNode("instrumentation/radar/range-selected");
  21. var RadarStandby = props.globals.getNode("instrumentation/radar/radar-standby");
  22. var RadarStandbyMP = props.globals.getNode("sim/multiplay/generic/int[6]");
  23. var SwpMarker = props.globals.getNode("instrumentation/radar2/sweep-marker-norm", 1);
  24. var SwpDisplayWidth = props.globals.getNode("instrumentation/radar2/sweep-width-m");
  25. var RngDisplayWidth = props.globals.getNode("instrumentation/radar2/range-width-m");
  26. var PpiDisplayRadius = props.globals.getNode("instrumentation/radar2/radius-ppi-display-m");
  27. var HudEyeDist = props.globals.getNode("instrumentation/radar2/hud-eye-dist-m");
  28. var HudRadius = props.globals.getNode("instrumentation/radar2/hud-radius-m");
  29. var HudVoffset = props.globals.getNode("instrumentation/radar2/hud-vertical-offset-m", 1);
  30. var HudTgtHDisplay = props.globals.getNode("instrumentation/radar2/hud/target-display", 1);
  31. var HudTgt = props.globals.getNode("instrumentation/radar2/hud/target", 1);
  32. var HudTgtTDev = props.globals.getNode("instrumentation/radar2/hud/target-total-deviation", 1);
  33. var HudTgtTDeg = props.globals.getNode("instrumentation/radar2/hud/target-total-angle", 1);
  34. var HudTgtClosureRate = props.globals.getNode("instrumentation/radar2/hud/closure-rate", 1);
  35. var OurAlt = props.globals.getNode("position/altitude-ft");
  36. var OurHdg = props.globals.getNode("orientation/heading-deg");
  37. var OurRoll = props.globals.getNode("orientation/roll-deg");
  38. var OurPitch = props.globals.getNode("orientation/pitch-deg");
  39. var EcmOn = props.globals.getNode("instrumentation/ecm/on-off", 1);
  40. var EcmAlert1 = props.globals.getNode("instrumentation/ecm/alert-type1", 1);
  41. var EcmAlert2 = props.globals.getNode("instrumentation/ecm/alert-type2", 1);
  42. var az_fld = AzField.getValue();
  43. var l_az_fld = 0;
  44. var r_az_fld = 0;
  45. var swp_marker = nil; # Scan azimuth deviation, normalized (-1 --> 1).
  46. var swp_deg = nil; # Scan azimuth deviation, in degree.
  47. var swp_deg_last = 0; # Used to get sweep direction.
  48. var swp_spd = 3.5;
  49. var swp_dir = nil; # Sweep direction, 0 to left, 1 to right.
  50. var swp_dir_last = 0;
  51. var swp_diplay_width = SwpDisplayWidth.getValue(); # Length of the max azimuth range on the screen.
  52. # used for the B-scan display and sweep markers.
  53. var rng_diplay_width = SwpDisplayWidth.getValue(); # Length of the max range vertical width on the
  54. # screen. used for the B-scan display.
  55. var ppi_diplay_radius = PpiDisplayRadius.getValue(); # Length of the radial size
  56. # of the PPI like display.
  57. var hud_eye_dist = HudEyeDist.getValue(); # Distance eye <-> HUD plane.
  58. var hud_radius = HudRadius.getValue(); # Used to clamp the nearest target marker.
  59. var hud_voffset = 0; # Used to verticaly offset the clamp border.
  60. var range_radar2 = 0;
  61. var my_radarcorr = 0;
  62. var wcs_mode = "rws"; #FIXME should handled as properties choice, not harcoded.
  63. var tmp_nearest_rng = nil;
  64. var tmp_nearest_u = nil;
  65. var nearest_rng = 0;
  66. var nearest_u = nil;
  67. var our_true_heading = 0;
  68. var our_alt = 0;
  69. var Mp = props.globals.getNode("ai/models");
  70. var tgts_list = [];
  71. var cnt = 0; # Counter used for the scan sweep pattern
  72. var cnt_hud = 0; # Counter used for the HUD update
  73. # ECM warnings.
  74. var ecm_alert1 = 0;
  75. var ecm_alert2 = 0;
  76. var ecm_alert1_last = 0;
  77. var ecm_alert2_last = 0;
  78. var u_ecm_signal = 0;
  79. var u_ecm_signal_norm = 0;
  80. var u_radar_standby = 0;
  81. var u_ecm_type_num = 0;
  82. init = func() {
  83. var our_ac_name = getprop("sim/aircraft");
  84. radardist.init();
  85. my_radarcorr = radardist.my_maxrange( our_ac_name ); # Kilometers
  86. var h = HudVoffset.getValue();
  87. if (h != nil) { hud_voffset = h }
  88. settimer(rdr_loop, 0.5);
  89. }
  90. # from debug.nas for use in 1.9.1
  91. var isnan = func {
  92. call(math.sin, arg, var err = []);
  93. return !!size(err);
  94. }
  95. # Main loop ###############
  96. var rdr_loop = func() {
  97. var display_rdr = DisplayRdr.getBoolValue();
  98. if ( display_rdr ) {
  99. az_scan();
  100. } elsif ( size(tgts_list) > 0 ) {
  101. foreach( u; tgts_list ) {
  102. u.set_display(0);
  103. }
  104. }
  105. if (cnt_hud == 0.1) {
  106. var nada = RadarStandby.getValue();
  107. if ( RadarStandbyMP != nil ) {
  108. RadarStandbyMP.setIntValue(nada); # Tell over MP if our radar is scaning or is in stanby.
  109. };
  110. hud_nearest_tgt();
  111. cnt_hud = 0;
  112. } else {
  113. cnt_hud += 1.0;
  114. }
  115. settimer(rdr_loop, 1.0);
  116. }
  117. var az_scan = func() {
  118. # Antena az scan.
  119. var fld_frac = az_fld / 120;
  120. var fswp_spd = swp_spd / fld_frac;
  121. swp_marker = math.sin(cnt * fswp_spd) * fld_frac;
  122. SwpMarker.setValue(swp_marker);
  123. swp_deg = az_fld / 2 * swp_marker;
  124. swp_dir = swp_deg < swp_deg_last ? 0 : 1;
  125. if ( az_fld == nil ) { az_fld = 74 }
  126. l_az_fld = - az_fld / 2;
  127. r_az_fld = az_fld / 2;
  128. var fading_speed = 0.015;
  129. our_true_heading = OurHdg.getValue();
  130. our_alt = OurAlt.getValue();
  131. if (swp_dir != swp_dir_last) {
  132. # Antena scan direction change. Max every 2 seconds. Reads the whole MP_list.
  133. # TODO: Transient move for the sweep marker when changing az scan field.
  134. az_fld = AzField.getValue();
  135. range_radar2 = RangeSelected.getValue();
  136. if ( range_radar2 == 0 ) { range_radar2 = 0.00000001 }
  137. # Reset nearest_range score
  138. nearest_u = tmp_nearest_u;
  139. nearest_rng = tmp_nearest_rng;
  140. tmp_nearest_rng = nil;
  141. tmp_nearest_u = nil;
  142. tgts_list = [];
  143. var raw_list = Mp.getChildren();
  144. foreach( var c; raw_list ) {
  145. # FIXME: At that time a multiplayer node may have been deleted while still
  146. # existing as a displayable target in the radar targets nodes.
  147. var type = c.getName();
  148. if (!c.getNode("valid", 1).getValue()) {
  149. continue;
  150. }
  151. var HaveRadarNode = c.getNode("radar");
  152. if (type == "multiplayer" or type == "tanker" and HaveRadarNode != nil) {
  153. var u = Target.new(c);
  154. u_ecm_signal = 0;
  155. u_ecm_signal_norm = 0;
  156. u_radar_standby = 0;
  157. u_ecm_type_num = 0;
  158. if ( u.Range != nil) {
  159. var u_rng = u.get_range();
  160. if (u_rng < range_radar2 ) {
  161. u.get_deviation(our_true_heading);
  162. if ( u.deviation > l_az_fld and u.deviation < r_az_fld ) {
  163. append(tgts_list, u);
  164. } else {
  165. u.set_display(0);
  166. }
  167. } else {
  168. u.set_display(0);
  169. }
  170. ecm_on = EcmOn.getBoolValue();
  171. # Test if target has a radar. Compute if we are illuminated. This propery used by ECM
  172. # over MP, should be standardized, like "ai/models/multiplayer[0]/radar/radar-standby".
  173. if ( ecm_on) {
  174. rwr(u); # TODO: override display when alert.
  175. }
  176. }
  177. }
  178. }
  179. # Summarize ECM alerts.
  180. if ( ecm_alert1 == 0 and ecm_alert1_last == 0 ) { EcmAlert1.setBoolValue(0) }
  181. if ( ecm_alert2 == 0 and ecm_alert1_last == 0 ) { EcmAlert2.setBoolValue(0) }
  182. ecm_alert1_last = ecm_alert1; # And avoid alert blinking at each loop.
  183. ecm_alert2_last = ecm_alert2;
  184. ecm_alert1 = 0;
  185. ecm_alert2 = 0;
  186. }
  187. foreach( u; tgts_list ) {
  188. var u_display = 0;
  189. var u_fading = u.get_fading() - fading_speed;
  190. if ( u_fading < 0 ) { u_fading = 0 }
  191. if (( swp_dir and swp_deg_last < u.deviation and u.deviation <= swp_deg )
  192. or ( ! swp_dir and swp_deg <= u.deviation and u.deviation < swp_deg_last )) {
  193. u.get_bearing();
  194. u.get_heading();
  195. var horizon = u.get_horizon( our_alt );
  196. var u_rng = u.get_range();
  197. if ( u_rng < horizon and radardist.radis(u.string, my_radarcorr)) {
  198. # Compute mp position in our B-scan like display. (Bearing/horizontal + Range/Vertical).
  199. u.set_relative_bearing( swp_diplay_width / az_fld * u.deviation );
  200. var factor_range_radar = rng_diplay_width / range_radar2; # Length of the distance range on the B-scan screen.
  201. u.set_ddd_draw_range_nm( factor_range_radar * u_rng );
  202. u_fading = 1;
  203. u_display = 1;
  204. # Compute mp position in our PPI like display.
  205. factor_range_radar = ppi_diplay_radius / range_radar2; # Length of the radius range on the PPI like screen.
  206. u.set_tid_draw_range_nm( factor_range_radar * u_rng );
  207. # Compute first digit of mp altitude rounded to nearest thousand. (labels).
  208. u.set_rounded_alt( rounding1000( u.get_altitude() ) / 1000 );
  209. # Compute closure rate in Kts.
  210. u.get_closure_rate();
  211. # Check if u = nearest echo.
  212. if ( tmp_nearest_rng == nil or u_rng < tmp_nearest_rng) {
  213. tmp_nearest_u = u;
  214. tmp_nearest_rng = u_rng;
  215. }
  216. }
  217. u.set_display(u_display);
  218. }
  219. u.set_fading(u_fading);
  220. }
  221. swp_deg_last = swp_deg;
  222. swp_dir_last = swp_dir;
  223. cnt += 1.0;
  224. }
  225. var hud_nearest_tgt = func() {
  226. # Computes nearest_u position in the HUD
  227. if ( nearest_u != nil ) {
  228. if ( wcs_mode == "tws-auto" and nearest_u.get_display() and nearest_u.deviation > l_az_fld and nearest_u.deviation < r_az_fld ) {
  229. var u_target = nearest_u.type ~ "[" ~ nearest_u.index ~ "]";
  230. var our_pitch = OurPitch.getValue();
  231. var u_dev_rad = (90 - nearest_u.get_deviation(our_true_heading)) * D2R;
  232. var u_elev_rad = (90 - nearest_u.get_total_elevation(our_pitch)) * D2R;
  233. # Deviation length on the HUD (at level flight), 0.6686m = distance eye <-> virtual HUD screen.
  234. var h_dev = 0.6686 / ( math.sin(u_dev_rad) / math.cos(u_dev_rad) );
  235. var v_dev = 0.6686 / ( math.sin(u_elev_rad) / math.cos(u_elev_rad) );
  236. # Angle between HUD center/top <-> HUD center/target position.
  237. # -90° left, 0° up, 90° right, +/- 180° down.
  238. var dev_deg = math.atan2( h_dev, v_dev ) * R2D;
  239. # Correction with own a/c roll.
  240. var combined_dev_deg = dev_deg - OurRoll.getValue();
  241. # Lenght HUD center <-> target pos on the HUD:
  242. var combined_dev_length = math.sqrt((h_dev*h_dev)+(v_dev*v_dev));
  243. # Clamp so the target follow the HUD limits.
  244. if ( hud_voffset == 0 ) {
  245. if ( combined_dev_length > hud_radius ) {
  246. combined_dev_length = hud_radius;
  247. Clamp_Blinker.blink();
  248. } else {
  249. Clamp_Blinker.cont();
  250. }
  251. } else {
  252. var norm_combined_dev_rad = (math.abs(combined_dev_deg) - 90) * D2R;
  253. var o_hud_radius = hud_radius - (math.sin(norm_combined_dev_rad) * hud_voffset);
  254. if ( combined_dev_length > o_hud_radius ) {
  255. combined_dev_length = o_hud_radius;
  256. Clamp_Blinker.blink();
  257. } else {
  258. Clamp_Blinker.cont();
  259. }
  260. }
  261. # Clamp closure rate from -200 to +1,000 Kts.
  262. var cr = nearest_u.ClosureRate.getValue();
  263. if (cr < -200) { cr = 200 } elsif (cr > 1000) { cr = 1000 }
  264. HudTgtClosureRate.setValue(cr);
  265. HudTgtTDeg.setValue(combined_dev_deg);
  266. HudTgtTDev.setValue(combined_dev_length);
  267. HudTgtHDisplay.setBoolValue(1);
  268. HudTgt.setValue(u_target);
  269. return;
  270. }
  271. }
  272. HudTgtClosureRate.setValue(0);
  273. HudTgtTDeg.setValue(0);
  274. HudTgtTDev.setValue(0);
  275. HudTgtHDisplay.setBoolValue(0);
  276. }
  277. # HUD clamped target blinker
  278. Clamp_Blinker = aircraft.light.new("instrumentation/radar2/hud/target-clamped-blinker", [0.1, 0.1]);
  279. setprop("instrumentation/radar2/hud/target-clamped-blinker/enabled", 1);
  280. # ECM: Radar Warning Receiver
  281. rwr = func(u) {
  282. var u_name = radardist.get_aircraft_name(u.string);
  283. var u_maxrange = radardist.my_maxrange(u_name); # in kilometer, 0 is unknown or no radar.
  284. var horizon = u.get_horizon( our_alt );
  285. var u_rng = u.get_range();
  286. var u_carrier = u.check_carrier_type();
  287. if ( u.get_rdr_standby() == 0 and u_maxrange > 0 and u_rng < horizon ) {
  288. # Test if we are in its radar field (hard coded 74°) or if we have a MPcarrier.
  289. # Compute the signal strength.
  290. var our_deviation_deg = deviation_normdeg(u.get_heading(), u.get_reciprocal_bearing());
  291. if ( our_deviation_deg < 0 ) { our_deviation_deg *= -1 }
  292. if ( our_deviation_deg < 37 or u_carrier == 1 ) {
  293. u_ecm_signal = (((-our_deviation_deg/20)+2.5)*(!u_carrier )) + (-u_rng/20) + 2.6 + (u_carrier*1.8);
  294. u_ecm_type_num = radardist.get_ecm_type_num(u_name);
  295. }
  296. } else {
  297. u_ecm_signal = 0;
  298. }
  299. # Compute global threat situation for undiscriminant warning lights
  300. # and discrete (normalized) definition of threat strength.
  301. if ( u_ecm_signal > 1 and u_ecm_signal < 3 ) {
  302. EcmAlert1.setBoolValue(1);
  303. ecm_alert1 = 1;
  304. u_ecm_signal_norm = 2;
  305. } elsif ( u_ecm_signal >= 3 ) {
  306. EcmAlert2.setBoolValue(1);
  307. ecm_alert2 = 1;
  308. u_ecm_signal_norm = 1;
  309. }
  310. u.EcmSignal.setValue(u_ecm_signal);
  311. u.EcmSignalNorm.setIntValue(u_ecm_signal_norm);
  312. u.EcmTypeNum.setIntValue(u_ecm_type_num);
  313. }
  314. # Utilities.
  315. var deviation_normdeg = func(our_heading, target_bearing) {
  316. var dev_norm = our_heading - target_bearing;
  317. while (dev_norm < -180) dev_norm += 360;
  318. while (dev_norm > 180) dev_norm -= 360;
  319. return(dev_norm);
  320. }
  321. var rounding1000 = func(n) {
  322. var a = int( n / 1000 );
  323. var l = ( a + 0.5 ) * 1000;
  324. n = (n >= l) ? ((a + 1) * 1000) : (a * 1000);
  325. return( n );
  326. }
  327. # Controls
  328. var radar_range_control = func(n) {
  329. # FIXME: Radar props should provide their own ranges instead of being hardcoded.
  330. # 5, 10, 20, 50, 100, 200
  331. var range_radar = RangeSelected.getValue();
  332. if ( n == 1 ) {
  333. if ( range_radar == 5 ) {
  334. range_radar = 10;
  335. } elsif ( range_radar == 10 ) {
  336. range_radar = 20;
  337. } elsif ( range_radar == 20 ) {
  338. range_radar = 50;
  339. } elsif ( range_radar == 50 ) {
  340. range_radar = 100;
  341. } else {
  342. range_radar = 150;
  343. }
  344. } else {
  345. if ( range_radar == 150 ) {
  346. range_radar = 100;
  347. } elsif ( range_radar == 100 ) {
  348. range_radar = 50;
  349. } elsif ( range_radar == 50 ) {
  350. range_radar = 20;
  351. } elsif ( range_radar == 20 ) {
  352. range_radar = 10;
  353. } else {
  354. range_radar = 5;
  355. }
  356. }
  357. RangeSelected.setValue(range_radar);
  358. }
  359. radar_mode_sel = func(mode) {
  360. # FIXME: Modes props should provide their own data instead of being hardcoded.
  361. foreach (var n; props.globals.getNode("instrumentation/radar/mode").getChildren()) {
  362. n.setBoolValue(n.getName() == mode);
  363. wcs_mode = mode;
  364. }
  365. if ( wcs_mode == "rws" ) {
  366. AzField.setValue(120);
  367. swp_diplay_width = 0.0844;
  368. } else {
  369. AzField.setValue(60);
  370. swp_diplay_width = 0.0422;
  371. }
  372. }
  373. radar_mode_toggle = func() {
  374. # FIXME: Modes props should provide their own data instead of being hardcoded.
  375. # Toggles between the available modes.
  376. foreach (var n; props.globals.getNode("instrumentation/radar/mode").getChildren()) {
  377. if ( n.getBoolValue() ) { wcs_mode = n.getName() }
  378. }
  379. if ( wcs_mode == "rws" ) {
  380. setprop("instrumentation/radar/mode/rws", 0);
  381. setprop("instrumentation/radar/mode/tws-auto", 1);
  382. wcs_mode = "tws-auto";
  383. AzField.setValue(60);
  384. swp_diplay_width = 0.0422;
  385. } elsif ( wcs_mode == "tws-auto" ) {
  386. setprop("instrumentation/radar/mode/tws-auto", 0);
  387. setprop("instrumentation/radar/mode/rws", 1);
  388. wcs_mode = "pulse-srch";
  389. AzField.setValue(120);
  390. swp_diplay_width = 0.0844;
  391. }
  392. }
  393. setlistener("sim/signals/fdm-initialized", init);
  394. # Target class
  395. var Target = {
  396. new : func (c) {
  397. var obj = { parents : [Target]};
  398. obj.RdrProp = c.getNode("radar");
  399. obj.Heading = c.getNode("orientation/true-heading-deg");
  400. obj.Alt = c.getNode("position/altitude-ft");
  401. obj.AcType = c.getNode("sim/model/ac-type");
  402. obj.type = c.getName();
  403. obj.index = c.getIndex();
  404. obj.string = "ai/models/" ~ obj.type ~ "[" ~ obj.index ~ "]";
  405. obj.shortstring = obj.type ~ "[" ~ obj.index ~ "]";
  406. obj.InstrTgts = props.globals.getNode("instrumentation/radar2/targets", 1);
  407. obj.TgtsFiles = obj.InstrTgts.getNode(obj.shortstring, 1);
  408. obj.Range = obj.RdrProp.getNode("range-nm");
  409. obj.Bearing = obj.RdrProp.getNode("bearing-deg");
  410. obj.Elevation = obj.RdrProp.getNode("elevation-deg");
  411. obj.BBearing = obj.TgtsFiles.getNode("bearing-deg", 1);
  412. obj.BHeading = obj.TgtsFiles.getNode("true-heading-deg", 1);
  413. obj.RangeScore = obj.TgtsFiles.getNode("range-score", 1);
  414. obj.RelBearing = obj.TgtsFiles.getNode("ddd-relative-bearing", 1);
  415. obj.Carrier = obj.TgtsFiles.getNode("carrier", 1);
  416. obj.EcmSignal = obj.TgtsFiles.getNode("ecm-signal", 1);
  417. obj.EcmSignalNorm = obj.TgtsFiles.getNode("ecm-signal-norm", 1);
  418. obj.EcmTypeNum = obj.TgtsFiles.getNode("ecm_type_num", 1);
  419. obj.Display = obj.TgtsFiles.getNode("display", 1);
  420. obj.Fading = obj.TgtsFiles.getNode("ddd-echo-fading", 1);
  421. obj.DddDrawRangeNm = obj.TgtsFiles.getNode("ddd-draw-range-nm", 1);
  422. obj.TidDrawRangeNm = obj.TgtsFiles.getNode("tid-draw-range-nm", 1);
  423. obj.RoundedAlt = obj.TgtsFiles.getNode("rounded-alt-ft", 1);
  424. obj.TimeLast = obj.TgtsFiles.getNode("closure-last-time", 1);
  425. obj.RangeLast = obj.TgtsFiles.getNode("closure-last-range-nm", 1);
  426. obj.ClosureRate = obj.TgtsFiles.getNode("closure-rate-kts", 1);
  427. obj.TimeLast.setValue(ElapsedSec.getValue());
  428. if ( obj.Range != nil) {
  429. obj.RangeLast.setValue(obj.Range.getValue());
  430. } else {
  431. obj.RangeLast.setValue(0);
  432. }
  433. obj.RadarStandby = c.getNode("sim/multiplay/generic/int[6]");
  434. obj.deviation = nil;
  435. return obj;
  436. },
  437. get_heading : func {
  438. var n = me.Heading.getValue();
  439. me.BHeading.setValue(n);
  440. return n;
  441. },
  442. get_bearing : func {
  443. var n = me.Bearing.getValue();
  444. me.BBearing.setValue(n);
  445. return n;
  446. },
  447. set_relative_bearing : func(n) {
  448. me.RelBearing.setValue(n);
  449. },
  450. get_reciprocal_bearing : func {
  451. return geo.normdeg(me.get_bearing() + 180);
  452. },
  453. get_deviation : func(true_heading_ref) {
  454. me.deviation = - deviation_normdeg(true_heading_ref, me.get_bearing());
  455. return me.deviation;
  456. },
  457. get_altitude : func {
  458. return me.Alt.getValue();
  459. },
  460. get_total_elevation : func(own_pitch) {
  461. me.deviation = - deviation_normdeg(own_pitch, me.Elevation.getValue());
  462. return me.deviation;
  463. },
  464. get_range : func {
  465. return me.Range.getValue();
  466. },
  467. get_horizon : func(own_alt) {
  468. var tgt_alt = me.get_altitude();
  469. if ( tgt_alt != nil ) {
  470. if ( own_alt < 0 ) { own_alt = 0.001 }
  471. if ( isnan(tgt_alt)) {
  472. return(0);
  473. }
  474. if ( tgt_alt < 0 ) { tgt_alt = 0.001 }
  475. return radardist.radar_horizon( own_alt, tgt_alt );
  476. } else {
  477. return(0);
  478. }
  479. },
  480. check_carrier_type : func {
  481. var type = "none";
  482. var carrier = 0;
  483. if ( me.AcType != nil ) { type = me.AcType.getValue() }
  484. if ( type == "MP-Nimitz" or type == "MP-Eisenhower" or type == "MP-Vinson") { carrier = 1 }
  485. # This works only after the mp-carrier model has been loaded. Before that it is seen like a common aircraft.
  486. me.Carrier.setBoolValue(carrier);
  487. return carrier;
  488. },
  489. get_rdr_standby : func {
  490. var s = 0;
  491. if ( me.RadarStandby != nil ) {
  492. s = me.RadarStandby.getValue();
  493. if (s == nil) { s = 0 } elsif (s != 1) { s = 0 }
  494. }
  495. return s;
  496. },
  497. get_display : func() {
  498. return me.Display.getValue();
  499. },
  500. set_display : func(n) {
  501. me.Display.setBoolValue(n);
  502. },
  503. get_fading : func() {
  504. var fading = me.Fading.getValue();
  505. if ( fading == nil ) { fading = 0 }
  506. return fading;
  507. },
  508. set_fading : func(n) {
  509. me.Fading.setValue(n);
  510. },
  511. set_ddd_draw_range_nm : func(n) {
  512. me.DddDrawRangeNm.setValue(n);
  513. },
  514. set_hud_draw_horiz_dev : func(n) {
  515. me.HudDrawHorizDev.setValue(n);
  516. },
  517. set_tid_draw_range_nm : func(n) {
  518. me.TidDrawRangeNm.setValue(n);
  519. },
  520. set_rounded_alt : func(n) {
  521. me.RoundedAlt.setValue(n);
  522. },
  523. get_closure_rate : func() {
  524. var dt = ElapsedSec.getValue() - me.TimeLast.getValue();
  525. var rng = me.Range.getValue();
  526. var t_distance = me.RangeLast.getValue() - rng;
  527. var cr = t_distance/dt*3600;
  528. me.ClosureRate.setValue(cr);
  529. me.RangeLast.setValue(rng);
  530. return(cr);
  531. },
  532. list : [],
  533. };