]> git.mxchange.org Git - flightgear.git/blob - src/Main/bfi.cxx
8dbd5209606e8540fb0da33e8338cef13901415b
[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/fg_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 #ifndef FG_OLD_WEATHER
52 #  include <WeatherCM/FGLocalWeatherDatabase.h>
53 #else
54 #  include <Weather/weather.hxx>
55 #endif
56
57 #include "globals.hxx"
58 #include "options.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 bool FGBFI::_needReinit = false;
75
76
77 \f
78 ////////////////////////////////////////////////////////////////////////
79 // Local functions
80 ////////////////////////////////////////////////////////////////////////
81
82
83 /**
84  * Initialize the BFI by binding its functions to properties.
85  *
86  * TODO: perhaps these should migrate into the individual modules
87  * (i.e. they should register themselves).
88  */
89 void
90 FGBFI::init ()
91 {
92   FG_LOG(FG_GENERAL, FG_INFO, "Starting BFI init");
93                                 // Simulation
94   current_properties.tieInt("/sim/flight-model",
95                             getFlightModel, setFlightModel);
96 //   current_properties.tieString("/sim/aircraft",
97 //                             getAircraft, setAircraft);
98   // TODO: timeGMT
99   current_properties.tieBool("/sim/hud/visibility",
100                              getHUDVisible, setHUDVisible);
101   current_properties.tieBool("/sim/panel/visibility",
102                              getPanelVisible, setPanelVisible);
103
104                                 // Position
105   current_properties.tieDouble("/position/latitude",
106                                 getLatitude, setLatitude);
107   current_properties.tieDouble("/position/longitude",
108                                getLongitude, setLongitude);
109   current_properties.tieDouble("/position/altitude",
110                                getAltitude, setAltitude);
111   current_properties.tieDouble("/position/altitude-agl",
112                                getAGL, 0);
113
114                                 // Orientation
115   current_properties.tieDouble("/orientation/heading",
116                                getHeading, setHeading);
117   current_properties.tieDouble("/orientation/heading-magnetic",
118                                getHeadingMag, 0);
119   current_properties.tieDouble("/orientation/pitch",
120                                getPitch, setPitch);
121   current_properties.tieDouble("/orientation/roll",
122                                getRoll, setRoll);
123
124                                 // Velocities
125   current_properties.tieDouble("/velocities/airspeed",
126                                getAirspeed, 0);
127   current_properties.tieDouble("/velocities/side-slip",
128                                getSideSlip, 0);
129   current_properties.tieDouble("/velocities/vertical-speed",
130                                getVerticalSpeed, 0);
131   current_properties.tieDouble("/velocities/speed-north",
132                                getSpeedNorth, setSpeedNorth);
133   current_properties.tieDouble("/velocities/speed-east",
134                                getSpeedEast, setSpeedEast);
135   current_properties.tieDouble("/velocities/speed-down",
136                                getSpeedDown, setSpeedDown);
137
138                                 // Controls
139   current_properties.tieDouble("/controls/throttle",
140                                getThrottle, setThrottle);
141   current_properties.tieDouble("/controls/flaps",
142                                getFlaps, setFlaps);
143   current_properties.tieDouble("/controls/aileron",
144                                getAileron, setAileron);
145   current_properties.tieDouble("/controls/rudder",
146                                getRudder, setRudder);
147   current_properties.tieDouble("/controls/elevator",
148                                getElevator, setElevator);
149   current_properties.tieDouble("/controls/elevator-trim",
150                                getElevatorTrim, setElevatorTrim);
151   current_properties.tieDouble("/controls/brakes/all",
152                                getBrakes, setBrakes);
153   current_properties.tieDouble("/controls/brakes/left",
154                                getLeftBrake, setLeftBrake);
155   current_properties.tieDouble("/controls/brakes/right",
156                                getRightBrake, setRightBrake);
157   current_properties.tieDouble("/controls/brakes/Center",
158                                getRightBrake, setCenterBrake);
159
160                                 // Deprecated...
161   current_properties.tieDouble("/controls/brake",
162                                getBrakes, setBrakes);
163   current_properties.tieDouble("/controls/left-brake",
164                                getLeftBrake, setLeftBrake);
165   current_properties.tieDouble("/controls/right-brake",
166                                getRightBrake, setRightBrake);
167
168                                 // Autopilot
169   current_properties.tieBool("/autopilot/locks/altitude",
170                              getAPAltitudeLock, setAPAltitudeLock);
171   current_properties.tieDouble("/autopilot/settings/altitude",
172                                getAPAltitude, setAPAltitude);
173   current_properties.tieBool("/autopilot/locks/heading",
174                              getAPHeadingLock, setAPHeadingLock);
175   current_properties.tieDouble("/autopilot/settings/heading",
176                                getAPHeading, setAPHeading);
177   current_properties.tieDouble("/autopilot/settings/heading-magnetic",
178                                getAPHeadingMag, setAPHeadingMag);
179   current_properties.tieBool("/autopilot/locks/nav1",
180                              getAPNAV1Lock, setAPNAV1Lock);
181
182                                 // Radio navigation
183   current_properties.tieDouble("/radios/nav1/frequencies/selected",
184                                getNAV1Freq, setNAV1Freq);
185   current_properties.tieDouble("/radios/nav1/frequencies/standby",
186                                getNAV1AltFreq, setNAV1AltFreq);
187   current_properties.tieDouble("/radios/nav1/radials/actual",
188                                getNAV1Radial, 0);
189   current_properties.tieDouble("/radios/nav1/radials/selected",
190                                getNAV1SelRadial, setNAV1SelRadial);
191   current_properties.tieDouble("/radios/nav1/dme/distance",
192                                getNAV1DistDME, 0);
193   current_properties.tieBool("/radios/nav1/in-range",
194                              getNAV1InRange, 0);
195   current_properties.tieBool("/radios/nav1/dme/in-range",
196                              getNAV1DMEInRange, 0);
197                                
198   current_properties.tieDouble("/radios/nav2/frequencies/selected",
199                                getNAV2Freq, setNAV2Freq);
200   current_properties.tieDouble("/radios/nav2/frequencies/standby",
201                                getNAV2AltFreq, setNAV2AltFreq);
202   current_properties.tieDouble("/radios/nav2/radials/actual",
203                                getNAV2Radial, 0);
204   current_properties.tieDouble("/radios/nav2/radials/selected",
205                                getNAV2SelRadial, setNAV2SelRadial);
206   current_properties.tieDouble("/radios/nav2/dme/distance",
207                                getNAV2DistDME, 0);
208   current_properties.tieBool("/radios/nav2/in-range",
209                              getNAV2InRange, 0);
210   current_properties.tieBool("/radios/nav2/dme/in-range",
211                              getNAV2DMEInRange, 0);
212
213   current_properties.tieDouble("/radios/adf/frequencies/selected",
214                                getADFFreq, setADFFreq);
215   current_properties.tieDouble("/radios/adf/frequencies/standby",
216                                getADFAltFreq, setADFAltFreq);
217   current_properties.tieDouble("/radios/adf/rotation",
218                                getADFRotation, setADFRotation);
219
220   FG_LOG(FG_GENERAL, FG_INFO, "Ending BFI init");
221 }
222
223
224 /**
225  * Reinitialize FGFS if required.
226  *
227  * Some changes (especially those in aircraft position) require that
228  * FGFS be reinitialized afterwards.  Rather than reinitialize after
229  * every change, the setter methods simply set a flag so that there
230  * can be a single reinit at the end of the frame.
231  */
232 void
233 FGBFI::update ()
234 {
235   if (_needReinit) {
236     reinit();
237   }
238 }
239
240
241 /**
242  * Reinitialize FGFS to use the new BFI settings.
243  */
244 void
245 FGBFI::reinit ()
246 {
247                                 // Save the state of everything
248                                 // that's going to get clobbered
249                                 // when we reinit the subsystems.
250
251   cout << "BFI: start reinit\n";
252
253 //   setHeading(getHeading());
254 //   setPitch(getPitch());
255 //   setRoll(getRoll());
256 //   setSpeedNorth(getSpeedNorth());
257 //   setSpeedEast(getSpeedEast());
258 //   setSpeedDown(getSpeedDown());
259 //   setLatitude(getLatitude());
260 //   setLongitude(getLongitude());
261 //   setAltitude(getAltitude());
262
263                                 // TODO: add more AP stuff
264   double elevator = getElevator();
265   double aileron = getAileron();
266   double rudder = getRudder();
267   double throttle = getThrottle();
268   double elevator_trim = getElevatorTrim();
269   double flaps = getFlaps();
270   double brake = getBrakes();
271   bool apHeadingLock = getAPHeadingLock();
272   double apHeadingMag = getAPHeadingMag();
273   bool apAltitudeLock = getAPAltitudeLock();
274   double apAltitude = getAPAltitude();
275   const string &targetAirport = getTargetAirport();
276   bool gpsLock = getGPSLock();
277   double gpsLatitude = getGPSTargetLatitude();
278   double gpsLongitude = getGPSTargetLongitude();
279
280   setTargetAirport("");
281   cout << "Target airport is " << current_options.get_airport_id() << endl;
282
283   fgReInitSubsystems();
284
285                                 // FIXME: this is wrong.
286                                 // All of these are scheduled events,
287                                 // and it should be possible to force
288                                 // them all to run once.
289   fgUpdateSunPos();
290   fgUpdateMoonPos();
291   cur_light_params.Update();
292   fgUpdateLocalTime();
293   fgUpdateWeatherDatabase();
294   fgRadioSearch();
295
296                                 // Restore all of the old states.
297   setElevator(elevator);
298   setAileron(aileron);
299   setRudder(rudder);
300   setThrottle(throttle);
301   setElevatorTrim(elevator_trim);
302   setFlaps(flaps);
303   setBrakes(brake);
304   setAPHeadingLock(apHeadingLock);
305   setAPHeadingMag(apHeadingMag);
306   setAPAltitudeLock(apAltitudeLock);
307   setAPAltitude(apAltitude);
308   setTargetAirport(targetAirport);
309   setGPSLock(gpsLock);
310   setGPSTargetLatitude(gpsLatitude);
311   setGPSTargetLongitude(gpsLongitude);
312
313   _needReinit = false;
314
315   cout << "BFI: end reinit\n";
316 }
317
318
319 \f
320 ////////////////////////////////////////////////////////////////////////
321 // Simulation.
322 ////////////////////////////////////////////////////////////////////////
323
324
325 /**
326  * Return the flight model as an integer.
327  *
328  * TODO: use a string instead.
329  */
330 int
331 FGBFI::getFlightModel ()
332 {
333   return current_options.get_flight_model();
334 }
335
336
337 /**
338  * Return the current aircraft as a string.
339  */
340 const string
341 FGBFI::getAircraft ()
342 {
343   return current_options.get_aircraft();
344 }
345
346
347 /**
348  * Return the current aircraft directory (UIUC) as a string.
349  */
350 const string
351 FGBFI::getAircraftDir ()
352 {
353   return aircraft_dir;
354 }
355
356
357 /**
358  * Set the flight model as an integer.
359  *
360  * TODO: use a string instead.
361  */
362 void
363 FGBFI::setFlightModel (int model)
364 {
365   current_options.set_flight_model(model);
366   needReinit();
367 }
368
369
370 /**
371  * Set the current aircraft.
372  */
373 void
374 FGBFI::setAircraft (const string &aircraft)
375 {
376   current_options.set_aircraft(aircraft);
377   needReinit();
378 }
379
380
381 /**
382  * Set the current aircraft directory (UIUC).
383  */
384 void
385 FGBFI::setAircraftDir (const string &dir)
386 {
387   aircraft_dir = dir;
388   needReinit();
389 }
390
391
392 /**
393  * Return the current Zulu time.
394  */
395 time_t
396 FGBFI::getTimeGMT ()
397 {
398   return globals->get_time_params()->get_cur_time();
399 }
400
401
402 /**
403  * Set the current Zulu time.
404  */
405 void
406 FGBFI::setTimeGMT (time_t time)
407 {
408                                 // FIXME: need to update lighting
409                                 // and solar system
410   current_options.set_time_offset(time);
411   current_options.set_time_offset_type(fgOPTIONS::FG_TIME_GMT_ABSOLUTE);
412   globals->get_time_params()->update( cur_fdm_state->get_Longitude(),
413                                       cur_fdm_state->get_Latitude(),
414                                       globals->get_warp() );
415   needReinit();
416 }
417
418
419 /**
420  * Return true if the HUD is visible.
421  */
422 bool
423 FGBFI::getHUDVisible ()
424 {
425   return current_options.get_hud_status();
426 }
427
428
429 /**
430  * Ensure that the HUD is visible or hidden.
431  */
432 void
433 FGBFI::setHUDVisible (bool visible)
434 {
435   current_options.set_hud_status(visible);
436 }
437
438
439 /**
440  * Return true if the 2D panel is visible.
441  */
442 bool
443 FGBFI::getPanelVisible ()
444 {
445   return current_options.get_panel_status();
446 }
447
448
449 /**
450  * Ensure that the 2D panel is visible or hidden.
451  */
452 void
453 FGBFI::setPanelVisible (bool visible)
454 {
455   if (current_options.get_panel_status() != visible) {
456     current_options.toggle_panel();
457   }
458 }
459
460
461 \f
462 ////////////////////////////////////////////////////////////////////////
463 // Position
464 ////////////////////////////////////////////////////////////////////////
465
466
467 /**
468  * Return the current latitude in degrees (negative for south).
469  */
470 double
471 FGBFI::getLatitude ()
472 {
473   return current_aircraft.fdm_state->get_Latitude() * RAD_TO_DEG;
474 }
475
476
477 /**
478  * Set the current latitude in degrees (negative for south).
479  */
480 void
481 FGBFI::setLatitude (double latitude)
482 {
483   current_options.set_lat(latitude);
484   current_aircraft.fdm_state->set_Latitude(latitude * DEG_TO_RAD);
485   needReinit();
486 }
487
488
489 /**
490  * Return the current longitude in degrees (negative for west).
491  */
492 double
493 FGBFI::getLongitude ()
494 {
495   return current_aircraft.fdm_state->get_Longitude() * RAD_TO_DEG;
496 }
497
498
499 /**
500  * Set the current longitude in degrees (negative for west).
501  */
502 void
503 FGBFI::setLongitude (double longitude)
504 {
505   current_options.set_lon(longitude);
506   current_aircraft.fdm_state->set_Longitude(longitude * DEG_TO_RAD);
507   needReinit();
508 }
509
510
511 /**
512  * Return the current altitude in feet.
513  */
514 double
515 FGBFI::getAltitude ()
516 {
517   return current_aircraft.fdm_state->get_Altitude();
518 }
519
520
521
522 /**
523  * Return the current altitude in above the terrain.
524  */
525 double
526 FGBFI::getAGL ()
527 {
528   return current_aircraft.fdm_state->get_Altitude()
529          - (scenery.cur_elev * METER_TO_FEET);
530 }
531
532
533 /**
534  * Set the current altitude in feet.
535  */
536 void
537 FGBFI::setAltitude (double altitude)
538 {
539   fgFDMForceAltitude(getFlightModel(), altitude * FEET_TO_METER);
540   current_options.set_altitude(altitude * FEET_TO_METER);
541   current_aircraft.fdm_state->set_Altitude(altitude);
542 //   needReinit();
543 }
544
545
546 \f
547 ////////////////////////////////////////////////////////////////////////
548 // Attitude
549 ////////////////////////////////////////////////////////////////////////
550
551
552 /**
553  * Return the current heading in degrees.
554  */
555 double
556 FGBFI::getHeading ()
557 {
558   return current_aircraft.fdm_state->get_Psi() * RAD_TO_DEG;
559 }
560
561
562 /**
563  * Return the current heading in degrees.
564  */
565 double
566 FGBFI::getHeadingMag ()
567 {
568   return current_aircraft.fdm_state->get_Psi() * RAD_TO_DEG - getMagVar();
569 }
570
571
572 /**
573  * Set the current heading in degrees.
574  */
575 void
576 FGBFI::setHeading (double heading)
577 {
578   current_options.set_heading(heading);
579   current_aircraft.fdm_state->set_Euler_Angles(getRoll() * DEG_TO_RAD,
580                                                getPitch() * DEG_TO_RAD,
581                                                heading * DEG_TO_RAD);
582   needReinit();
583 }
584
585
586 /**
587  * Return the current pitch in degrees.
588  */
589 double
590 FGBFI::getPitch ()
591 {
592   return current_aircraft.fdm_state->get_Theta() * RAD_TO_DEG;
593 }
594
595
596 /**
597  * Set the current pitch in degrees.
598  */
599 void
600 FGBFI::setPitch (double pitch)
601 {
602
603   current_options.set_pitch(pitch);
604   current_aircraft.fdm_state->set_Euler_Angles(getRoll() * DEG_TO_RAD,
605                                                pitch * DEG_TO_RAD,
606                                                getHeading() * DEG_TO_RAD);
607   needReinit();
608 }
609
610
611 /**
612  * Return the current roll in degrees.
613  */
614 double
615 FGBFI::getRoll ()
616 {
617   return current_aircraft.fdm_state->get_Phi() * RAD_TO_DEG;
618 }
619
620
621 /**
622  * Set the current roll in degrees.
623  */
624 void
625 FGBFI::setRoll (double roll)
626 {
627   current_options.set_roll(roll);
628   current_aircraft.fdm_state->set_Euler_Angles(roll * DEG_TO_RAD,
629                                                getPitch() * DEG_TO_RAD,
630                                                getHeading() * DEG_TO_RAD);
631   needReinit();
632 }
633
634
635 \f
636 ////////////////////////////////////////////////////////////////////////
637 // Velocities
638 ////////////////////////////////////////////////////////////////////////
639
640
641 /**
642  * Return the current airspeed in knots.
643  */
644 double
645 FGBFI::getAirspeed ()
646 {
647                                 // FIXME: should we add speed-up?
648   return current_aircraft.fdm_state->get_V_calibrated_kts();
649 }
650
651
652 /**
653  * Return the current sideslip (FIXME: units unknown).
654  */
655 double
656 FGBFI::getSideSlip ()
657 {
658   return current_aircraft.fdm_state->get_Beta();
659 }
660
661
662 /**
663  * Return the current climb rate in feet/minute
664  */
665 double
666 FGBFI::getVerticalSpeed ()
667 {
668                                 // What about meters?
669   return current_aircraft.fdm_state->get_Climb_Rate() * 60.0;
670 }
671
672
673 /**
674  * Get the current north velocity (units??).
675  */
676 double
677 FGBFI::getSpeedNorth ()
678 {
679   return current_aircraft.fdm_state->get_V_north();
680 }
681
682
683 /**
684  * Set the current north velocity (units??).
685  */
686 void
687 FGBFI::setSpeedNorth (double speed)
688 {
689   current_options.set_uBody(speed);
690   current_aircraft.fdm_state->set_Velocities_Local(speed,
691                                                    getSpeedEast(),
692                                                    getSpeedDown());
693   needReinit();
694 }
695
696
697 /**
698  * Get the current east velocity (units??).
699  */
700 double
701 FGBFI::getSpeedEast ()
702 {
703   return current_aircraft.fdm_state->get_V_east();
704 }
705
706
707 /**
708  * Set the current east velocity (units??).
709  */
710 void
711 FGBFI::setSpeedEast (double speed)
712 {
713   current_options.set_vBody(speed);
714   current_aircraft.fdm_state->set_Velocities_Local(getSpeedNorth(),
715                                                    speed,
716                                                    getSpeedDown());
717   needReinit();
718 }
719
720
721 /**
722  * Get the current down velocity (units??).
723  */
724 double
725 FGBFI::getSpeedDown ()
726 {
727   return current_aircraft.fdm_state->get_V_down();
728 }
729
730
731 /**
732  * Set the current down velocity (units??).
733  */
734 void
735 FGBFI::setSpeedDown (double speed)
736 {
737   current_options.set_wBody(speed);
738   current_aircraft.fdm_state->set_Velocities_Local(getSpeedNorth(),
739                                                    getSpeedEast(),
740                                                    speed);
741   needReinit();
742 }
743
744
745 \f
746 ////////////////////////////////////////////////////////////////////////
747 // Controls
748 ////////////////////////////////////////////////////////////////////////
749
750
751 /**
752  * Get the throttle setting, from 0.0 (none) to 1.0 (full).
753  */
754 double
755 FGBFI::getThrottle ()
756 {
757                                 // FIXME: add throttle selector
758   return controls.get_throttle(0);
759 }
760
761
762 /**
763  * Set the throttle, from 0.0 (none) to 1.0 (full).
764  */
765 void
766 FGBFI::setThrottle (double throttle)
767 {
768                                 // FIXME: allow throttle selection
769                                 // FIXME: clamp?
770   controls.set_throttle(0, throttle);
771 }
772
773
774 /**
775  * Get the flaps setting, from 0.0 (none) to 1.0 (full).
776  */
777 double
778 FGBFI::getFlaps ()
779 {
780   return controls.get_flaps();
781 }
782
783
784 /**
785  * Set the flaps, from 0.0 (none) to 1.0 (full).
786  */
787 void
788 FGBFI::setFlaps (double flaps)
789 {
790                                 // FIXME: clamp?
791   controls.set_flaps(flaps);
792 }
793
794
795 /**
796  * Get the aileron, from -1.0 (left) to 1.0 (right).
797  */
798 double
799 FGBFI::getAileron ()
800 {
801   return controls.get_aileron();
802 }
803
804
805 /**
806  * Set the aileron, from -1.0 (left) to 1.0 (right).
807  */
808 void
809 FGBFI::setAileron (double aileron)
810 {
811                                 // FIXME: clamp?
812   controls.set_aileron(aileron);
813 }
814
815
816 /**
817  * Get the rudder setting, from -1.0 (left) to 1.0 (right).
818  */
819 double
820 FGBFI::getRudder ()
821 {
822   return controls.get_rudder();
823 }
824
825
826 /**
827  * Set the rudder, from -1.0 (left) to 1.0 (right).
828  */
829 void
830 FGBFI::setRudder (double rudder)
831 {
832                                 // FIXME: clamp?
833   controls.set_rudder(rudder);
834 }
835
836
837 /**
838  * Get the elevator setting, from -1.0 (down) to 1.0 (up).
839  */
840 double
841 FGBFI::getElevator ()
842 {
843   return controls.get_elevator();
844 }
845
846
847 /**
848  * Set the elevator, from -1.0 (down) to 1.0 (up).
849  */
850 void
851 FGBFI::setElevator (double elevator)
852 {
853                                 // FIXME: clamp?
854   controls.set_elevator(elevator);
855 }
856
857
858 /**
859  * Get the elevator trim, from -1.0 (down) to 1.0 (up).
860  */
861 double
862 FGBFI::getElevatorTrim ()
863 {
864   return controls.get_elevator_trim();
865 }
866
867
868 /**
869  * Set the elevator trim, from -1.0 (down) to 1.0 (up).
870  */
871 void
872 FGBFI::setElevatorTrim (double trim)
873 {
874                                 // FIXME: clamp?
875   controls.set_elevator_trim(trim);
876 }
877
878
879 /**
880  * Get the highest brake setting, from 0.0 (none) to 1.0 (full).
881  */
882 double
883 FGBFI::getBrakes ()
884 {
885   double b1 = getCenterBrake();
886   double b2 = getLeftBrake();
887   double b3 = getRightBrake();
888   return (b1 > b2 ? (b1 > b3 ? b1 : b3) : (b2 > b3 ? b2 : b3));
889 }
890
891
892 /**
893  * Set all brakes, from 0.0 (none) to 1.0 (full).
894  */
895 void
896 FGBFI::setBrakes (double brake)
897 {
898   setCenterBrake(brake);
899   setLeftBrake(brake);
900   setRightBrake(brake);
901 }
902
903
904 /**
905  * Get the center brake, from 0.0 (none) to 1.0 (full).
906  */
907 double
908 FGBFI::getCenterBrake ()
909 {
910   return controls.get_brake(2);
911 }
912
913
914 /**
915  * Set the center brake, from 0.0 (none) to 1.0 (full).
916  */
917 void
918 FGBFI::setCenterBrake (double brake)
919 {
920   controls.set_brake(2, brake);
921 }
922
923
924 /**
925  * Get the left brake, from 0.0 (none) to 1.0 (full).
926  */
927 double
928 FGBFI::getLeftBrake ()
929 {
930   return controls.get_brake(0);
931 }
932
933
934 /**
935  * Set the left brake, from 0.0 (none) to 1.0 (full).
936  */
937 void
938 FGBFI::setLeftBrake (double brake)
939 {
940   controls.set_brake(0, brake);
941 }
942
943
944 /**
945  * Get the right brake, from 0.0 (none) to 1.0 (full).
946  */
947 double
948 FGBFI::getRightBrake ()
949 {
950   return controls.get_brake(1);
951 }
952
953
954 /**
955  * Set the right brake, from 0.0 (none) to 1.0 (full).
956  */
957 void
958 FGBFI::setRightBrake (double brake)
959 {
960   controls.set_brake(1, brake);
961 }
962
963
964
965
966 \f
967 ////////////////////////////////////////////////////////////////////////
968 // Autopilot
969 ////////////////////////////////////////////////////////////////////////
970
971
972 /**
973  * Get the autopilot altitude lock (true=on).
974  */
975 bool
976 FGBFI::getAPAltitudeLock ()
977 {
978     return current_autopilot->get_AltitudeEnabled();
979 }
980
981
982 /**
983  * Set the autopilot altitude lock (true=on).
984  */
985 void
986 FGBFI::setAPAltitudeLock (bool lock)
987 {
988   current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_LOCK);
989   current_autopilot->set_AltitudeEnabled(lock);
990 }
991
992
993 /**
994  * Get the autopilot target altitude in feet.
995  */
996 double
997 FGBFI::getAPAltitude ()
998 {
999   return current_autopilot->get_TargetAltitude() * METER_TO_FEET;
1000 }
1001
1002
1003 /**
1004  * Set the autopilot target altitude in feet.
1005  */
1006 void
1007 FGBFI::setAPAltitude (double altitude)
1008 {
1009     current_autopilot->set_TargetAltitude( altitude );
1010 }
1011
1012
1013 /**
1014  * Get the autopilot heading lock (true=on).
1015  */
1016 bool
1017 FGBFI::getAPHeadingLock ()
1018 {
1019     return
1020       (current_autopilot->get_HeadingEnabled() &&
1021        current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_LOCK);
1022 }
1023
1024
1025 /**
1026  * Set the autopilot heading lock (true=on).
1027  */
1028 void
1029 FGBFI::setAPHeadingLock (bool lock)
1030 {
1031   if (lock) {
1032                                 // We need to do this so that
1033                                 // it's possible to lock onto a
1034                                 // heading other than the current
1035                                 // heading.
1036     double heading = getAPHeadingMag();
1037     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_LOCK);
1038     current_autopilot->set_HeadingEnabled(true);
1039     setAPHeadingMag(heading);
1040   } else if (current_autopilot->get_HeadingMode() ==
1041              FGAutopilot::FG_HEADING_LOCK) {
1042     current_autopilot->set_HeadingEnabled(false);
1043   }
1044 }
1045
1046
1047 /**
1048  * Get the autopilot target heading in degrees.
1049  */
1050 double
1051 FGBFI::getAPHeading ()
1052 {
1053   return current_autopilot->get_TargetHeading();
1054 }
1055
1056
1057 /**
1058  * Set the autopilot target heading in degrees.
1059  */
1060 void
1061 FGBFI::setAPHeading (double heading)
1062 {
1063   current_autopilot->set_TargetHeading( heading );
1064 }
1065
1066
1067 /**
1068  * Get the autopilot target heading in degrees.
1069  */
1070 double
1071 FGBFI::getAPHeadingMag ()
1072 {
1073   return current_autopilot->get_TargetHeading() - getMagVar();
1074 }
1075
1076
1077 /**
1078  * Set the autopilot target heading in degrees.
1079  */
1080 void
1081 FGBFI::setAPHeadingMag (double heading)
1082 {
1083   current_autopilot->set_TargetHeading( heading + getMagVar() );
1084 }
1085
1086
1087 /**
1088  * Return true if the autopilot is locked to NAV1.
1089  */
1090 bool
1091 FGBFI::getAPNAV1Lock ()
1092 {
1093   return
1094     (current_autopilot->get_HeadingEnabled() &&
1095      current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_NAV1);
1096 }
1097
1098
1099 /**
1100  * Set the autopilot NAV1 lock.
1101  */
1102 void
1103 FGBFI::setAPNAV1Lock (bool lock)
1104 {
1105   if (lock) {
1106     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_NAV1);
1107     current_autopilot->set_HeadingEnabled(true);
1108   } else if (current_autopilot->get_HeadingMode() ==
1109              FGAutopilot::FG_HEADING_NAV1) {
1110     current_autopilot->set_HeadingEnabled(false);
1111   }
1112 }
1113
1114
1115 \f
1116 ////////////////////////////////////////////////////////////////////////
1117 // Radio navigation.
1118 ////////////////////////////////////////////////////////////////////////
1119
1120 double
1121 FGBFI::getNAV1Freq ()
1122 {
1123   return current_radiostack->get_nav1_freq();
1124 }
1125
1126 double
1127 FGBFI::getNAV1AltFreq ()
1128 {
1129   return current_radiostack->get_nav1_alt_freq();
1130 }
1131
1132 double
1133 FGBFI::getNAV1Radial ()
1134 {
1135   return current_radiostack->get_nav1_radial();
1136 }
1137
1138 double
1139 FGBFI::getNAV1SelRadial ()
1140 {
1141   return current_radiostack->get_nav1_sel_radial();
1142 }
1143
1144 double
1145 FGBFI::getNAV1DistDME ()
1146 {
1147   return current_radiostack->get_nav1_dme_dist();
1148 }
1149
1150 bool
1151 FGBFI::getNAV1InRange ()
1152 {
1153   return current_radiostack->get_nav1_inrange();
1154 }
1155
1156 bool
1157 FGBFI::getNAV1DMEInRange ()
1158 {
1159   return (current_radiostack->get_nav1_inrange() &&
1160           current_radiostack->get_nav1_has_dme());
1161 }
1162
1163 double
1164 FGBFI::getNAV2Freq ()
1165 {
1166   return current_radiostack->get_nav2_freq();
1167 }
1168
1169 double
1170 FGBFI::getNAV2AltFreq ()
1171 {
1172   return current_radiostack->get_nav2_alt_freq();
1173 }
1174
1175 double
1176 FGBFI::getNAV2Radial ()
1177 {
1178   return current_radiostack->get_nav2_radial();
1179 }
1180
1181 double
1182 FGBFI::getNAV2SelRadial ()
1183 {
1184   return current_radiostack->get_nav2_sel_radial();
1185 }
1186
1187 double
1188 FGBFI::getNAV2DistDME ()
1189 {
1190   return current_radiostack->get_nav2_dme_dist();
1191 }
1192
1193 bool
1194 FGBFI::getNAV2InRange ()
1195 {
1196   return current_radiostack->get_nav2_inrange();
1197 }
1198
1199 bool
1200 FGBFI::getNAV2DMEInRange ()
1201 {
1202   return (current_radiostack->get_nav2_inrange() &&
1203           current_radiostack->get_nav2_has_dme());
1204 }
1205
1206 double
1207 FGBFI::getADFFreq ()
1208 {
1209   return current_radiostack->get_adf_freq();
1210 }
1211
1212 double
1213 FGBFI::getADFAltFreq ()
1214 {
1215   return current_radiostack->get_adf_alt_freq();
1216 }
1217
1218 double
1219 FGBFI::getADFRotation ()
1220 {
1221   return current_radiostack->get_adf_rotation();
1222 }
1223
1224 void
1225 FGBFI::setNAV1Freq (double freq)
1226 {
1227   current_radiostack->set_nav1_freq(freq);
1228 }
1229
1230 void
1231 FGBFI::setNAV1AltFreq (double freq)
1232 {
1233   current_radiostack->set_nav1_alt_freq(freq);
1234 }
1235
1236 void
1237 FGBFI::setNAV1SelRadial (double radial)
1238 {
1239   current_radiostack->set_nav1_sel_radial(radial);
1240 }
1241
1242 void
1243 FGBFI::setNAV2Freq (double freq)
1244 {
1245   current_radiostack->set_nav2_freq(freq);
1246 }
1247
1248 void
1249 FGBFI::setNAV2AltFreq (double freq)
1250 {
1251   current_radiostack->set_nav2_alt_freq(freq);
1252 }
1253
1254 void
1255 FGBFI::setNAV2SelRadial (double radial)
1256 {
1257   current_radiostack->set_nav2_sel_radial(radial);
1258 }
1259
1260 void
1261 FGBFI::setADFFreq (double freq)
1262 {
1263   current_radiostack->set_adf_freq(freq);
1264 }
1265
1266 void
1267 FGBFI::setADFAltFreq (double freq)
1268 {
1269   current_radiostack->set_adf_alt_freq(freq);
1270 }
1271
1272 void
1273 FGBFI::setADFRotation (double rot)
1274 {
1275   current_radiostack->set_adf_rotation(rot);
1276 }
1277
1278
1279 \f
1280 ////////////////////////////////////////////////////////////////////////
1281 // GPS
1282 ////////////////////////////////////////////////////////////////////////
1283
1284
1285 /**
1286  * Get the autopilot GPS lock (true=on).
1287  */
1288 bool
1289 FGBFI::getGPSLock ()
1290 {
1291   return (current_autopilot->get_HeadingEnabled() &&
1292           (current_autopilot->get_HeadingMode() ==
1293            FGAutopilot::FG_HEADING_WAYPOINT ));
1294 }
1295
1296
1297 /**
1298  * Set the autopilot GPS lock (true=on).
1299  */
1300 void
1301 FGBFI::setGPSLock (bool lock)
1302 {
1303   if (lock) {
1304     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_WAYPOINT);
1305     current_autopilot->set_HeadingEnabled(true);
1306   } else if (current_autopilot->get_HeadingMode() ==
1307              FGAutopilot::FG_HEADING_WAYPOINT) {
1308     current_autopilot->set_HeadingEnabled(false);
1309   }
1310 }
1311
1312
1313 /**
1314  * Get the GPS target airport code.
1315  */
1316 const string
1317 FGBFI::getTargetAirport ()
1318 {
1319   return current_options.get_airport_id();
1320 }
1321
1322
1323 /**
1324  * Set the GPS target airport code.
1325  */
1326 void
1327 FGBFI::setTargetAirport (const string &airportId)
1328 {
1329   current_options.set_airport_id(airportId);
1330 }
1331
1332
1333 /**
1334  * Get the GPS target latitude in degrees (negative for south).
1335  */
1336 double
1337 FGBFI::getGPSTargetLatitude ()
1338 {
1339     return current_autopilot->get_TargetLatitude();
1340 }
1341
1342
1343 /**
1344  * Set the GPS target latitude in degrees (negative for south).
1345  */
1346 void
1347 FGBFI::setGPSTargetLatitude (double latitude)
1348 {
1349   current_autopilot->set_TargetLatitude( latitude );
1350 }
1351
1352
1353 /**
1354  * Get the GPS target longitude in degrees (negative for west).
1355  */
1356 double
1357 FGBFI::getGPSTargetLongitude ()
1358 {
1359   return current_autopilot->get_TargetLongitude();
1360 }
1361
1362
1363 /**
1364  * Set the GPS target longitude in degrees (negative for west).
1365  */
1366 void
1367 FGBFI::setGPSTargetLongitude (double longitude)
1368 {
1369   current_autopilot->set_TargetLongitude( longitude );
1370 }
1371
1372
1373 \f
1374 ////////////////////////////////////////////////////////////////////////
1375 // Weather
1376 ////////////////////////////////////////////////////////////////////////
1377
1378
1379 /**
1380  * Get the current visible (units??).
1381  */
1382 double
1383 FGBFI::getVisibility ()
1384 {
1385 #ifndef FG_OLD_WEATHER
1386   return WeatherDatabase->getWeatherVisibility();
1387 #else
1388   return current_weather.get_visibility();
1389 #endif
1390 }
1391
1392
1393 /**
1394  * Check whether clouds are enabled.
1395  */
1396 bool
1397 FGBFI::getClouds ()
1398 {
1399   return current_options.get_clouds();
1400 }
1401
1402
1403 /**
1404  * Check the height of the clouds ASL (units?).
1405  */
1406 double
1407 FGBFI::getCloudsASL ()
1408 {
1409   return current_options.get_clouds_asl();
1410 }
1411
1412
1413 /**
1414  * Set the current visibility (units??).
1415  */
1416 void
1417 FGBFI::setVisibility (double visibility)
1418 {
1419 #ifndef FG_OLD_WEATHER
1420   WeatherDatabase->setWeatherVisibility(visibility);
1421 #else
1422   current_weather.set_visibility(visibility);
1423 #endif
1424 }
1425
1426
1427 /**
1428  * Switch clouds on or off.
1429  */
1430 void
1431 FGBFI::setClouds (bool clouds)
1432 {
1433   cout << "Set clouds to " << clouds << endl;
1434   current_options.set_clouds(clouds);
1435   needReinit();
1436 }
1437
1438
1439 /**
1440  * Set the cloud height.
1441  */
1442 void
1443 FGBFI::setCloudsASL (double cloudsASL)
1444 {
1445   current_options.set_clouds_asl(cloudsASL);
1446   needReinit();
1447 }
1448
1449
1450 \f
1451 ////////////////////////////////////////////////////////////////////////
1452 // Time
1453 ////////////////////////////////////////////////////////////////////////
1454
1455 /**
1456  * Return the magnetic variation
1457  */
1458 double
1459 FGBFI::getMagVar ()
1460 {
1461   return globals->get_mag()->get_magvar() * RAD_TO_DEG;
1462 }
1463
1464
1465 /**
1466  * Return the magnetic variation
1467  */
1468 double
1469 FGBFI::getMagDip ()
1470 {
1471   return globals->get_mag()->get_magdip() * RAD_TO_DEG;
1472 }
1473
1474
1475 // end of bfi.cxx
1476