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