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