]> git.mxchange.org Git - flightgear.git/blob - src/Main/bfi.cxx
src/GUI/gui.cxx:
[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   }
757 }
758
759
760 /**
761  * Return the current engine0 CHT.
762  */
763 double
764 FGBFI::getCHT ()
765 {
766   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
767       return current_aircraft.fdm_state->get_engine(0)->get_CHT();
768   }
769 }
770
771
772 /**
773  * Return the current engine0 CHT.
774  */
775 double
776 FGBFI::getMP ()
777 {
778   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
779       return current_aircraft.fdm_state->get_engine(0)->get_Manifold_Pressure();
780   }
781 }
782
783
784 \f
785 ////////////////////////////////////////////////////////////////////////
786 // Velocities
787 ////////////////////////////////////////////////////////////////////////
788
789
790 /**
791  * Return the current airspeed in knots.
792  */
793 double
794 FGBFI::getAirspeed ()
795 {
796                                 // FIXME: should we add speed-up?
797   return current_aircraft.fdm_state->get_V_calibrated_kts();
798 }
799
800
801 /**
802  * Set the calibrated airspeed in knots.
803  */
804 void
805 FGBFI::setAirspeed (double speed)
806 {
807   current_aircraft.fdm_state->set_V_calibrated_kts(speed);
808 }
809
810
811 /**
812  * Return the current sideslip (FIXME: units unknown).
813  */
814 double
815 FGBFI::getSideSlip ()
816 {
817   return current_aircraft.fdm_state->get_Beta();
818 }
819
820
821 /**
822  * Return the current climb rate in feet/minute
823  */
824 double
825 FGBFI::getVerticalSpeed ()
826 {
827                                 // What about meters?
828   return current_aircraft.fdm_state->get_Climb_Rate() * 60.0;
829 }
830
831
832 /**
833  * Get the current north velocity (units??).
834  */
835 double
836 FGBFI::getSpeedNorth ()
837 {
838   return current_aircraft.fdm_state->get_V_north();
839 }
840
841
842 // /**
843 //  * Set the current north velocity (units??).
844 //  */
845 // void
846 // FGBFI::setSpeedNorth (double speed)
847 // {
848 //   FGInterface * fdm = current_aircraft.fdm_state;
849 // //   fdm->set_Velocities_Local(speed, fdm->get_V_east(), fdm->get_V_down());
850 // }
851
852
853 /**
854  * Get the current east velocity (units??).
855  */
856 double
857 FGBFI::getSpeedEast ()
858 {
859   return current_aircraft.fdm_state->get_V_east();
860 }
861
862
863 // /**
864 //  * Set the current east velocity (units??).
865 //  */
866 // void
867 // FGBFI::setSpeedEast (double speed)
868 // {
869 //   FGInterface * fdm = current_aircraft.fdm_state;
870 // //   fdm->set_Velocities_Local(fdm->get_V_north(), speed, fdm->get_V_down());
871 // }
872
873
874 /**
875  * Get the current down velocity (units??).
876  */
877 double
878 FGBFI::getSpeedDown ()
879 {
880   return current_aircraft.fdm_state->get_V_down();
881 }
882
883
884 // /**
885 //  * Set the current down velocity (units??).
886 //  */
887 // void
888 // FGBFI::setSpeedDown (double speed)
889 // {
890 //   FGInterface * fdm = current_aircraft.fdm_state;
891 // //   fdm->set_Velocities_Local(fdm->get_V_north(), fdm->get_V_east(), speed);
892 // }
893
894
895 \f
896 ////////////////////////////////////////////////////////////////////////
897 // Controls
898 ////////////////////////////////////////////////////////////////////////
899
900
901 /**
902  * Get the throttle setting, from 0.0 (none) to 1.0 (full).
903  */
904 double
905 FGBFI::getThrottle ()
906 {
907                                 // FIXME: add engine selector
908   return controls.get_throttle(0);
909 }
910
911
912 /**
913  * Set the throttle, from 0.0 (none) to 1.0 (full).
914  */
915 void
916 FGBFI::setThrottle (double throttle)
917 {
918                                 // FIXME: allow engine selection
919   controls.set_throttle(0, throttle);
920 }
921
922
923 /**
924  * Get the fuel mixture setting, from 0.0 (none) to 1.0 (full).
925  */
926 double
927 FGBFI::getMixture ()
928 {
929                                 // FIXME: add engine selector
930   return controls.get_mixture(0);
931 }
932
933
934 /**
935  * Set the fuel mixture, from 0.0 (none) to 1.0 (full).
936  */
937 void
938 FGBFI::setMixture (double mixture)
939 {
940                                 // FIXME: allow engine selection
941   controls.set_mixture(0, mixture);
942 }
943
944
945 /**
946  * Get the propellor pitch setting, from 0.0 (none) to 1.0 (full).
947  */
948 double
949 FGBFI::getPropAdvance ()
950 {
951                                 // FIXME: add engine selector
952   return controls.get_prop_advance(0);
953 }
954
955
956 /**
957  * Set the propellor pitch, from 0.0 (none) to 1.0 (full).
958  */
959 void
960 FGBFI::setPropAdvance (double pitch)
961 {
962                                 // FIXME: allow engine selection
963   controls.set_prop_advance(0, pitch);
964 }
965
966
967 /**
968  * Get the flaps setting, from 0.0 (none) to 1.0 (full).
969  */
970 double
971 FGBFI::getFlaps ()
972 {
973   return controls.get_flaps();
974 }
975
976
977 /**
978  * Set the flaps, from 0.0 (none) to 1.0 (full).
979  */
980 void
981 FGBFI::setFlaps (double flaps)
982 {
983                                 // FIXME: clamp?
984   controls.set_flaps(flaps);
985 }
986
987
988 /**
989  * Get the aileron, from -1.0 (left) to 1.0 (right).
990  */
991 double
992 FGBFI::getAileron ()
993 {
994   return controls.get_aileron();
995 }
996
997
998 /**
999  * Set the aileron, from -1.0 (left) to 1.0 (right).
1000  */
1001 void
1002 FGBFI::setAileron (double aileron)
1003 {
1004                                 // FIXME: clamp?
1005   controls.set_aileron(aileron);
1006 }
1007
1008
1009 /**
1010  * Get the rudder setting, from -1.0 (left) to 1.0 (right).
1011  */
1012 double
1013 FGBFI::getRudder ()
1014 {
1015   return controls.get_rudder();
1016 }
1017
1018
1019 /**
1020  * Set the rudder, from -1.0 (left) to 1.0 (right).
1021  */
1022 void
1023 FGBFI::setRudder (double rudder)
1024 {
1025                                 // FIXME: clamp?
1026   controls.set_rudder(rudder);
1027 }
1028
1029
1030 /**
1031  * Get the elevator setting, from -1.0 (down) to 1.0 (up).
1032  */
1033 double
1034 FGBFI::getElevator ()
1035 {
1036   return controls.get_elevator();
1037 }
1038
1039
1040 /**
1041  * Set the elevator, from -1.0 (down) to 1.0 (up).
1042  */
1043 void
1044 FGBFI::setElevator (double elevator)
1045 {
1046                                 // FIXME: clamp?
1047   controls.set_elevator(elevator);
1048 }
1049
1050
1051 /**
1052  * Get the elevator trim, from -1.0 (down) to 1.0 (up).
1053  */
1054 double
1055 FGBFI::getElevatorTrim ()
1056 {
1057   return controls.get_elevator_trim();
1058 }
1059
1060
1061 /**
1062  * Set the elevator trim, from -1.0 (down) to 1.0 (up).
1063  */
1064 void
1065 FGBFI::setElevatorTrim (double trim)
1066 {
1067                                 // FIXME: clamp?
1068   controls.set_elevator_trim(trim);
1069 }
1070
1071
1072 /**
1073  * Get the highest brake setting, from 0.0 (none) to 1.0 (full).
1074  */
1075 double
1076 FGBFI::getBrakes ()
1077 {
1078   double b1 = getCenterBrake();
1079   double b2 = getLeftBrake();
1080   double b3 = getRightBrake();
1081   return (b1 > b2 ? (b1 > b3 ? b1 : b3) : (b2 > b3 ? b2 : b3));
1082 }
1083
1084
1085 /**
1086  * Set all brakes, from 0.0 (none) to 1.0 (full).
1087  */
1088 void
1089 FGBFI::setBrakes (double brake)
1090 {
1091   setCenterBrake(brake);
1092   setLeftBrake(brake);
1093   setRightBrake(brake);
1094 }
1095
1096
1097 /**
1098  * Get the center brake, from 0.0 (none) to 1.0 (full).
1099  */
1100 double
1101 FGBFI::getCenterBrake ()
1102 {
1103   return controls.get_brake(2);
1104 }
1105
1106
1107 /**
1108  * Set the center brake, from 0.0 (none) to 1.0 (full).
1109  */
1110 void
1111 FGBFI::setCenterBrake (double brake)
1112 {
1113   controls.set_brake(2, brake);
1114 }
1115
1116
1117 /**
1118  * Get the left brake, from 0.0 (none) to 1.0 (full).
1119  */
1120 double
1121 FGBFI::getLeftBrake ()
1122 {
1123   return controls.get_brake(0);
1124 }
1125
1126
1127 /**
1128  * Set the left brake, from 0.0 (none) to 1.0 (full).
1129  */
1130 void
1131 FGBFI::setLeftBrake (double brake)
1132 {
1133   controls.set_brake(0, brake);
1134 }
1135
1136
1137 /**
1138  * Get the right brake, from 0.0 (none) to 1.0 (full).
1139  */
1140 double
1141 FGBFI::getRightBrake ()
1142 {
1143   return controls.get_brake(1);
1144 }
1145
1146
1147 /**
1148  * Set the right brake, from 0.0 (none) to 1.0 (full).
1149  */
1150 void
1151 FGBFI::setRightBrake (double brake)
1152 {
1153   controls.set_brake(1, brake);
1154 }
1155
1156
1157
1158
1159 \f
1160 ////////////////////////////////////////////////////////////////////////
1161 // Autopilot
1162 ////////////////////////////////////////////////////////////////////////
1163
1164
1165 /**
1166  * Get the autopilot altitude lock (true=on).
1167  */
1168 bool
1169 FGBFI::getAPAltitudeLock ()
1170 {
1171     return current_autopilot->get_AltitudeEnabled();
1172 }
1173
1174
1175 /**
1176  * Set the autopilot altitude lock (true=on).
1177  */
1178 void
1179 FGBFI::setAPAltitudeLock (bool lock)
1180 {
1181   current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_LOCK);
1182   current_autopilot->set_AltitudeEnabled(lock);
1183 }
1184
1185
1186 /**
1187  * Get the autopilot target altitude in feet.
1188  */
1189 double
1190 FGBFI::getAPAltitude ()
1191 {
1192   return current_autopilot->get_TargetAltitude() * METER_TO_FEET;
1193 }
1194
1195
1196 /**
1197  * Set the autopilot target altitude in feet.
1198  */
1199 void
1200 FGBFI::setAPAltitude (double altitude)
1201 {
1202     current_autopilot->set_TargetAltitude( altitude );
1203 }
1204
1205
1206 /**
1207  * Get the autopilot heading lock (true=on).
1208  */
1209 bool
1210 FGBFI::getAPHeadingLock ()
1211 {
1212     return
1213       (current_autopilot->get_HeadingEnabled() &&
1214        current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_LOCK);
1215 }
1216
1217
1218 /**
1219  * Set the autopilot heading lock (true=on).
1220  */
1221 void
1222 FGBFI::setAPHeadingLock (bool lock)
1223 {
1224   if (lock) {
1225                                 // We need to do this so that
1226                                 // it's possible to lock onto a
1227                                 // heading other than the current
1228                                 // heading.
1229     double heading = getAPHeadingMag();
1230     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_LOCK);
1231     current_autopilot->set_HeadingEnabled(true);
1232     setAPHeadingMag(heading);
1233   } else if (current_autopilot->get_HeadingMode() ==
1234              FGAutopilot::FG_HEADING_LOCK) {
1235     current_autopilot->set_HeadingEnabled(false);
1236   }
1237 }
1238
1239
1240 /**
1241  * Get the autopilot target heading in degrees.
1242  */
1243 double
1244 FGBFI::getAPHeading ()
1245 {
1246   return current_autopilot->get_TargetHeading();
1247 }
1248
1249
1250 /**
1251  * Set the autopilot target heading in degrees.
1252  */
1253 void
1254 FGBFI::setAPHeading (double heading)
1255 {
1256   current_autopilot->set_TargetHeading( heading );
1257 }
1258
1259
1260 /**
1261  * Get the autopilot target heading in degrees.
1262  */
1263 double
1264 FGBFI::getAPHeadingMag ()
1265 {
1266   return current_autopilot->get_TargetHeading() - getMagVar();
1267 }
1268
1269
1270 /**
1271  * Set the autopilot target heading in degrees.
1272  */
1273 void
1274 FGBFI::setAPHeadingMag (double heading)
1275 {
1276   current_autopilot->set_TargetHeading( heading + getMagVar() );
1277 }
1278
1279
1280 /**
1281  * Return true if the autopilot is locked to NAV1.
1282  */
1283 bool
1284 FGBFI::getAPNAV1Lock ()
1285 {
1286   return
1287     (current_autopilot->get_HeadingEnabled() &&
1288      current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_NAV1);
1289 }
1290
1291
1292 /**
1293  * Set the autopilot NAV1 lock.
1294  */
1295 void
1296 FGBFI::setAPNAV1Lock (bool lock)
1297 {
1298   if (lock) {
1299     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_NAV1);
1300     current_autopilot->set_HeadingEnabled(true);
1301   } else if (current_autopilot->get_HeadingMode() ==
1302              FGAutopilot::FG_HEADING_NAV1) {
1303     current_autopilot->set_HeadingEnabled(false);
1304   }
1305 }
1306
1307
1308 \f
1309 ////////////////////////////////////////////////////////////////////////
1310 // Radio navigation.
1311 ////////////////////////////////////////////////////////////////////////
1312
1313 double
1314 FGBFI::getNAV1Freq ()
1315 {
1316   return current_radiostack->get_nav1_freq();
1317 }
1318
1319 double
1320 FGBFI::getNAV1AltFreq ()
1321 {
1322   return current_radiostack->get_nav1_alt_freq();
1323 }
1324
1325 double
1326 FGBFI::getNAV1Radial ()
1327 {
1328   return current_radiostack->get_nav1_radial();
1329 }
1330
1331 double
1332 FGBFI::getNAV1SelRadial ()
1333 {
1334   return current_radiostack->get_nav1_sel_radial();
1335 }
1336
1337 double
1338 FGBFI::getNAV1DistDME ()
1339 {
1340   return current_radiostack->get_nav1_dme_dist();
1341 }
1342
1343 bool 
1344 FGBFI::getNAV1TO ()
1345 {
1346   if (current_radiostack->get_nav1_inrange()) {
1347     double heading = current_radiostack->get_nav1_heading();
1348     double radial = current_radiostack->get_nav1_radial();
1349     double var = FGBFI::getMagVar();
1350     if (current_radiostack->get_nav1_loc()) {
1351       double offset = fabs(heading - radial);
1352       return (offset<= 8.0 || offset >= 352.0);
1353     } else {
1354       double offset =
1355         fabs(heading - var - radial);
1356       return (offset <= 20.0 || offset >= 340.0);
1357     }
1358   } else {
1359     return false;
1360   }
1361 }
1362
1363 bool
1364 FGBFI::getNAV1FROM ()
1365 {
1366   if (current_radiostack->get_nav1_inrange()) {
1367     double heading = current_radiostack->get_nav1_heading();
1368     double radial = current_radiostack->get_nav1_radial();
1369     double var = FGBFI::getMagVar();
1370     if (current_radiostack->get_nav1_loc()) {
1371       double offset = fabs(heading - radial);
1372       return (offset >= 172.0 && offset<= 188.0);
1373     } else {
1374       double offset =
1375         fabs(heading - var - radial);
1376       return (offset >= 160.0 && offset <= 200.0);
1377     }
1378   } else {
1379     return false;
1380   }
1381 }
1382
1383 bool
1384 FGBFI::getNAV1InRange ()
1385 {
1386   return current_radiostack->get_nav1_inrange();
1387 }
1388
1389 bool
1390 FGBFI::getNAV1DMEInRange ()
1391 {
1392   return (current_radiostack->get_nav1_inrange() &&
1393           current_radiostack->get_nav1_has_dme());
1394 }
1395
1396 double
1397 FGBFI::getNAV2Freq ()
1398 {
1399   return current_radiostack->get_nav2_freq();
1400 }
1401
1402 double
1403 FGBFI::getNAV2AltFreq ()
1404 {
1405   return current_radiostack->get_nav2_alt_freq();
1406 }
1407
1408 double
1409 FGBFI::getNAV2Radial ()
1410 {
1411   return current_radiostack->get_nav2_radial();
1412 }
1413
1414 double
1415 FGBFI::getNAV2SelRadial ()
1416 {
1417   return current_radiostack->get_nav2_sel_radial();
1418 }
1419
1420 double
1421 FGBFI::getNAV2DistDME ()
1422 {
1423   return current_radiostack->get_nav2_dme_dist();
1424 }
1425
1426 bool 
1427 FGBFI::getNAV2TO ()
1428 {
1429   if (current_radiostack->get_nav2_inrange()) {
1430     double heading = current_radiostack->get_nav2_heading();
1431     double radial = current_radiostack->get_nav2_radial();
1432     double var = FGBFI::getMagVar();
1433     if (current_radiostack->get_nav2_loc()) {
1434       double offset = fabs(heading - radial);
1435       return (offset<= 8.0 || offset >= 352.0);
1436     } else {
1437       double offset =
1438         fabs(heading - var - radial);
1439       return (offset <= 20.0 || offset >= 340.0);
1440     }
1441   } else {
1442     return false;
1443   }
1444 }
1445
1446 bool 
1447 FGBFI::getNAV2FROM ()
1448 {
1449   if (current_radiostack->get_nav2_inrange()) {
1450     double heading = current_radiostack->get_nav2_heading();
1451     double radial = current_radiostack->get_nav2_radial();
1452     double var = FGBFI::getMagVar();
1453     if (current_radiostack->get_nav2_loc()) {
1454       double offset = fabs(heading - radial);
1455       return (offset >= 172.0 && offset<= 188.0);
1456     } else {
1457       double offset =
1458         fabs(heading - var - radial);
1459       return (offset >= 160.0 && offset <= 200.0);
1460     }
1461   } else {
1462     return false;
1463   }
1464 }
1465
1466
1467 bool
1468 FGBFI::getNAV2InRange ()
1469 {
1470   return current_radiostack->get_nav2_inrange();
1471 }
1472
1473 bool
1474 FGBFI::getNAV2DMEInRange ()
1475 {
1476   return (current_radiostack->get_nav2_inrange() &&
1477           current_radiostack->get_nav2_has_dme());
1478 }
1479
1480 double
1481 FGBFI::getADFFreq ()
1482 {
1483   return current_radiostack->get_adf_freq();
1484 }
1485
1486 double
1487 FGBFI::getADFAltFreq ()
1488 {
1489   return current_radiostack->get_adf_alt_freq();
1490 }
1491
1492 double
1493 FGBFI::getADFRotation ()
1494 {
1495   return current_radiostack->get_adf_rotation();
1496 }
1497
1498 void
1499 FGBFI::setNAV1Freq (double freq)
1500 {
1501   current_radiostack->set_nav1_freq(freq);
1502 }
1503
1504 void
1505 FGBFI::setNAV1AltFreq (double freq)
1506 {
1507   current_radiostack->set_nav1_alt_freq(freq);
1508 }
1509
1510 void
1511 FGBFI::setNAV1SelRadial (double radial)
1512 {
1513   current_radiostack->set_nav1_sel_radial(radial);
1514 }
1515
1516 void
1517 FGBFI::setNAV2Freq (double freq)
1518 {
1519   current_radiostack->set_nav2_freq(freq);
1520 }
1521
1522 void
1523 FGBFI::setNAV2AltFreq (double freq)
1524 {
1525   current_radiostack->set_nav2_alt_freq(freq);
1526 }
1527
1528 void
1529 FGBFI::setNAV2SelRadial (double radial)
1530 {
1531   current_radiostack->set_nav2_sel_radial(radial);
1532 }
1533
1534 void
1535 FGBFI::setADFFreq (double freq)
1536 {
1537   current_radiostack->set_adf_freq(freq);
1538 }
1539
1540 void
1541 FGBFI::setADFAltFreq (double freq)
1542 {
1543   current_radiostack->set_adf_alt_freq(freq);
1544 }
1545
1546 void
1547 FGBFI::setADFRotation (double rot)
1548 {
1549   current_radiostack->set_adf_rotation(rot);
1550 }
1551
1552
1553 \f
1554 ////////////////////////////////////////////////////////////////////////
1555 // GPS
1556 ////////////////////////////////////////////////////////////////////////
1557
1558
1559 /**
1560  * Get the autopilot GPS lock (true=on).
1561  */
1562 bool
1563 FGBFI::getGPSLock ()
1564 {
1565   return (current_autopilot->get_HeadingEnabled() &&
1566           (current_autopilot->get_HeadingMode() ==
1567            FGAutopilot::FG_HEADING_WAYPOINT ));
1568 }
1569
1570
1571 /**
1572  * Set the autopilot GPS lock (true=on).
1573  */
1574 void
1575 FGBFI::setGPSLock (bool lock)
1576 {
1577   if (lock) {
1578     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_WAYPOINT);
1579     current_autopilot->set_HeadingEnabled(true);
1580   } else if (current_autopilot->get_HeadingMode() ==
1581              FGAutopilot::FG_HEADING_WAYPOINT) {
1582     current_autopilot->set_HeadingEnabled(false);
1583   }
1584 }
1585
1586
1587 /**
1588  * Get the GPS target airport code.
1589  */
1590 const string &
1591 FGBFI::getTargetAirport ()
1592 {
1593   // FIXME: not thread-safe
1594   static string out;
1595   out = globals->get_options()->get_airport_id();
1596
1597   return out;
1598 }
1599
1600
1601 /**
1602  * Set the GPS target airport code.
1603  */
1604 void
1605 FGBFI::setTargetAirport (const string &airportId)
1606 {
1607   // cout << "setting target airport id = " << airportId << endl;
1608   globals->get_options()->set_airport_id(airportId);
1609 }
1610
1611
1612 /**
1613  * Get the GPS target latitude in degrees (negative for south).
1614  */
1615 double
1616 FGBFI::getGPSTargetLatitude ()
1617 {
1618     return current_autopilot->get_TargetLatitude();
1619 }
1620
1621
1622 /**
1623  * Get the GPS target longitude in degrees (negative for west).
1624  */
1625 double
1626 FGBFI::getGPSTargetLongitude ()
1627 {
1628   return current_autopilot->get_TargetLongitude();
1629 }
1630
1631 #if 0
1632 /**
1633  * Set the GPS target longitude in degrees (negative for west).
1634  */
1635 void
1636 FGBFI::setGPSTargetLongitude (double longitude)
1637 {
1638   current_autopilot->set_TargetLongitude( longitude );
1639 }
1640 #endif
1641
1642
1643 \f
1644 ////////////////////////////////////////////////////////////////////////
1645 // Weather
1646 ////////////////////////////////////////////////////////////////////////
1647
1648
1649 /**
1650  * Get the current visible (units??).
1651  */
1652 double
1653 FGBFI::getVisibility ()
1654 {
1655 #ifndef FG_OLD_WEATHER
1656   return WeatherDatabase->getWeatherVisibility();
1657 #else
1658   return current_weather.get_visibility();
1659 #endif
1660 }
1661
1662
1663 /**
1664  * Set the current visibility (units??).
1665  */
1666 void
1667 FGBFI::setVisibility (double visibility)
1668 {
1669 #ifndef FG_OLD_WEATHER
1670   WeatherDatabase->setWeatherVisibility(visibility);
1671 #else
1672   current_weather.set_visibility(visibility);
1673 #endif
1674 }
1675
1676
1677 \f
1678 ////////////////////////////////////////////////////////////////////////
1679 // Time
1680 ////////////////////////////////////////////////////////////////////////
1681
1682 /**
1683  * Return the magnetic variation
1684  */
1685 double
1686 FGBFI::getMagVar ()
1687 {
1688   return globals->get_mag()->get_magvar() * RAD_TO_DEG;
1689 }
1690
1691
1692 /**
1693  * Return the magnetic variation
1694  */
1695 double
1696 FGBFI::getMagDip ()
1697 {
1698   return globals->get_mag()->get_magdip() * RAD_TO_DEG;
1699 }
1700
1701
1702 // end of bfi.cxx
1703