]> git.mxchange.org Git - flightgear.git/blob - src/Main/bfi.cxx
Integrated FGOptions with the property manager (by David Megginson)
[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 CLASS IS DEPRECATED; USE THE PROPERTY MANAGER INSTEAD.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License as
11 // published by the Free Software Foundation; either version 2 of the
12 // License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 // General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 //
23 // $Id$
24
25 #include "fgfs.hxx"
26
27 #include <simgear/constants.h>
28 #include <simgear/debug/logstream.hxx>
29 #include <simgear/ephemeris/ephemeris.hxx>
30 #include <simgear/math/sg_types.hxx>
31 #include <simgear/misc/props.hxx>
32 #include <simgear/timing/sg_time.hxx>
33
34 #include <Aircraft/aircraft.hxx>
35 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
36 #include <Controls/controls.hxx>
37 #include <Autopilot/newauto.hxx>
38 #include <Scenery/scenery.hxx>
39 #include <Time/light.hxx>
40 #include <Time/event.hxx>
41 #include <Time/sunpos.hxx>
42 #include <Time/tmp.hxx>
43 #include <Cockpit/radiostack.hxx>
44 #include <Cockpit/panel.hxx>
45 #ifndef FG_OLD_WEATHER
46 #  include <WeatherCM/FGLocalWeatherDatabase.h>
47 #else
48 #  include <Weather/weather.hxx>
49 #endif
50
51 #include "globals.hxx"
52 #include "fg_init.hxx"
53 #include "fg_props.hxx"
54
55 FG_USING_NAMESPACE(std);
56
57
58 #include "bfi.hxx"
59
60
61 \f
62 ////////////////////////////////////////////////////////////////////////
63 // Static variables.
64 ////////////////////////////////////////////////////////////////////////
65
66                                 // Yech -- not thread-safe, etc. etc.
67 static bool _needReinit = false;
68 static string _temp;
69
70 static inline void needReinit ()
71 {
72   _needReinit = true;
73 }
74
75
76 /**
77  * Reinitialize FGFS to use the new BFI settings.
78  */
79 static inline void
80 reinit ()
81 {
82                                 // Save the state of everything
83                                 // that's going to get clobbered
84                                 // when we reinit the subsystems.
85
86   FG_LOG(FG_GENERAL, FG_INFO, "Starting BFI reinit");
87
88                                 // TODO: add more AP stuff
89   bool apHeadingLock = FGBFI::getAPHeadingLock();
90   double apHeadingMag = FGBFI::getAPHeadingMag();
91   bool apAltitudeLock = FGBFI::getAPAltitudeLock();
92   double apAltitude = FGBFI::getAPAltitude();
93   const string &targetAirport = FGBFI::getTargetAirport();
94   bool gpsLock = FGBFI::getGPSLock();
95   // double gpsLatitude = FGBFI::getGPSTargetLatitude();
96   // double gpsLongitude = FGBFI::getGPSTargetLongitude();
97
98   FGBFI::setTargetAirport("");
99
100   fgReInitSubsystems();
101
102                                 // FIXME: this is wrong.
103                                 // All of these are scheduled events,
104                                 // and it should be possible to force
105                                 // them all to run once.
106   fgUpdateSunPos();
107   fgUpdateMoonPos();
108   cur_light_params.Update();
109   fgUpdateLocalTime();
110   fgUpdateWeatherDatabase();
111   current_radiostack->search();
112
113                                 // Restore all of the old states.
114   FGBFI::setAPHeadingLock(apHeadingLock);
115   FGBFI::setAPHeadingMag(apHeadingMag);
116   FGBFI::setAPAltitudeLock(apAltitudeLock);
117   FGBFI::setAPAltitude(apAltitude);
118   FGBFI::setTargetAirport(targetAirport);
119   FGBFI::setGPSLock(gpsLock);
120
121   _needReinit = false;
122
123   FG_LOG(FG_GENERAL, FG_INFO, "Ending BFI reinit");
124 }
125
126 // BEGIN: kludge 2000-12-07
127 // This is a kludge around a LaRCsim problem; see setAltitude()
128 // for details.
129 static int _altitude_countdown = 0;
130 static double _requested_altitude = -9999;
131 static bool _saved_freeze = false;
132 static inline void _check_altitude ()
133 {
134   if (_altitude_countdown > 0) {
135     _altitude_countdown--;
136     if (_altitude_countdown == 0) {
137       current_aircraft.fdm_state->set_Altitude(_requested_altitude);
138       globals->set_freeze(_saved_freeze);
139     }
140   }
141 }
142
143 static int _lighting_countdown = 0;
144 static inline void _check_lighting ()
145 {
146   if (_lighting_countdown > 0) {
147     _lighting_countdown--;
148     if (_lighting_countdown == 0)
149       fgUpdateSkyAndLightingParams();
150   }
151 }
152 // END: kludge
153
154
155 // BEGIN: kludge
156 // Allow the view to be set from two axes (i.e. a joystick hat)
157 // This needs to be in FGViewer itself, somehow.
158 static double axisLong = 0.0;
159 static double axisLat = 0.0;
160
161 static inline void
162 _set_view_from_axes ()
163 {
164                                 // Take no action when hat is centered
165   if (axisLong == 0 && axisLat == 0)
166     return;
167
168   double viewDir = 0;
169
170   if (axisLong < 0) {           // Longitudinal axis forward
171     if (axisLat < 0)
172       viewDir = 45;
173     else if (axisLat > 0)
174       viewDir = 315;
175     else
176       viewDir = 0;
177   } else if (axisLong > 0) {    // Longitudinal axis backward
178     if (axisLat < 0)
179       viewDir = 135;
180     else if (axisLat > 0)
181       viewDir = 225;
182     else
183       viewDir = 180;
184   } else {                      // Longitudinal axis neutral
185     if (axisLat < 0)
186       viewDir = 90;
187     else
188       viewDir = 270;
189   }
190
191   globals->get_current_view()->set_goal_view_offset(viewDir*DEG_TO_RAD);
192 //   globals->get_current_view()->set_view_offset(viewDir*DEG_TO_RAD);
193 }
194
195 // END: kludge
196
197
198 \f
199 ////////////////////////////////////////////////////////////////////////
200 // Local functions
201 ////////////////////////////////////////////////////////////////////////
202
203 /**
204  * Initialize the BFI by binding its functions to properties.
205  *
206  * TODO: perhaps these should migrate into the individual modules
207  * (i.e. they should register themselves).
208  */
209 void
210 FGBFI::init ()
211 {
212   FG_LOG(FG_GENERAL, FG_INFO, "Starting BFI init");
213                                 // Simulation
214 //   fgTie("/sim/flight-model", getFlightModel, setFlightModel);
215 //   fgTie("/sim/aircraft", getAircraft, setAircraft);
216   fgTie("/sim/aircraft-dir", getAircraftDir, setAircraftDir);
217   fgTie("/sim/time/gmt", getDateString, setDateString);
218   fgTie("/sim/time/gmt-string", getGMTString);
219 //   fgTie("/sim/hud/visibility", getHUDVisible, setHUDVisible);
220
221                                 // Position
222 //   fgTie("/position/airport-id", getTargetAirport, setTargetAirport);
223   fgTie("/position/latitude", getLatitude, setLatitude);
224   fgTie("/position/longitude", getLongitude, setLongitude);
225   fgTie("/position/altitude", getAltitude, setAltitude);
226   fgTie("/position/altitude-agl", getAGL);
227
228                                 // Orientation
229   fgTie("/orientation/heading", getHeading, setHeading);
230   fgTie("/orientation/heading-magnetic", getHeadingMag);
231   fgTie("/orientation/pitch", getPitch, setPitch);
232   fgTie("/orientation/roll", getRoll, setRoll);
233
234                                 // Engine
235   fgTie("/engines/engine0/rpm", getRPM);
236   fgTie("/engines/engine0/egt", getEGT);
237   fgTie("/engines/engine0/cht", getCHT);
238   fgTie("/engines/engine0/mp", getMP);
239
240                                 // Velocities
241   fgTie("/velocities/airspeed", getAirspeed, setAirspeed);
242   fgTie("/velocities/side-slip", getSideSlip);
243   fgTie("/velocities/vertical-speed", getVerticalSpeed);
244   fgTie("/velocities/speed-north", getSpeedNorth);
245   fgTie("/velocities/speed-east", getSpeedEast);
246   fgTie("/velocities/speed-down", getSpeedDown);
247
248                                 // Autopilot
249   fgTie("/autopilot/locks/altitude", getAPAltitudeLock, setAPAltitudeLock);
250   fgTie("/autopilot/settings/altitude", getAPAltitude, setAPAltitude);
251   fgTie("/autopilot/locks/heading", getAPHeadingLock, setAPHeadingLock);
252   fgTie("/autopilot/settings/heading", getAPHeading, setAPHeading);
253   fgTie("/autopilot/settings/heading-magnetic",
254              getAPHeadingMag, setAPHeadingMag);
255   fgTie("/autopilot/locks/nav1", getAPNAV1Lock, setAPNAV1Lock);
256
257                                 // Weather
258   fgTie("/environment/visibility", getVisibility, setVisibility);
259   fgTie("/environment/wind-north", getWindNorth, setWindNorth);
260   fgTie("/environment/wind-east", getWindEast, setWindEast);
261   fgTie("/environment/wind-down", getWindDown, setWindDown);
262
263                                 // View
264   fgTie("/sim/view/axes/long", (double(*)())0, setViewAxisLong);
265   fgTie("/sim/view/axes/lat", (double(*)())0, setViewAxisLat);
266
267   _altitude_countdown = 0;
268   globals->set_freeze(_saved_freeze);
269   _needReinit = false;
270
271   FG_LOG(FG_GENERAL, FG_INFO, "Ending BFI init");
272 }
273
274
275 /**
276  * Reinitialize FGFS if required.
277  *
278  * Some changes (especially those in aircraft position) require that
279  * FGFS be reinitialized afterwards.  Rather than reinitialize after
280  * every change, the setter methods simply set a flag so that there
281  * can be a single reinit at the end of the frame.
282  */
283 void
284 FGBFI::update ()
285 {
286   _check_altitude();
287   _check_lighting();
288   _set_view_from_axes();
289   if (_needReinit) {
290     reinit();
291   }
292 }
293
294
295 \f
296 ////////////////////////////////////////////////////////////////////////
297 // Simulation.
298 ////////////////////////////////////////////////////////////////////////
299
300
301 /**
302  * Return the flight model as an integer.
303  *
304  * TODO: use a string instead.
305  */
306 int
307 FGBFI::getFlightModel ()
308 {
309   return globals->get_options()->get_flight_model();
310 }
311
312
313 /**
314  * Return the current aircraft as a string.
315  */
316 string
317 FGBFI::getAircraft ()
318 {
319   _temp = globals->get_options()->get_aircraft();
320   return _temp;
321 }
322
323
324 /**
325  * Return the current aircraft directory (UIUC) as a string.
326  */
327 string 
328 FGBFI::getAircraftDir ()
329 {
330   _temp = aircraft_dir;
331   return _temp;
332 }
333
334
335 /**
336  * Set the flight model as an integer.
337  *
338  * TODO: use a string instead.
339  */
340 void
341 FGBFI::setFlightModel (int model)
342 {
343   if (getFlightModel() != model) {
344     globals->get_options()->set_flight_model(model);
345     needReinit();
346   }
347 }
348
349
350 /**
351  * Set the current aircraft.
352  */
353 void
354 FGBFI::setAircraft (string aircraft)
355 {
356   if (getAircraft() != aircraft) {
357     globals->get_options()->set_aircraft(aircraft);
358     needReinit();
359   }
360 }
361
362
363 /**
364  * Set the current aircraft directory (UIUC).
365  */
366 void
367 FGBFI::setAircraftDir (string dir)
368 {
369   if (getAircraftDir() != dir) {
370     aircraft_dir = dir;
371     needReinit();
372   }
373 }
374
375
376 /**
377  * Return the current Zulu time.
378  */
379 string 
380 FGBFI::getDateString ()
381 {
382   string out;
383   char buf[64];
384   struct tm * t = globals->get_time_params()->getGmt();
385   sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
386           t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
387           t->tm_hour, t->tm_min, t->tm_sec);
388   out = buf;
389   return out;
390 }
391
392
393 /**
394  * Set the current Zulu time.
395  */
396 void
397 FGBFI::setDateString (string date_string)
398 // FGBFI::setTimeGMT (time_t time)
399 {
400   SGTime * st = globals->get_time_params();
401   struct tm * current_time = st->getGmt();
402   struct tm new_time;
403
404                                 // Scan for basic ISO format
405                                 // YYYY-MM-DDTHH:MM:SS
406   int ret = sscanf(date_string.c_str(), "%d-%d-%dT%d:%d:%d",
407                    &(new_time.tm_year), &(new_time.tm_mon),
408                    &(new_time.tm_mday), &(new_time.tm_hour),
409                    &(new_time.tm_min), &(new_time.tm_sec));
410
411                                 // Be pretty picky about this, so
412                                 // that strange things don't happen
413                                 // if the save file has been edited
414                                 // by hand.
415   if (ret != 6) {
416     FG_LOG(FG_INPUT, FG_ALERT, "Date/time string " << date_string
417            << " not in YYYY-MM-DDTHH:MM:SS format; skipped");
418     return;
419   }
420
421                                 // OK, it looks like we got six
422                                 // values, one way or another.
423   new_time.tm_year -= 1900;
424   new_time.tm_mon -= 1;
425
426                                 // Now, tell flight gear to use
427                                 // the new time.  This was far
428                                 // too difficult, by the way.
429   long int warp =
430     mktime(&new_time) - mktime(current_time) + globals->get_warp();
431   double lon = current_aircraft.fdm_state->get_Longitude();
432   double lat = current_aircraft.fdm_state->get_Latitude();
433   double alt = current_aircraft.fdm_state->get_Altitude() * FEET_TO_METER;
434   globals->set_warp(warp);
435   st->update(lon, lat, warp);
436   fgUpdateSkyAndLightingParams();
437 }
438
439
440 /**
441  * Return the GMT as a string.
442  */
443 string 
444 FGBFI::getGMTString ()
445 {
446   string out;
447   char buf[16];
448   struct tm * t = globals->get_time_params()->getGmt();
449   sprintf(buf, " %.2d:%.2d:%.2d",
450           t->tm_hour, t->tm_min, t->tm_sec);
451   out = buf;
452   return out;
453 }
454
455
456 /**
457  * Return true if the HUD is visible.
458  */
459 bool
460 FGBFI::getHUDVisible ()
461 {
462   return globals->get_options()->get_hud_status();
463 }
464
465
466 /**
467  * Ensure that the HUD is visible or hidden.
468  */
469 void
470 FGBFI::setHUDVisible (bool visible)
471 {
472   globals->get_options()->set_hud_status(visible);
473 }
474
475
476 \f
477 ////////////////////////////////////////////////////////////////////////
478 // Position
479 ////////////////////////////////////////////////////////////////////////
480
481
482 /**
483  * Return the current latitude in degrees (negative for south).
484  */
485 double
486 FGBFI::getLatitude ()
487 {
488   return current_aircraft.fdm_state->get_Latitude() * RAD_TO_DEG;
489 }
490
491
492 /**
493  * Set the current latitude in degrees (negative for south).
494  */
495 void
496 FGBFI::setLatitude (double latitude)
497 {
498   current_aircraft.fdm_state->set_Latitude(latitude * DEG_TO_RAD);
499   fgUpdateSkyAndLightingParams();
500   if (_lighting_countdown <= 0)
501     _lighting_countdown = 5;
502 }
503
504
505 /**
506  * Return the current longitude in degrees (negative for west).
507  */
508 double
509 FGBFI::getLongitude ()
510 {
511   return current_aircraft.fdm_state->get_Longitude() * RAD_TO_DEG;
512 }
513
514
515 /**
516  * Set the current longitude in degrees (negative for west).
517  */
518 void
519 FGBFI::setLongitude (double longitude)
520 {
521   current_aircraft.fdm_state->set_Longitude(longitude * DEG_TO_RAD);
522   fgUpdateSkyAndLightingParams();
523   if (_lighting_countdown <= 0)
524     _lighting_countdown = 5;
525 }
526
527
528 /**
529  * Return the current altitude in feet.
530  */
531 double
532 FGBFI::getAltitude ()
533 {
534   return current_aircraft.fdm_state->get_Altitude();
535 }
536
537
538
539 /**
540  * Return the current altitude in above the terrain.
541  */
542 double
543 FGBFI::getAGL ()
544 {
545   return current_aircraft.fdm_state->get_Altitude()
546          - (scenery.cur_elev * METER_TO_FEET);
547 }
548
549
550 /**
551  * Set the current altitude in feet.
552  */
553 void
554 FGBFI::setAltitude (double altitude)
555 {
556   current_aircraft.fdm_state->set_Altitude(altitude);
557
558                                 // 2000-12-07
559                                 // This is an ugly kludge around a
560                                 // LaRCsim problem; if the
561                                 // requested altitude cannot be
562                                 // set right away (because it's
563                                 // below the last-calculated ground
564                                 // level), pause FGFS, wait for
565                                 // five frames, and then try again.
566   if (_altitude_countdown <= 0 &&
567       fabs(getAltitude() - altitude) > 5.0) {
568     _altitude_countdown = 5;
569     _requested_altitude = altitude;
570     _saved_freeze = globals->get_freeze();
571     globals->set_freeze(true);
572   }
573 }
574
575
576 \f
577 ////////////////////////////////////////////////////////////////////////
578 // Attitude
579 ////////////////////////////////////////////////////////////////////////
580
581
582 /**
583  * Return the current heading in degrees.
584  */
585 double
586 FGBFI::getHeading ()
587 {
588   return current_aircraft.fdm_state->get_Psi() * RAD_TO_DEG;
589 }
590
591
592 /**
593  * Return the current heading in degrees.
594  */
595 double
596 FGBFI::getHeadingMag ()
597 {
598   return current_aircraft.fdm_state->get_Psi() * RAD_TO_DEG - getMagVar();
599 }
600
601
602 /**
603  * Set the current heading in degrees.
604  */
605 void
606 FGBFI::setHeading (double heading)
607 {
608   FGInterface * fdm = current_aircraft.fdm_state;
609   fdm->set_Euler_Angles(fdm->get_Phi(), fdm->get_Theta(),
610                         heading * DEG_TO_RAD);
611 }
612
613
614 /**
615  * Return the current pitch in degrees.
616  */
617 double
618 FGBFI::getPitch ()
619 {
620   return current_aircraft.fdm_state->get_Theta() * RAD_TO_DEG;
621 }
622
623
624 /**
625  * Set the current pitch in degrees.
626  */
627 void
628 FGBFI::setPitch (double pitch)
629 {
630   FGInterface * fdm = current_aircraft.fdm_state;
631   fdm->set_Euler_Angles(fdm->get_Phi(), pitch * DEG_TO_RAD, fdm->get_Psi());
632 }
633
634
635 /**
636  * Return the current roll in degrees.
637  */
638 double
639 FGBFI::getRoll ()
640 {
641   return current_aircraft.fdm_state->get_Phi() * RAD_TO_DEG;
642 }
643
644
645 /**
646  * Set the current roll in degrees.
647  */
648 void
649 FGBFI::setRoll (double roll)
650 {
651   FGInterface * fdm = current_aircraft.fdm_state;
652   fdm->set_Euler_Angles(roll * DEG_TO_RAD, fdm->get_Theta(), fdm->get_Psi());
653 }
654
655
656 /**
657  * Return the current engine0 rpm
658  */
659 double
660 FGBFI::getRPM ()
661 {
662   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
663       return current_aircraft.fdm_state->get_engine(0)->get_RPM();
664   } else {
665       return 0.0;
666   }
667 }
668
669
670 /**
671  * Set the current engine0 rpm
672  */
673 void
674 FGBFI::setRPM (double rpm)
675 {
676     if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
677         if (getRPM() != rpm) {
678             current_aircraft.fdm_state->get_engine(0)->set_RPM( rpm );
679         }
680     }
681 }
682
683
684 /**
685  * Return the current engine0 EGT.
686  */
687 double
688 FGBFI::getEGT ()
689 {
690   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
691       return current_aircraft.fdm_state->get_engine(0)->get_EGT();
692   } else {
693       return 0.0;
694   }
695 }
696
697
698 /**
699  * Return the current engine0 CHT.
700  */
701 double
702 FGBFI::getCHT ()
703 {
704   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
705       return current_aircraft.fdm_state->get_engine(0)->get_CHT();
706   } else {
707       return 0.0;
708   }
709 }
710
711
712 /**
713  * Return the current engine0 CHT.
714  */
715 double
716 FGBFI::getMP ()
717 {
718   if ( current_aircraft.fdm_state->get_engine(0) != NULL ) {
719       return current_aircraft.fdm_state->get_engine(0)->get_Manifold_Pressure();
720   } else {
721       return 0.0;
722   }
723 }
724
725
726 \f
727 ////////////////////////////////////////////////////////////////////////
728 // Velocities
729 ////////////////////////////////////////////////////////////////////////
730
731
732 /**
733  * Return the current airspeed in knots.
734  */
735 double
736 FGBFI::getAirspeed ()
737 {
738                                 // FIXME: should we add speed-up?
739   return current_aircraft.fdm_state->get_V_calibrated_kts();
740 }
741
742
743 /**
744  * Set the calibrated airspeed in knots.
745  */
746 void
747 FGBFI::setAirspeed (double speed)
748 {
749   current_aircraft.fdm_state->set_V_calibrated_kts(speed);
750 }
751
752
753 /**
754  * Return the current sideslip (FIXME: units unknown).
755  */
756 double
757 FGBFI::getSideSlip ()
758 {
759   return current_aircraft.fdm_state->get_Beta();
760 }
761
762
763 /**
764  * Return the current climb rate in feet/minute
765  */
766 double
767 FGBFI::getVerticalSpeed ()
768 {
769                                 // What about meters?
770   return current_aircraft.fdm_state->get_Climb_Rate() * 60.0;
771 }
772
773
774 /**
775  * Get the current north velocity (units??).
776  */
777 double
778 FGBFI::getSpeedNorth ()
779 {
780   return current_aircraft.fdm_state->get_V_north();
781 }
782
783
784 // /**
785 //  * Set the current north velocity (units??).
786 //  */
787 // void
788 // FGBFI::setSpeedNorth (double speed)
789 // {
790 //   FGInterface * fdm = current_aircraft.fdm_state;
791 // //   fdm->set_Velocities_Local(speed, fdm->get_V_east(), fdm->get_V_down());
792 // }
793
794
795 /**
796  * Get the current east velocity (units??).
797  */
798 double
799 FGBFI::getSpeedEast ()
800 {
801   return current_aircraft.fdm_state->get_V_east();
802 }
803
804
805 // /**
806 //  * Set the current east velocity (units??).
807 //  */
808 // void
809 // FGBFI::setSpeedEast (double speed)
810 // {
811 //   FGInterface * fdm = current_aircraft.fdm_state;
812 // //   fdm->set_Velocities_Local(fdm->get_V_north(), speed, fdm->get_V_down());
813 // }
814
815
816 /**
817  * Get the current down velocity (units??).
818  */
819 double
820 FGBFI::getSpeedDown ()
821 {
822   return current_aircraft.fdm_state->get_V_down();
823 }
824
825
826 // /**
827 //  * Set the current down velocity (units??).
828 //  */
829 // void
830 // FGBFI::setSpeedDown (double speed)
831 // {
832 //   FGInterface * fdm = current_aircraft.fdm_state;
833 // //   fdm->set_Velocities_Local(fdm->get_V_north(), fdm->get_V_east(), speed);
834 // }
835
836
837 \f
838 ////////////////////////////////////////////////////////////////////////
839 // Controls
840 ////////////////////////////////////////////////////////////////////////
841
842 #if 0
843
844 /**
845  * Get the throttle setting, from 0.0 (none) to 1.0 (full).
846  */
847 double
848 FGBFI::getThrottle ()
849 {
850                                 // FIXME: add engine selector
851   return controls.get_throttle(0);
852 }
853
854
855 /**
856  * Set the throttle, from 0.0 (none) to 1.0 (full).
857  */
858 void
859 FGBFI::setThrottle (double throttle)
860 {
861                                 // FIXME: allow engine selection
862   controls.set_throttle(0, throttle);
863 }
864
865
866 /**
867  * Get the fuel mixture setting, from 0.0 (none) to 1.0 (full).
868  */
869 double
870 FGBFI::getMixture ()
871 {
872                                 // FIXME: add engine selector
873   return controls.get_mixture(0);
874 }
875
876
877 /**
878  * Set the fuel mixture, from 0.0 (none) to 1.0 (full).
879  */
880 void
881 FGBFI::setMixture (double mixture)
882 {
883                                 // FIXME: allow engine selection
884   controls.set_mixture(0, mixture);
885 }
886
887
888 /**
889  * Get the propellor pitch setting, from 0.0 (none) to 1.0 (full).
890  */
891 double
892 FGBFI::getPropAdvance ()
893 {
894                                 // FIXME: add engine selector
895   return controls.get_prop_advance(0);
896 }
897
898
899 /**
900  * Set the propellor pitch, from 0.0 (none) to 1.0 (full).
901  */
902 void
903 FGBFI::setPropAdvance (double pitch)
904 {
905                                 // FIXME: allow engine selection
906   controls.set_prop_advance(0, pitch);
907 }
908
909
910 /**
911  * Get the flaps setting, from 0.0 (none) to 1.0 (full).
912  */
913 double
914 FGBFI::getFlaps ()
915 {
916   return controls.get_flaps();
917 }
918
919
920 /**
921  * Set the flaps, from 0.0 (none) to 1.0 (full).
922  */
923 void
924 FGBFI::setFlaps (double flaps)
925 {
926                                 // FIXME: clamp?
927   controls.set_flaps(flaps);
928 }
929
930
931 /**
932  * Get the aileron, from -1.0 (left) to 1.0 (right).
933  */
934 double
935 FGBFI::getAileron ()
936 {
937   return controls.get_aileron();
938 }
939
940
941 /**
942  * Set the aileron, from -1.0 (left) to 1.0 (right).
943  */
944 void
945 FGBFI::setAileron (double aileron)
946 {
947                                 // FIXME: clamp?
948   controls.set_aileron(aileron);
949 }
950
951
952 /**
953  * Get the rudder setting, from -1.0 (left) to 1.0 (right).
954  */
955 double
956 FGBFI::getRudder ()
957 {
958   return controls.get_rudder();
959 }
960
961
962 /**
963  * Set the rudder, from -1.0 (left) to 1.0 (right).
964  */
965 void
966 FGBFI::setRudder (double rudder)
967 {
968                                 // FIXME: clamp?
969   controls.set_rudder(rudder);
970 }
971
972
973 /**
974  * Get the elevator setting, from -1.0 (down) to 1.0 (up).
975  */
976 double
977 FGBFI::getElevator ()
978 {
979   return controls.get_elevator();
980 }
981
982
983 /**
984  * Set the elevator, from -1.0 (down) to 1.0 (up).
985  */
986 void
987 FGBFI::setElevator (double elevator)
988 {
989                                 // FIXME: clamp?
990   controls.set_elevator(elevator);
991 }
992
993
994 /**
995  * Get the elevator trim, from -1.0 (down) to 1.0 (up).
996  */
997 double
998 FGBFI::getElevatorTrim ()
999 {
1000   return controls.get_elevator_trim();
1001 }
1002
1003
1004 /**
1005  * Set the elevator trim, from -1.0 (down) to 1.0 (up).
1006  */
1007 void
1008 FGBFI::setElevatorTrim (double trim)
1009 {
1010                                 // FIXME: clamp?
1011   controls.set_elevator_trim(trim);
1012 }
1013
1014
1015 /**
1016  * Get the highest brake setting, from 0.0 (none) to 1.0 (full).
1017  */
1018 double
1019 FGBFI::getBrakes ()
1020 {
1021   double b1 = getCenterBrake();
1022   double b2 = getLeftBrake();
1023   double b3 = getRightBrake();
1024   return (b1 > b2 ? (b1 > b3 ? b1 : b3) : (b2 > b3 ? b2 : b3));
1025 }
1026
1027
1028 /**
1029  * Set all brakes, from 0.0 (none) to 1.0 (full).
1030  */
1031 void
1032 FGBFI::setBrakes (double brake)
1033 {
1034   setCenterBrake(brake);
1035   setLeftBrake(brake);
1036   setRightBrake(brake);
1037 }
1038
1039
1040 /**
1041  * Get the center brake, from 0.0 (none) to 1.0 (full).
1042  */
1043 double
1044 FGBFI::getCenterBrake ()
1045 {
1046   return controls.get_brake(2);
1047 }
1048
1049
1050 /**
1051  * Set the center brake, from 0.0 (none) to 1.0 (full).
1052  */
1053 void
1054 FGBFI::setCenterBrake (double brake)
1055 {
1056   controls.set_brake(2, brake);
1057 }
1058
1059
1060 /**
1061  * Get the left brake, from 0.0 (none) to 1.0 (full).
1062  */
1063 double
1064 FGBFI::getLeftBrake ()
1065 {
1066   return controls.get_brake(0);
1067 }
1068
1069
1070 /**
1071  * Set the left brake, from 0.0 (none) to 1.0 (full).
1072  */
1073 void
1074 FGBFI::setLeftBrake (double brake)
1075 {
1076   controls.set_brake(0, brake);
1077 }
1078
1079
1080 /**
1081  * Get the right brake, from 0.0 (none) to 1.0 (full).
1082  */
1083 double
1084 FGBFI::getRightBrake ()
1085 {
1086   return controls.get_brake(1);
1087 }
1088
1089
1090 /**
1091  * Set the right brake, from 0.0 (none) to 1.0 (full).
1092  */
1093 void
1094 FGBFI::setRightBrake (double brake)
1095 {
1096   controls.set_brake(1, brake);
1097 }
1098
1099
1100 #endif
1101
1102 \f
1103 ////////////////////////////////////////////////////////////////////////
1104 // Autopilot
1105 ////////////////////////////////////////////////////////////////////////
1106
1107
1108 /**
1109  * Get the autopilot altitude lock (true=on).
1110  */
1111 bool
1112 FGBFI::getAPAltitudeLock ()
1113 {
1114     return current_autopilot->get_AltitudeEnabled();
1115 }
1116
1117
1118 /**
1119  * Set the autopilot altitude lock (true=on).
1120  */
1121 void
1122 FGBFI::setAPAltitudeLock (bool lock)
1123 {
1124   current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_LOCK);
1125   current_autopilot->set_AltitudeEnabled(lock);
1126 }
1127
1128
1129 /**
1130  * Get the autopilot target altitude in feet.
1131  */
1132 double
1133 FGBFI::getAPAltitude ()
1134 {
1135   return current_autopilot->get_TargetAltitude() * METER_TO_FEET;
1136 }
1137
1138
1139 /**
1140  * Set the autopilot target altitude in feet.
1141  */
1142 void
1143 FGBFI::setAPAltitude (double altitude)
1144 {
1145     current_autopilot->set_TargetAltitude( altitude );
1146 }
1147
1148
1149 /**
1150  * Get the autopilot heading lock (true=on).
1151  */
1152 bool
1153 FGBFI::getAPHeadingLock ()
1154 {
1155     return
1156       (current_autopilot->get_HeadingEnabled() &&
1157        current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_LOCK);
1158 }
1159
1160
1161 /**
1162  * Set the autopilot heading lock (true=on).
1163  */
1164 void
1165 FGBFI::setAPHeadingLock (bool lock)
1166 {
1167   if (lock) {
1168                                 // We need to do this so that
1169                                 // it's possible to lock onto a
1170                                 // heading other than the current
1171                                 // heading.
1172     double heading = getAPHeadingMag();
1173     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_LOCK);
1174     current_autopilot->set_HeadingEnabled(true);
1175     setAPHeadingMag(heading);
1176   } else if (current_autopilot->get_HeadingMode() ==
1177              FGAutopilot::FG_HEADING_LOCK) {
1178     current_autopilot->set_HeadingEnabled(false);
1179   }
1180 }
1181
1182
1183 /**
1184  * Get the autopilot target heading in degrees.
1185  */
1186 double
1187 FGBFI::getAPHeading ()
1188 {
1189   return current_autopilot->get_TargetHeading();
1190 }
1191
1192
1193 /**
1194  * Set the autopilot target heading in degrees.
1195  */
1196 void
1197 FGBFI::setAPHeading (double heading)
1198 {
1199   current_autopilot->set_TargetHeading( heading );
1200 }
1201
1202
1203 /**
1204  * Get the autopilot target heading in degrees.
1205  */
1206 double
1207 FGBFI::getAPHeadingMag ()
1208 {
1209   return current_autopilot->get_TargetHeading() - getMagVar();
1210 }
1211
1212
1213 /**
1214  * Set the autopilot target heading in degrees.
1215  */
1216 void
1217 FGBFI::setAPHeadingMag (double heading)
1218 {
1219   current_autopilot->set_TargetHeading( heading + getMagVar() );
1220 }
1221
1222
1223 /**
1224  * Return true if the autopilot is locked to NAV1.
1225  */
1226 bool
1227 FGBFI::getAPNAV1Lock ()
1228 {
1229   return
1230     (current_autopilot->get_HeadingEnabled() &&
1231      current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_NAV1);
1232 }
1233
1234
1235 /**
1236  * Set the autopilot NAV1 lock.
1237  */
1238 void
1239 FGBFI::setAPNAV1Lock (bool lock)
1240 {
1241   if (lock) {
1242     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_NAV1);
1243     current_autopilot->set_HeadingEnabled(true);
1244   } else if (current_autopilot->get_HeadingMode() ==
1245              FGAutopilot::FG_HEADING_NAV1) {
1246     current_autopilot->set_HeadingEnabled(false);
1247   }
1248 }
1249
1250
1251 \f
1252 ////////////////////////////////////////////////////////////////////////
1253 // GPS
1254 ////////////////////////////////////////////////////////////////////////
1255
1256
1257 /**
1258  * Get the autopilot GPS lock (true=on).
1259  */
1260 bool
1261 FGBFI::getGPSLock ()
1262 {
1263   return (current_autopilot->get_HeadingEnabled() &&
1264           (current_autopilot->get_HeadingMode() ==
1265            FGAutopilot::FG_HEADING_WAYPOINT ));
1266 }
1267
1268
1269 /**
1270  * Set the autopilot GPS lock (true=on).
1271  */
1272 void
1273 FGBFI::setGPSLock (bool lock)
1274 {
1275   if (lock) {
1276     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_WAYPOINT);
1277     current_autopilot->set_HeadingEnabled(true);
1278   } else if (current_autopilot->get_HeadingMode() ==
1279              FGAutopilot::FG_HEADING_WAYPOINT) {
1280     current_autopilot->set_HeadingEnabled(false);
1281   }
1282 }
1283
1284
1285 /**
1286  * Get the GPS target airport code.
1287  */
1288 string 
1289 FGBFI::getTargetAirport ()
1290 {
1291   // FIXME: not thread-safe
1292   static string out;
1293   out = globals->get_options()->get_airport_id();
1294
1295   return out;
1296 }
1297
1298
1299 /**
1300  * Set the GPS target airport code.
1301  */
1302 void
1303 FGBFI::setTargetAirport (string airportId)
1304 {
1305   globals->get_options()->set_airport_id(airportId);
1306 }
1307
1308
1309 /**
1310  * Get the GPS target latitude in degrees (negative for south).
1311  */
1312 double
1313 FGBFI::getGPSTargetLatitude ()
1314 {
1315     return current_autopilot->get_TargetLatitude();
1316 }
1317
1318
1319 /**
1320  * Get the GPS target longitude in degrees (negative for west).
1321  */
1322 double
1323 FGBFI::getGPSTargetLongitude ()
1324 {
1325   return current_autopilot->get_TargetLongitude();
1326 }
1327
1328 #if 0
1329 /**
1330  * Set the GPS target longitude in degrees (negative for west).
1331  */
1332 void
1333 FGBFI::setGPSTargetLongitude (double longitude)
1334 {
1335   current_autopilot->set_TargetLongitude( longitude );
1336 }
1337 #endif
1338
1339
1340 \f
1341 ////////////////////////////////////////////////////////////////////////
1342 // Weather
1343 ////////////////////////////////////////////////////////////////////////
1344
1345
1346 /**
1347  * Get the current visibility (meters).
1348  */
1349 double
1350 FGBFI::getVisibility ()
1351 {
1352 #ifndef FG_OLD_WEATHER
1353   return WeatherDatabase->getWeatherVisibility();
1354 #else
1355   return current_weather.get_visibility();
1356 #endif
1357 }
1358
1359
1360 /**
1361  * Set the current visibility (meters).
1362  */
1363 void
1364 FGBFI::setVisibility (double visibility)
1365 {
1366 #ifndef FG_OLD_WEATHER
1367   WeatherDatabase->setWeatherVisibility(visibility);
1368 #else
1369   current_weather.set_visibility(visibility);
1370 #endif
1371 }
1372
1373
1374 /**
1375  * Get the current wind north velocity (feet/second).
1376  */
1377 double
1378 FGBFI::getWindNorth ()
1379 {
1380   return current_aircraft.fdm_state->get_V_north_airmass();
1381 }
1382
1383
1384 /**
1385  * Set the current wind north velocity (feet/second).
1386  */
1387 void
1388 FGBFI::setWindNorth (double speed)
1389 {
1390   current_aircraft.fdm_state->set_Velocities_Local_Airmass(speed,
1391                                                            getWindEast(),
1392                                                            getWindDown());
1393 }
1394
1395
1396 /**
1397  * Get the current wind east velocity (feet/second).
1398  */
1399 double
1400 FGBFI::getWindEast ()
1401 {
1402   return current_aircraft.fdm_state->get_V_east_airmass();
1403 }
1404
1405
1406 /**
1407  * Set the current wind east velocity (feet/second).
1408  */
1409 void
1410 FGBFI::setWindEast (double speed)
1411 {
1412   cout << "Set wind-east to " << speed << endl;
1413   current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
1414                                                            speed,
1415                                                            getWindDown());
1416 }
1417
1418
1419 /**
1420  * Get the current wind down velocity (feet/second).
1421  */
1422 double
1423 FGBFI::getWindDown ()
1424 {
1425   return current_aircraft.fdm_state->get_V_down_airmass();
1426 }
1427
1428
1429 /**
1430  * Set the current wind down velocity (feet/second).
1431  */
1432 void
1433 FGBFI::setWindDown (double speed)
1434 {
1435   current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
1436                                                            getWindEast(),
1437                                                            speed);
1438 }
1439
1440
1441 \f
1442 ////////////////////////////////////////////////////////////////////////
1443 // View.
1444 ////////////////////////////////////////////////////////////////////////
1445
1446 void
1447 FGBFI::setViewAxisLong (double axis)
1448 {
1449   axisLong = axis;
1450 }
1451
1452 void
1453 FGBFI::setViewAxisLat (double axis)
1454 {
1455   axisLat = axis;
1456 }
1457
1458 \f
1459 ////////////////////////////////////////////////////////////////////////
1460 // Time
1461 ////////////////////////////////////////////////////////////////////////
1462
1463 /**
1464  * Return the magnetic variation
1465  */
1466 double
1467 FGBFI::getMagVar ()
1468 {
1469   return globals->get_mag()->get_magvar() * RAD_TO_DEG;
1470 }
1471
1472
1473 /**
1474  * Return the magnetic variation
1475  */
1476 double
1477 FGBFI::getMagDip ()
1478 {
1479   return globals->get_mag()->get_magdip() * RAD_TO_DEG;
1480 }
1481
1482
1483 // end of bfi.cxx
1484