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