]> git.mxchange.org Git - flightgear.git/blob - src/Main/bfi.cxx
Moved fov and win_ration from FGOptions to FGViewer so we can control these
[flightgear.git] / src / Main / bfi.cxx
1 // bfi.cxx - Big Friendly Interface implementation
2 //
3 // Written by David Megginson, started February, 2000.
4 //
5 // Copyright (C) 2000  David Megginson - david@megginson.com
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #if defined( FG_HAVE_NATIVE_SGI_COMPILERS )
29 #  include <iostream.h>
30 #else
31 #  include <iostream>
32 #endif
33
34 #include <simgear/constants.h>
35 #include <simgear/debug/logstream.hxx>
36 #include <simgear/ephemeris/ephemeris.hxx>
37 #include <simgear/math/sg_types.hxx>
38 #include <simgear/misc/props.hxx>
39 #include <simgear/timing/sg_time.hxx>
40
41 #include <Aircraft/aircraft.hxx>
42 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
43 #include <Controls/controls.hxx>
44 #include <Autopilot/newauto.hxx>
45 #include <Scenery/scenery.hxx>
46 #include <Time/light.hxx>
47 #include <Time/event.hxx>
48 #include <Time/sunpos.hxx>
49 #include <Time/tmp.hxx>
50 #include <Cockpit/radiostack.hxx>
51 #include <Cockpit/panel.hxx>
52 #ifndef FG_OLD_WEATHER
53 #  include <WeatherCM/FGLocalWeatherDatabase.h>
54 #else
55 #  include <Weather/weather.hxx>
56 #endif
57
58 #include "globals.hxx"
59 #include "save.hxx"
60 #include "fg_init.hxx"
61 #include <simgear/misc/props.hxx>
62
63 FG_USING_NAMESPACE(std);
64
65
66 #include "bfi.hxx"
67
68
69 \f
70 ////////////////////////////////////////////////////////////////////////
71 // Static variables.
72 ////////////////////////////////////////////////////////////////////////
73
74                                 // Yech -- not thread-safe, etc. etc.
75 static bool _needReinit = false;
76 static string _temp;
77
78 static inline void needReinit ()
79 {
80   _needReinit = true;
81 }
82
83
84 /**
85  * Reinitialize FGFS to use the new BFI settings.
86  */
87 static inline void
88 reinit ()
89 {
90                                 // Save the state of everything
91                                 // that's going to get clobbered
92                                 // when we reinit the subsystems.
93
94   cout << "BFI: start reinit\n";
95
96                                 // TODO: add more AP stuff
97   double elevator = FGBFI::getElevator();
98   double aileron = FGBFI::getAileron();
99   double rudder = FGBFI::getRudder();
100   double throttle = FGBFI::getThrottle();
101   double elevator_trim = FGBFI::getElevatorTrim();
102   double flaps = FGBFI::getFlaps();
103   double brake = FGBFI::getBrakes();
104   bool apHeadingLock = FGBFI::getAPHeadingLock();
105   double apHeadingMag = FGBFI::getAPHeadingMag();
106   bool apAltitudeLock = FGBFI::getAPAltitudeLock();
107   double apAltitude = FGBFI::getAPAltitude();
108   const string &targetAirport = FGBFI::getTargetAirport();
109   bool gpsLock = FGBFI::getGPSLock();
110   // double gpsLatitude = FGBFI::getGPSTargetLatitude();
111   // double gpsLongitude = FGBFI::getGPSTargetLongitude();
112
113   FGBFI::setTargetAirport("");
114   cout << "Target airport is " << globals->get_options()->get_airport_id() << endl;
115
116   fgReInitSubsystems();
117
118                                 // FIXME: this is wrong.
119                                 // All of these are scheduled events,
120                                 // and it should be possible to force
121                                 // them all to run once.
122   fgUpdateSunPos();
123   fgUpdateMoonPos();
124   cur_light_params.Update();
125   fgUpdateLocalTime();
126   fgUpdateWeatherDatabase();
127   fgRadioSearch();
128
129                                 // Restore all of the old states.
130   FGBFI::setElevator(elevator);
131   FGBFI::setAileron(aileron);
132   FGBFI::setRudder(rudder);
133   FGBFI::setThrottle(throttle);
134   FGBFI::setElevatorTrim(elevator_trim);
135   FGBFI::setFlaps(flaps);
136   FGBFI::setBrakes(brake);
137   FGBFI::setAPHeadingLock(apHeadingLock);
138   FGBFI::setAPHeadingMag(apHeadingMag);
139   FGBFI::setAPAltitudeLock(apAltitudeLock);
140   FGBFI::setAPAltitude(apAltitude);
141   FGBFI::setTargetAirport(targetAirport);
142   FGBFI::setGPSLock(gpsLock);
143
144   _needReinit = false;
145
146   cout << "BFI: end reinit\n";
147 }
148
149
150 \f
151 ////////////////////////////////////////////////////////////////////////
152 // Local functions
153 ////////////////////////////////////////////////////////////////////////
154
155
156 /**
157  * Initialize the BFI by binding its functions to properties.
158  *
159  * TODO: perhaps these should migrate into the individual modules
160  * (i.e. they should register themselves).
161  */
162 void
163 FGBFI::init ()
164 {
165   FG_LOG(FG_GENERAL, FG_INFO, "Starting BFI init");
166                                 // Simulation
167   current_properties.tieInt("/sim/flight-model",
168                             getFlightModel, setFlightModel);
169   current_properties.tieString("/sim/aircraft",
170                                getAircraft, setAircraft);
171   current_properties.tieString("/sim/aircraft-dir",
172                                getAircraftDir, setAircraftDir);
173   // TODO: timeGMT
174   current_properties.tieString("/sim/time/gmt-string",
175                                getGMTString, 0);
176   current_properties.tieBool("/sim/hud/visibility",
177                              getHUDVisible, setHUDVisible);
178   current_properties.tieBool("/sim/panel/visibility",
179                              getPanelVisible, setPanelVisible);
180   current_properties.tieInt("/sim/panel/x-offset",
181                             getPanelXOffset, setPanelXOffset);
182   current_properties.tieInt("/sim/panel/y-offset",
183                             getPanelYOffset, setPanelYOffset);
184
185                                 // Position
186   current_properties.tieString("/position/airport-id",
187                                 getTargetAirport, setTargetAirport);
188   current_properties.tieDouble("/position/latitude",
189                                 getLatitude, setLatitude);
190   current_properties.tieDouble("/position/longitude",
191                                getLongitude, setLongitude);
192   current_properties.tieDouble("/position/altitude",
193                                // getAltitude, setAltitude);
194                                getAltitude, setAltitude, false);
195   current_properties.tieDouble("/position/altitude-agl",
196                                getAGL, 0);
197
198                                 // Orientation
199   current_properties.tieDouble("/orientation/heading",
200                                getHeading, setHeading);
201   current_properties.tieDouble("/orientation/heading-magnetic",
202                                getHeadingMag, 0);
203   current_properties.tieDouble("/orientation/pitch",
204                                getPitch, setPitch);
205   current_properties.tieDouble("/orientation/roll",
206                                getRoll, setRoll);
207
208                                 // Engine
209   current_properties.tieDouble("/engines/engine0/rpm",
210                                getRPM, 0);
211   current_properties.tieDouble("/engines/engine0/egt",
212                                getEGT, 0);
213   current_properties.tieDouble("/engines/engine0/cht",
214                                getCHT, 0);
215   current_properties.tieDouble("/engines/engine0/mp",
216                                getMP, 0);
217
218                                 // Velocities
219   current_properties.tieDouble("/velocities/airspeed",
220                                getAirspeed, setAirspeed);
221   current_properties.tieDouble("/velocities/side-slip",
222                                getSideSlip, 0);
223   current_properties.tieDouble("/velocities/vertical-speed",
224                                getVerticalSpeed, 0);
225   current_properties.tieDouble("/velocities/speed-north",
226                                getSpeedNorth, 0);
227   current_properties.tieDouble("/velocities/speed-east",
228                                getSpeedEast, 0);
229   current_properties.tieDouble("/velocities/speed-down",
230                                getSpeedDown, 0);
231
232                                 // Controls
233   current_properties.tieDouble("/controls/throttle",
234                                getThrottle, setThrottle);
235   current_properties.tieDouble("/controls/mixture",
236                                getMixture, setMixture);
237   current_properties.tieDouble("/controls/propellor-pitch",
238                                getPropAdvance, setPropAdvance);
239   current_properties.tieDouble("/controls/flaps",
240                                getFlaps, setFlaps);
241   current_properties.tieDouble("/controls/aileron",
242                                getAileron, setAileron);
243   current_properties.tieDouble("/controls/rudder",
244                                getRudder, setRudder);
245   current_properties.tieDouble("/controls/elevator",
246                                getElevator, setElevator);
247   current_properties.tieDouble("/controls/elevator-trim",
248                                getElevatorTrim, setElevatorTrim);
249   current_properties.tieDouble("/controls/brakes/all",
250                                getBrakes, setBrakes);
251   current_properties.tieDouble("/controls/brakes/left",
252                                getLeftBrake, setLeftBrake);
253   current_properties.tieDouble("/controls/brakes/right",
254                                getRightBrake, setRightBrake);
255   current_properties.tieDouble("/controls/brakes/center",
256                                getRightBrake, setCenterBrake);
257
258                                 // Autopilot
259   current_properties.tieBool("/autopilot/locks/altitude",
260                              getAPAltitudeLock, setAPAltitudeLock);
261   current_properties.tieDouble("/autopilot/settings/altitude",
262                                getAPAltitude, setAPAltitude);
263   current_properties.tieBool("/autopilot/locks/heading",
264                              getAPHeadingLock, setAPHeadingLock);
265   current_properties.tieDouble("/autopilot/settings/heading",
266                                getAPHeading, setAPHeading);
267   current_properties.tieDouble("/autopilot/settings/heading-magnetic",
268                                getAPHeadingMag, setAPHeadingMag);
269   current_properties.tieBool("/autopilot/locks/nav1",
270                              getAPNAV1Lock, setAPNAV1Lock);
271
272                                 // Radio navigation
273   current_properties.tieDouble("/radios/nav1/frequencies/selected",
274                                getNAV1Freq, setNAV1Freq);
275   current_properties.tieDouble("/radios/nav1/frequencies/standby",
276                                getNAV1AltFreq, setNAV1AltFreq);
277   current_properties.tieDouble("/radios/nav1/radials/actual",
278                                getNAV1Radial, 0);
279   current_properties.tieDouble("/radios/nav1/radials/selected",
280                                getNAV1SelRadial, setNAV1SelRadial);
281   current_properties.tieDouble("/radios/nav1/dme/distance",
282                                getNAV1DistDME, 0);
283   current_properties.tieBool("/radios/nav1/to-flag",
284                              getNAV1TO, 0);
285   current_properties.tieBool("/radios/nav1/from-flag",
286                              getNAV1FROM, 0);
287   current_properties.tieBool("/radios/nav1/in-range",
288                              getNAV1InRange, 0);
289   current_properties.tieBool("/radios/nav1/dme/in-range",
290                              getNAV1DMEInRange, 0);
291                                
292   current_properties.tieDouble("/radios/nav2/frequencies/selected",
293                                getNAV2Freq, setNAV2Freq);
294   current_properties.tieDouble("/radios/nav2/frequencies/standby",
295                                getNAV2AltFreq, setNAV2AltFreq);
296   current_properties.tieDouble("/radios/nav2/radials/actual",
297                                getNAV2Radial, 0);
298   current_properties.tieDouble("/radios/nav2/radials/selected",
299                                getNAV2SelRadial, setNAV2SelRadial);
300   current_properties.tieDouble("/radios/nav2/dme/distance",
301                                getNAV2DistDME, 0);
302   current_properties.tieBool("/radios/nav2/to-flag",
303                              getNAV2TO, 0);
304   current_properties.tieBool("/radios/nav2/from-flag",
305                              getNAV2FROM, 0);
306   current_properties.tieBool("/radios/nav2/in-range",
307                              getNAV2InRange, 0);
308   current_properties.tieBool("/radios/nav2/dme/in-range",
309                              getNAV2DMEInRange, 0);
310
311   current_properties.tieDouble("/radios/adf/frequencies/selected",
312                                getADFFreq, setADFFreq);
313   current_properties.tieDouble("/radios/adf/frequencies/standby",
314                                getADFAltFreq, setADFAltFreq);
315   current_properties.tieDouble("/radios/adf/rotation",
316                                getADFRotation, setADFRotation);
317
318   current_properties.tieDouble("/environment/visibility",
319                                getVisibility, setVisibility);
320
321   _needReinit = false;
322
323   FG_LOG(FG_GENERAL, FG_INFO, "Ending BFI init");
324 }
325
326
327 /**
328  * Reinitialize FGFS if required.
329  *
330  * Some changes (especially those in aircraft position) require that
331  * FGFS be reinitialized afterwards.  Rather than reinitialize after
332  * every change, the setter methods simply set a flag so that there
333  * can be a single reinit at the end of the frame.
334  */
335 void
336 FGBFI::update ()
337 {
338   if (_needReinit) {
339     reinit();
340   }
341 }
342
343
344 \f
345 ////////////////////////////////////////////////////////////////////////
346 // Simulation.
347 ////////////////////////////////////////////////////////////////////////
348
349
350 /**
351  * Return the flight model as an integer.
352  *
353  * TODO: use a string instead.
354  */
355 int
356 FGBFI::getFlightModel ()
357 {
358   return globals->get_options()->get_flight_model();
359 }
360
361
362 /**
363  * Return the current aircraft as a string.
364  */
365 const string &
366 FGBFI::getAircraft ()
367 {
368   _temp = globals->get_options()->get_aircraft();
369   return _temp;
370 }
371
372
373 /**
374  * Return the current aircraft directory (UIUC) as a string.
375  */
376 const string &
377 FGBFI::getAircraftDir ()
378 {
379   _temp = aircraft_dir;
380   return _temp;
381 }
382
383
384 /**
385  * Set the flight model as an integer.
386  *
387  * TODO: use a string instead.
388  */
389 void
390 FGBFI::setFlightModel (int model)
391 {
392   if (getFlightModel() != model) {
393     globals->get_options()->set_flight_model(model);
394     needReinit();
395   }
396 }
397
398
399 /**
400  * Set the current aircraft.
401  */
402 void
403 FGBFI::setAircraft (const string &aircraft)
404 {
405   if (getAircraft() != aircraft) {
406     globals->get_options()->set_aircraft(aircraft);
407     needReinit();
408   }
409 }
410
411
412 /**
413  * Set the current aircraft directory (UIUC).
414  */
415 void
416 FGBFI::setAircraftDir (const string &dir)
417 {
418   if (getAircraftDir() != dir) {
419     aircraft_dir = dir;
420     needReinit();
421   }
422 }
423
424
425 /**
426  * Return the current Zulu time.
427  */
428 time_t
429 FGBFI::getTimeGMT ()
430 {
431   return globals->get_time_params()->get_cur_time();
432 }
433
434
435 /**
436  * Set the current Zulu time.
437  */
438 void
439 FGBFI::setTimeGMT (time_t time)
440 {
441   if (getTimeGMT() != time) {
442                                 // FIXME: need to update lighting
443                                 // and solar system
444     globals->get_options()->set_time_offset(time);
445     globals->get_options()->set_time_offset_type(FGOptions::FG_TIME_GMT_ABSOLUTE);
446     globals->get_time_params()->update( cur_fdm_state->get_Longitude(),
447                                         cur_fdm_state->get_Latitude(),
448                                         globals->get_warp() );
449     needReinit();
450   }
451 }
452
453
454 /**
455  * Return the GMT as a string.
456  */
457 const string &
458 FGBFI::getGMTString ()
459 {
460   static string out;            // FIXME: not thread-safe
461   char buf[16];
462   struct tm * t = globals->get_time_params()->getGmt();
463   sprintf(buf, " %.2d:%.2d:%.2d",
464           t->tm_hour, t->tm_min, t->tm_sec);
465   out = buf;
466   return out;
467 }
468
469
470 /**
471  * Return true if the HUD is visible.
472  */
473 bool
474 FGBFI::getHUDVisible ()
475 {
476   return globals->get_options()->get_hud_status();
477 }
478
479
480 /**
481  * Ensure that the HUD is visible or hidden.
482  */
483 void
484 FGBFI::setHUDVisible (bool visible)
485 {
486   globals->get_options()->set_hud_status(visible);
487 }
488
489
490 /**
491  * Return true if the 2D panel is visible.
492  */
493 bool
494 FGBFI::getPanelVisible ()
495 {
496   return globals->get_options()->get_panel_status();
497 }
498
499
500 /**
501  * Ensure that the 2D panel is visible or hidden.
502  */
503 void
504 FGBFI::setPanelVisible (bool visible)
505 {
506   if (globals->get_options()->get_panel_status() != visible) {
507     globals->get_options()->toggle_panel();
508   }
509 }
510
511
512 /**
513  * Get the panel's current x-shift.
514  */
515 int
516 FGBFI::getPanelXOffset ()
517 {
518   if (current_panel != 0)
519     return current_panel->getXOffset();
520   else
521     return 0;
522 }
523
524
525 /**
526  * Set the panel's current x-shift.
527  */
528 void
529 FGBFI::setPanelXOffset (int offset)
530 {
531   if (current_panel != 0)
532     current_panel->setXOffset(offset);
533 }
534
535
536 /**
537  * Get the panel's current y-shift.
538  */
539 int
540 FGBFI::getPanelYOffset ()
541 {
542   if (current_panel != 0)
543     return current_panel->getYOffset();
544   else
545     return 0;
546 }
547
548
549 /**
550  * Set the panel's current y-shift.
551  */
552 void
553 FGBFI::setPanelYOffset (int offset)
554 {
555   if (current_panel != 0)
556     current_panel->setYOffset(offset);
557 }
558
559
560
561
562 \f
563 ////////////////////////////////////////////////////////////////////////
564 // Position
565 ////////////////////////////////////////////////////////////////////////
566
567
568 /**
569  * Return the current latitude in degrees (negative for south).
570  */
571 double
572 FGBFI::getLatitude ()
573 {
574   return current_aircraft.fdm_state->get_Latitude() * RAD_TO_DEG;
575 }
576
577
578 /**
579  * Set the current latitude in degrees (negative for south).
580  */
581 void
582 FGBFI::setLatitude (double latitude)
583 {
584   current_aircraft.fdm_state->set_Latitude(latitude * DEG_TO_RAD);
585 }
586
587
588 /**
589  * Return the current longitude in degrees (negative for west).
590  */
591 double
592 FGBFI::getLongitude ()
593 {
594   return current_aircraft.fdm_state->get_Longitude() * RAD_TO_DEG;
595 }
596
597
598 /**
599  * Set the current longitude in degrees (negative for west).
600  */
601 void
602 FGBFI::setLongitude (double longitude)
603 {
604   current_aircraft.fdm_state->set_Longitude(longitude * DEG_TO_RAD);
605 }
606
607
608 /**
609  * Return the current altitude in feet.
610  */
611 double
612 FGBFI::getAltitude ()
613 {
614   return current_aircraft.fdm_state->get_Altitude();
615 }
616
617
618
619 /**
620  * Return the current altitude in above the terrain.
621  */
622 double
623 FGBFI::getAGL ()
624 {
625   return current_aircraft.fdm_state->get_Altitude()
626          - (scenery.cur_elev * METER_TO_FEET);
627 }
628
629
630 /**
631  * Set the current altitude in feet.
632  */
633 void
634 FGBFI::setAltitude (double altitude)
635 {
636   current_aircraft.fdm_state->set_Altitude(altitude);
637 }
638
639
640 \f
641 ////////////////////////////////////////////////////////////////////////
642 // Attitude
643 ////////////////////////////////////////////////////////////////////////
644
645
646 /**
647  * Return the current heading in degrees.
648  */
649 double
650 FGBFI::getHeading ()
651 {
652   return current_aircraft.fdm_state->get_Psi() * RAD_TO_DEG;
653 }
654
655
656 /**
657  * Return the current heading in degrees.
658  */
659 double
660 FGBFI::getHeadingMag ()
661 {
662   return current_aircraft.fdm_state->get_Psi() * RAD_TO_DEG - getMagVar();
663 }
664
665
666 /**
667  * Set the current heading in degrees.
668  */
669 void
670 FGBFI::setHeading (double heading)
671 {
672   FGInterface * fdm = current_aircraft.fdm_state;
673   fdm->set_Euler_Angles(fdm->get_Phi(), fdm->get_Theta(),
674                         heading * DEG_TO_RAD);
675 }
676
677
678 /**
679  * Return the current pitch in degrees.
680  */
681 double
682 FGBFI::getPitch ()
683 {
684   return current_aircraft.fdm_state->get_Theta() * RAD_TO_DEG;
685 }
686
687
688 /**
689  * Set the current pitch in degrees.
690  */
691 void
692 FGBFI::setPitch (double pitch)
693 {
694   FGInterface * fdm = current_aircraft.fdm_state;
695   fdm->set_Euler_Angles(fdm->get_Phi(), pitch * DEG_TO_RAD, fdm->get_Psi());
696 }
697
698
699 /**
700  * Return the current roll in degrees.
701  */
702 double
703 FGBFI::getRoll ()
704 {
705   return current_aircraft.fdm_state->get_Phi() * RAD_TO_DEG;
706 }
707
708
709 /**
710  * Set the current roll in degrees.
711  */
712 void
713 FGBFI::setRoll (double roll)
714 {
715   FGInterface * fdm = current_aircraft.fdm_state;
716   fdm->set_Euler_Angles(roll * DEG_TO_RAD, fdm->get_Theta(), fdm->get_Psi());
717 }
718
719
720 /**
721  * Return the current engine0 rpm
722  */
723 double
724 FGBFI::getRPM ()
725 {
726   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
727       return current_aircraft.fdm_state->get_engine(0)->get_RPM();
728   } else {
729       return 0.0;
730   }
731 }
732
733
734 /**
735  * Set the current engine0 rpm
736  */
737 void
738 FGBFI::setRPM (double rpm)
739 {
740     if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
741         if (getRPM() != rpm) {
742             current_aircraft.fdm_state->get_engine(0)->set_RPM( rpm );
743         }
744     }
745 }
746
747
748 /**
749  * Return the current engine0 EGT.
750  */
751 double
752 FGBFI::getEGT ()
753 {
754   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
755       return current_aircraft.fdm_state->get_engine(0)->get_EGT();
756   } else {
757       return 0.0;
758   }
759 }
760
761
762 /**
763  * Return the current engine0 CHT.
764  */
765 double
766 FGBFI::getCHT ()
767 {
768   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
769       return current_aircraft.fdm_state->get_engine(0)->get_CHT();
770   } else {
771       return 0.0;
772   }
773 }
774
775
776 /**
777  * Return the current engine0 CHT.
778  */
779 double
780 FGBFI::getMP ()
781 {
782   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
783       return current_aircraft.fdm_state->get_engine(0)->get_Manifold_Pressure();
784   } else {
785       return 0.0;
786   }
787 }
788
789
790 \f
791 ////////////////////////////////////////////////////////////////////////
792 // Velocities
793 ////////////////////////////////////////////////////////////////////////
794
795
796 /**
797  * Return the current airspeed in knots.
798  */
799 double
800 FGBFI::getAirspeed ()
801 {
802                                 // FIXME: should we add speed-up?
803   return current_aircraft.fdm_state->get_V_calibrated_kts();
804 }
805
806
807 /**
808  * Set the calibrated airspeed in knots.
809  */
810 void
811 FGBFI::setAirspeed (double speed)
812 {
813   current_aircraft.fdm_state->set_V_calibrated_kts(speed);
814 }
815
816
817 /**
818  * Return the current sideslip (FIXME: units unknown).
819  */
820 double
821 FGBFI::getSideSlip ()
822 {
823   return current_aircraft.fdm_state->get_Beta();
824 }
825
826
827 /**
828  * Return the current climb rate in feet/minute
829  */
830 double
831 FGBFI::getVerticalSpeed ()
832 {
833                                 // What about meters?
834   return current_aircraft.fdm_state->get_Climb_Rate() * 60.0;
835 }
836
837
838 /**
839  * Get the current north velocity (units??).
840  */
841 double
842 FGBFI::getSpeedNorth ()
843 {
844   return current_aircraft.fdm_state->get_V_north();
845 }
846
847
848 // /**
849 //  * Set the current north velocity (units??).
850 //  */
851 // void
852 // FGBFI::setSpeedNorth (double speed)
853 // {
854 //   FGInterface * fdm = current_aircraft.fdm_state;
855 // //   fdm->set_Velocities_Local(speed, fdm->get_V_east(), fdm->get_V_down());
856 // }
857
858
859 /**
860  * Get the current east velocity (units??).
861  */
862 double
863 FGBFI::getSpeedEast ()
864 {
865   return current_aircraft.fdm_state->get_V_east();
866 }
867
868
869 // /**
870 //  * Set the current east velocity (units??).
871 //  */
872 // void
873 // FGBFI::setSpeedEast (double speed)
874 // {
875 //   FGInterface * fdm = current_aircraft.fdm_state;
876 // //   fdm->set_Velocities_Local(fdm->get_V_north(), speed, fdm->get_V_down());
877 // }
878
879
880 /**
881  * Get the current down velocity (units??).
882  */
883 double
884 FGBFI::getSpeedDown ()
885 {
886   return current_aircraft.fdm_state->get_V_down();
887 }
888
889
890 // /**
891 //  * Set the current down velocity (units??).
892 //  */
893 // void
894 // FGBFI::setSpeedDown (double speed)
895 // {
896 //   FGInterface * fdm = current_aircraft.fdm_state;
897 // //   fdm->set_Velocities_Local(fdm->get_V_north(), fdm->get_V_east(), speed);
898 // }
899
900
901 \f
902 ////////////////////////////////////////////////////////////////////////
903 // Controls
904 ////////////////////////////////////////////////////////////////////////
905
906
907 /**
908  * Get the throttle setting, from 0.0 (none) to 1.0 (full).
909  */
910 double
911 FGBFI::getThrottle ()
912 {
913                                 // FIXME: add engine selector
914   return controls.get_throttle(0);
915 }
916
917
918 /**
919  * Set the throttle, from 0.0 (none) to 1.0 (full).
920  */
921 void
922 FGBFI::setThrottle (double throttle)
923 {
924                                 // FIXME: allow engine selection
925   controls.set_throttle(0, throttle);
926 }
927
928
929 /**
930  * Get the fuel mixture setting, from 0.0 (none) to 1.0 (full).
931  */
932 double
933 FGBFI::getMixture ()
934 {
935                                 // FIXME: add engine selector
936   return controls.get_mixture(0);
937 }
938
939
940 /**
941  * Set the fuel mixture, from 0.0 (none) to 1.0 (full).
942  */
943 void
944 FGBFI::setMixture (double mixture)
945 {
946                                 // FIXME: allow engine selection
947   controls.set_mixture(0, mixture);
948 }
949
950
951 /**
952  * Get the propellor pitch setting, from 0.0 (none) to 1.0 (full).
953  */
954 double
955 FGBFI::getPropAdvance ()
956 {
957                                 // FIXME: add engine selector
958   return controls.get_prop_advance(0);
959 }
960
961
962 /**
963  * Set the propellor pitch, from 0.0 (none) to 1.0 (full).
964  */
965 void
966 FGBFI::setPropAdvance (double pitch)
967 {
968                                 // FIXME: allow engine selection
969   controls.set_prop_advance(0, pitch);
970 }
971
972
973 /**
974  * Get the flaps setting, from 0.0 (none) to 1.0 (full).
975  */
976 double
977 FGBFI::getFlaps ()
978 {
979   return controls.get_flaps();
980 }
981
982
983 /**
984  * Set the flaps, from 0.0 (none) to 1.0 (full).
985  */
986 void
987 FGBFI::setFlaps (double flaps)
988 {
989                                 // FIXME: clamp?
990   controls.set_flaps(flaps);
991 }
992
993
994 /**
995  * Get the aileron, from -1.0 (left) to 1.0 (right).
996  */
997 double
998 FGBFI::getAileron ()
999 {
1000   return controls.get_aileron();
1001 }
1002
1003
1004 /**
1005  * Set the aileron, from -1.0 (left) to 1.0 (right).
1006  */
1007 void
1008 FGBFI::setAileron (double aileron)
1009 {
1010                                 // FIXME: clamp?
1011   controls.set_aileron(aileron);
1012 }
1013
1014
1015 /**
1016  * Get the rudder setting, from -1.0 (left) to 1.0 (right).
1017  */
1018 double
1019 FGBFI::getRudder ()
1020 {
1021   return controls.get_rudder();
1022 }
1023
1024
1025 /**
1026  * Set the rudder, from -1.0 (left) to 1.0 (right).
1027  */
1028 void
1029 FGBFI::setRudder (double rudder)
1030 {
1031                                 // FIXME: clamp?
1032   controls.set_rudder(rudder);
1033 }
1034
1035
1036 /**
1037  * Get the elevator setting, from -1.0 (down) to 1.0 (up).
1038  */
1039 double
1040 FGBFI::getElevator ()
1041 {
1042   return controls.get_elevator();
1043 }
1044
1045
1046 /**
1047  * Set the elevator, from -1.0 (down) to 1.0 (up).
1048  */
1049 void
1050 FGBFI::setElevator (double elevator)
1051 {
1052                                 // FIXME: clamp?
1053   controls.set_elevator(elevator);
1054 }
1055
1056
1057 /**
1058  * Get the elevator trim, from -1.0 (down) to 1.0 (up).
1059  */
1060 double
1061 FGBFI::getElevatorTrim ()
1062 {
1063   return controls.get_elevator_trim();
1064 }
1065
1066
1067 /**
1068  * Set the elevator trim, from -1.0 (down) to 1.0 (up).
1069  */
1070 void
1071 FGBFI::setElevatorTrim (double trim)
1072 {
1073                                 // FIXME: clamp?
1074   controls.set_elevator_trim(trim);
1075 }
1076
1077
1078 /**
1079  * Get the highest brake setting, from 0.0 (none) to 1.0 (full).
1080  */
1081 double
1082 FGBFI::getBrakes ()
1083 {
1084   double b1 = getCenterBrake();
1085   double b2 = getLeftBrake();
1086   double b3 = getRightBrake();
1087   return (b1 > b2 ? (b1 > b3 ? b1 : b3) : (b2 > b3 ? b2 : b3));
1088 }
1089
1090
1091 /**
1092  * Set all brakes, from 0.0 (none) to 1.0 (full).
1093  */
1094 void
1095 FGBFI::setBrakes (double brake)
1096 {
1097   setCenterBrake(brake);
1098   setLeftBrake(brake);
1099   setRightBrake(brake);
1100 }
1101
1102
1103 /**
1104  * Get the center brake, from 0.0 (none) to 1.0 (full).
1105  */
1106 double
1107 FGBFI::getCenterBrake ()
1108 {
1109   return controls.get_brake(2);
1110 }
1111
1112
1113 /**
1114  * Set the center brake, from 0.0 (none) to 1.0 (full).
1115  */
1116 void
1117 FGBFI::setCenterBrake (double brake)
1118 {
1119   controls.set_brake(2, brake);
1120 }
1121
1122
1123 /**
1124  * Get the left brake, from 0.0 (none) to 1.0 (full).
1125  */
1126 double
1127 FGBFI::getLeftBrake ()
1128 {
1129   return controls.get_brake(0);
1130 }
1131
1132
1133 /**
1134  * Set the left brake, from 0.0 (none) to 1.0 (full).
1135  */
1136 void
1137 FGBFI::setLeftBrake (double brake)
1138 {
1139   controls.set_brake(0, brake);
1140 }
1141
1142
1143 /**
1144  * Get the right brake, from 0.0 (none) to 1.0 (full).
1145  */
1146 double
1147 FGBFI::getRightBrake ()
1148 {
1149   return controls.get_brake(1);
1150 }
1151
1152
1153 /**
1154  * Set the right brake, from 0.0 (none) to 1.0 (full).
1155  */
1156 void
1157 FGBFI::setRightBrake (double brake)
1158 {
1159   controls.set_brake(1, brake);
1160 }
1161
1162
1163
1164
1165 \f
1166 ////////////////////////////////////////////////////////////////////////
1167 // Autopilot
1168 ////////////////////////////////////////////////////////////////////////
1169
1170
1171 /**
1172  * Get the autopilot altitude lock (true=on).
1173  */
1174 bool
1175 FGBFI::getAPAltitudeLock ()
1176 {
1177     return current_autopilot->get_AltitudeEnabled();
1178 }
1179
1180
1181 /**
1182  * Set the autopilot altitude lock (true=on).
1183  */
1184 void
1185 FGBFI::setAPAltitudeLock (bool lock)
1186 {
1187   current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_LOCK);
1188   current_autopilot->set_AltitudeEnabled(lock);
1189 }
1190
1191
1192 /**
1193  * Get the autopilot target altitude in feet.
1194  */
1195 double
1196 FGBFI::getAPAltitude ()
1197 {
1198   return current_autopilot->get_TargetAltitude() * METER_TO_FEET;
1199 }
1200
1201
1202 /**
1203  * Set the autopilot target altitude in feet.
1204  */
1205 void
1206 FGBFI::setAPAltitude (double altitude)
1207 {
1208     current_autopilot->set_TargetAltitude( altitude );
1209 }
1210
1211
1212 /**
1213  * Get the autopilot heading lock (true=on).
1214  */
1215 bool
1216 FGBFI::getAPHeadingLock ()
1217 {
1218     return
1219       (current_autopilot->get_HeadingEnabled() &&
1220        current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_LOCK);
1221 }
1222
1223
1224 /**
1225  * Set the autopilot heading lock (true=on).
1226  */
1227 void
1228 FGBFI::setAPHeadingLock (bool lock)
1229 {
1230   if (lock) {
1231                                 // We need to do this so that
1232                                 // it's possible to lock onto a
1233                                 // heading other than the current
1234                                 // heading.
1235     double heading = getAPHeadingMag();
1236     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_LOCK);
1237     current_autopilot->set_HeadingEnabled(true);
1238     setAPHeadingMag(heading);
1239   } else if (current_autopilot->get_HeadingMode() ==
1240              FGAutopilot::FG_HEADING_LOCK) {
1241     current_autopilot->set_HeadingEnabled(false);
1242   }
1243 }
1244
1245
1246 /**
1247  * Get the autopilot target heading in degrees.
1248  */
1249 double
1250 FGBFI::getAPHeading ()
1251 {
1252   return current_autopilot->get_TargetHeading();
1253 }
1254
1255
1256 /**
1257  * Set the autopilot target heading in degrees.
1258  */
1259 void
1260 FGBFI::setAPHeading (double heading)
1261 {
1262   current_autopilot->set_TargetHeading( heading );
1263 }
1264
1265
1266 /**
1267  * Get the autopilot target heading in degrees.
1268  */
1269 double
1270 FGBFI::getAPHeadingMag ()
1271 {
1272   return current_autopilot->get_TargetHeading() - getMagVar();
1273 }
1274
1275
1276 /**
1277  * Set the autopilot target heading in degrees.
1278  */
1279 void
1280 FGBFI::setAPHeadingMag (double heading)
1281 {
1282   current_autopilot->set_TargetHeading( heading + getMagVar() );
1283 }
1284
1285
1286 /**
1287  * Return true if the autopilot is locked to NAV1.
1288  */
1289 bool
1290 FGBFI::getAPNAV1Lock ()
1291 {
1292   return
1293     (current_autopilot->get_HeadingEnabled() &&
1294      current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_NAV1);
1295 }
1296
1297
1298 /**
1299  * Set the autopilot NAV1 lock.
1300  */
1301 void
1302 FGBFI::setAPNAV1Lock (bool lock)
1303 {
1304   if (lock) {
1305     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_NAV1);
1306     current_autopilot->set_HeadingEnabled(true);
1307   } else if (current_autopilot->get_HeadingMode() ==
1308              FGAutopilot::FG_HEADING_NAV1) {
1309     current_autopilot->set_HeadingEnabled(false);
1310   }
1311 }
1312
1313
1314 \f
1315 ////////////////////////////////////////////////////////////////////////
1316 // Radio navigation.
1317 ////////////////////////////////////////////////////////////////////////
1318
1319 double
1320 FGBFI::getNAV1Freq ()
1321 {
1322   return current_radiostack->get_nav1_freq();
1323 }
1324
1325 double
1326 FGBFI::getNAV1AltFreq ()
1327 {
1328   return current_radiostack->get_nav1_alt_freq();
1329 }
1330
1331 double
1332 FGBFI::getNAV1Radial ()
1333 {
1334   return current_radiostack->get_nav1_radial();
1335 }
1336
1337 double
1338 FGBFI::getNAV1SelRadial ()
1339 {
1340   return current_radiostack->get_nav1_sel_radial();
1341 }
1342
1343 double
1344 FGBFI::getNAV1DistDME ()
1345 {
1346   return current_radiostack->get_nav1_dme_dist();
1347 }
1348
1349 bool 
1350 FGBFI::getNAV1TO ()
1351 {
1352   if (current_radiostack->get_nav1_inrange()) {
1353     double heading = current_radiostack->get_nav1_heading();
1354     double radial = current_radiostack->get_nav1_radial();
1355     double var = FGBFI::getMagVar();
1356     if (current_radiostack->get_nav1_loc()) {
1357       double offset = fabs(heading - radial);
1358       return (offset<= 8.0 || offset >= 352.0);
1359     } else {
1360       double offset =
1361         fabs(heading - var - radial);
1362       return (offset <= 20.0 || offset >= 340.0);
1363     }
1364   } else {
1365     return false;
1366   }
1367 }
1368
1369 bool
1370 FGBFI::getNAV1FROM ()
1371 {
1372   if (current_radiostack->get_nav1_inrange()) {
1373     double heading = current_radiostack->get_nav1_heading();
1374     double radial = current_radiostack->get_nav1_radial();
1375     double var = FGBFI::getMagVar();
1376     if (current_radiostack->get_nav1_loc()) {
1377       double offset = fabs(heading - radial);
1378       return (offset >= 172.0 && offset<= 188.0);
1379     } else {
1380       double offset =
1381         fabs(heading - var - radial);
1382       return (offset >= 160.0 && offset <= 200.0);
1383     }
1384   } else {
1385     return false;
1386   }
1387 }
1388
1389 bool
1390 FGBFI::getNAV1InRange ()
1391 {
1392   return current_radiostack->get_nav1_inrange();
1393 }
1394
1395 bool
1396 FGBFI::getNAV1DMEInRange ()
1397 {
1398   return (current_radiostack->get_nav1_inrange() &&
1399           current_radiostack->get_nav1_has_dme());
1400 }
1401
1402 double
1403 FGBFI::getNAV2Freq ()
1404 {
1405   return current_radiostack->get_nav2_freq();
1406 }
1407
1408 double
1409 FGBFI::getNAV2AltFreq ()
1410 {
1411   return current_radiostack->get_nav2_alt_freq();
1412 }
1413
1414 double
1415 FGBFI::getNAV2Radial ()
1416 {
1417   return current_radiostack->get_nav2_radial();
1418 }
1419
1420 double
1421 FGBFI::getNAV2SelRadial ()
1422 {
1423   return current_radiostack->get_nav2_sel_radial();
1424 }
1425
1426 double
1427 FGBFI::getNAV2DistDME ()
1428 {
1429   return current_radiostack->get_nav2_dme_dist();
1430 }
1431
1432 bool 
1433 FGBFI::getNAV2TO ()
1434 {
1435   if (current_radiostack->get_nav2_inrange()) {
1436     double heading = current_radiostack->get_nav2_heading();
1437     double radial = current_radiostack->get_nav2_radial();
1438     double var = FGBFI::getMagVar();
1439     if (current_radiostack->get_nav2_loc()) {
1440       double offset = fabs(heading - radial);
1441       return (offset<= 8.0 || offset >= 352.0);
1442     } else {
1443       double offset =
1444         fabs(heading - var - radial);
1445       return (offset <= 20.0 || offset >= 340.0);
1446     }
1447   } else {
1448     return false;
1449   }
1450 }
1451
1452 bool 
1453 FGBFI::getNAV2FROM ()
1454 {
1455   if (current_radiostack->get_nav2_inrange()) {
1456     double heading = current_radiostack->get_nav2_heading();
1457     double radial = current_radiostack->get_nav2_radial();
1458     double var = FGBFI::getMagVar();
1459     if (current_radiostack->get_nav2_loc()) {
1460       double offset = fabs(heading - radial);
1461       return (offset >= 172.0 && offset<= 188.0);
1462     } else {
1463       double offset =
1464         fabs(heading - var - radial);
1465       return (offset >= 160.0 && offset <= 200.0);
1466     }
1467   } else {
1468     return false;
1469   }
1470 }
1471
1472
1473 bool
1474 FGBFI::getNAV2InRange ()
1475 {
1476   return current_radiostack->get_nav2_inrange();
1477 }
1478
1479 bool
1480 FGBFI::getNAV2DMEInRange ()
1481 {
1482   return (current_radiostack->get_nav2_inrange() &&
1483           current_radiostack->get_nav2_has_dme());
1484 }
1485
1486 double
1487 FGBFI::getADFFreq ()
1488 {
1489   return current_radiostack->get_adf_freq();
1490 }
1491
1492 double
1493 FGBFI::getADFAltFreq ()
1494 {
1495   return current_radiostack->get_adf_alt_freq();
1496 }
1497
1498 double
1499 FGBFI::getADFRotation ()
1500 {
1501   return current_radiostack->get_adf_rotation();
1502 }
1503
1504 void
1505 FGBFI::setNAV1Freq (double freq)
1506 {
1507   current_radiostack->set_nav1_freq(freq);
1508 }
1509
1510 void
1511 FGBFI::setNAV1AltFreq (double freq)
1512 {
1513   current_radiostack->set_nav1_alt_freq(freq);
1514 }
1515
1516 void
1517 FGBFI::setNAV1SelRadial (double radial)
1518 {
1519   current_radiostack->set_nav1_sel_radial(radial);
1520 }
1521
1522 void
1523 FGBFI::setNAV2Freq (double freq)
1524 {
1525   current_radiostack->set_nav2_freq(freq);
1526 }
1527
1528 void
1529 FGBFI::setNAV2AltFreq (double freq)
1530 {
1531   current_radiostack->set_nav2_alt_freq(freq);
1532 }
1533
1534 void
1535 FGBFI::setNAV2SelRadial (double radial)
1536 {
1537   current_radiostack->set_nav2_sel_radial(radial);
1538 }
1539
1540 void
1541 FGBFI::setADFFreq (double freq)
1542 {
1543   current_radiostack->set_adf_freq(freq);
1544 }
1545
1546 void
1547 FGBFI::setADFAltFreq (double freq)
1548 {
1549   current_radiostack->set_adf_alt_freq(freq);
1550 }
1551
1552 void
1553 FGBFI::setADFRotation (double rot)
1554 {
1555   current_radiostack->set_adf_rotation(rot);
1556 }
1557
1558
1559 \f
1560 ////////////////////////////////////////////////////////////////////////
1561 // GPS
1562 ////////////////////////////////////////////////////////////////////////
1563
1564
1565 /**
1566  * Get the autopilot GPS lock (true=on).
1567  */
1568 bool
1569 FGBFI::getGPSLock ()
1570 {
1571   return (current_autopilot->get_HeadingEnabled() &&
1572           (current_autopilot->get_HeadingMode() ==
1573            FGAutopilot::FG_HEADING_WAYPOINT ));
1574 }
1575
1576
1577 /**
1578  * Set the autopilot GPS lock (true=on).
1579  */
1580 void
1581 FGBFI::setGPSLock (bool lock)
1582 {
1583   if (lock) {
1584     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_WAYPOINT);
1585     current_autopilot->set_HeadingEnabled(true);
1586   } else if (current_autopilot->get_HeadingMode() ==
1587              FGAutopilot::FG_HEADING_WAYPOINT) {
1588     current_autopilot->set_HeadingEnabled(false);
1589   }
1590 }
1591
1592
1593 /**
1594  * Get the GPS target airport code.
1595  */
1596 const string &
1597 FGBFI::getTargetAirport ()
1598 {
1599   // FIXME: not thread-safe
1600   static string out;
1601   out = globals->get_options()->get_airport_id();
1602
1603   return out;
1604 }
1605
1606
1607 /**
1608  * Set the GPS target airport code.
1609  */
1610 void
1611 FGBFI::setTargetAirport (const string &airportId)
1612 {
1613   // cout << "setting target airport id = " << airportId << endl;
1614   globals->get_options()->set_airport_id(airportId);
1615 }
1616
1617
1618 /**
1619  * Get the GPS target latitude in degrees (negative for south).
1620  */
1621 double
1622 FGBFI::getGPSTargetLatitude ()
1623 {
1624     return current_autopilot->get_TargetLatitude();
1625 }
1626
1627
1628 /**
1629  * Get the GPS target longitude in degrees (negative for west).
1630  */
1631 double
1632 FGBFI::getGPSTargetLongitude ()
1633 {
1634   return current_autopilot->get_TargetLongitude();
1635 }
1636
1637 #if 0
1638 /**
1639  * Set the GPS target longitude in degrees (negative for west).
1640  */
1641 void
1642 FGBFI::setGPSTargetLongitude (double longitude)
1643 {
1644   current_autopilot->set_TargetLongitude( longitude );
1645 }
1646 #endif
1647
1648
1649 \f
1650 ////////////////////////////////////////////////////////////////////////
1651 // Weather
1652 ////////////////////////////////////////////////////////////////////////
1653
1654
1655 /**
1656  * Get the current visible (units??).
1657  */
1658 double
1659 FGBFI::getVisibility ()
1660 {
1661 #ifndef FG_OLD_WEATHER
1662   return WeatherDatabase->getWeatherVisibility();
1663 #else
1664   return current_weather.get_visibility();
1665 #endif
1666 }
1667
1668
1669 /**
1670  * Set the current visibility (units??).
1671  */
1672 void
1673 FGBFI::setVisibility (double visibility)
1674 {
1675 #ifndef FG_OLD_WEATHER
1676   WeatherDatabase->setWeatherVisibility(visibility);
1677 #else
1678   current_weather.set_visibility(visibility);
1679 #endif
1680 }
1681
1682
1683 \f
1684 ////////////////////////////////////////////////////////////////////////
1685 // Time
1686 ////////////////////////////////////////////////////////////////////////
1687
1688 /**
1689  * Return the magnetic variation
1690  */
1691 double
1692 FGBFI::getMagVar ()
1693 {
1694   return globals->get_mag()->get_magvar() * RAD_TO_DEG;
1695 }
1696
1697
1698 /**
1699  * Return the magnetic variation
1700  */
1701 double
1702 FGBFI::getMagDip ()
1703 {
1704   return globals->get_mag()->get_magdip() * RAD_TO_DEG;
1705 }
1706
1707
1708 // end of bfi.cxx
1709