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