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