]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_props.cxx
Sync with latest JSBSim CVS
[flightgear.git] / src / Main / fg_props.cxx
1 // fg_props.cxx -- support for FlightGear properties.
2 //
3 // Written by David Megginson, started 2000.
4 //
5 // Copyright (C) 2000, 2001 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 #ifdef HAVE_CONFIG_H
24 #  include <simgear/compiler.h>
25 #endif
26
27 #include <simgear/misc/exception.hxx>
28
29 #include STL_IOSTREAM
30
31 #include <Autopilot/newauto.hxx>
32 #include <Aircraft/aircraft.hxx>
33 #include <Time/tmp.hxx>
34 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
35 #ifndef FG_OLD_WEATHER
36 #  include <WeatherCM/FGLocalWeatherDatabase.h>
37 #else
38 #  include <Weather/weather.hxx>
39 #endif
40 #include <Objects/matlib.hxx>
41
42 #include <GUI/gui.h>
43
44 #include "fgfs.hxx"
45 #include "fg_props.hxx"
46 #include "viewmgr.hxx"
47
48 #if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
49 SG_USING_STD(istream);
50 SG_USING_STD(ostream);
51 #endif
52
53 static double getWindNorth ();
54 static double getWindEast ();
55 static double getWindDown ();
56
57 // Allow the view to be set from two axes (i.e. a joystick hat)
58 // This needs to be in FGViewer itself, somehow.
59 static double axisLong = 0.0;
60 static double axisLat = 0.0;
61
62 static bool winding_ccw = true; // FIXME: temporary
63
64 static bool fdm_data_logging = false; // FIXME: temporary
65
66
67 /**
68  * Utility function.
69  */
70 static inline void
71 _set_view_from_axes ()
72 {
73                                 // Take no action when hat is centered
74   if ( ( axisLong <  0.01 ) &&
75        ( axisLong > -0.01 ) &&
76        ( axisLat  <  0.01 ) &&
77        ( axisLat  > -0.01 )
78      )
79     return;
80
81   double viewDir = 999;
82
83   /* Do all the quick and easy cases */
84   if (axisLong < 0) {           // Longitudinal axis forward
85     if (axisLat == axisLong)
86       viewDir = 45;
87     else if (axisLat == - axisLong)
88       viewDir = 315;
89     else if (axisLat == 0)
90       viewDir = 0;
91   } else if (axisLong > 0) {    // Longitudinal axis backward
92     if (axisLat == - axisLong)
93       viewDir = 135;
94     else if (axisLat == axisLong)
95       viewDir = 225;
96     else if (axisLat == 0)
97       viewDir = 180;
98   } else if (axisLong == 0) {   // Longitudinal axis neutral
99     if (axisLat < 0)
100       viewDir = 90;
101     else if (axisLat > 0)
102       viewDir = 270;
103     else return; /* And assertion failure maybe? */
104   }
105
106   /* Do all the difficult cases */
107   if ( viewDir > 900 )
108     viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axisLat, -axisLong );
109   if ( viewDir < -1 ) viewDir += 360;
110
111 //  SG_LOG(SG_INPUT, SG_ALERT, "Joystick Lat=" << axisLat << "   and Long="
112 //      << axisLong << "  gave angle=" << viewDir );
113
114   globals->get_current_view()->set_goal_view_offset(viewDir*SGD_DEGREES_TO_RADIANS);
115 //   globals->get_current_view()->set_view_offset(viewDir*SGD_DEGREES_TO_RADIANS);
116 }
117
118 \f
119 ////////////////////////////////////////////////////////////////////////
120 // Default property bindings (not yet handled by any module).
121 ////////////////////////////////////////////////////////////////////////
122
123
124 /**
125  * Get the pause state of the sim.
126  */
127 static bool
128 getFreeze ()
129 {
130   return globals->get_freeze();
131 }
132
133
134 /**
135  * Set the pause state of the sim.
136  */
137 static void
138 setFreeze (bool freeze)
139 {
140   globals->set_freeze(freeze);
141 }
142
143 /**
144  * Return the current aircraft directory (UIUC) as a string.
145  */
146 static string 
147 getAircraftDir ()
148 {
149   return aircraft_dir;
150 }
151
152
153 /**
154  * Set the current aircraft directory (UIUC).
155  */
156 static void
157 setAircraftDir (string dir)
158 {
159   if (getAircraftDir() != dir) {
160     aircraft_dir = dir;
161 //     needReinit(); FIXME!!
162   }
163 }
164
165
166 /**
167  * Get the current view offset in degrees.
168  */
169 static double
170 getViewOffset ()
171 {
172   return (globals->get_current_view()
173           ->get_view_offset() * SGD_RADIANS_TO_DEGREES);
174 }
175
176
177 static void
178 setViewOffset (double offset)
179 {
180   globals->get_current_view()->set_view_offset(offset * SGD_DEGREES_TO_RADIANS);
181 }
182
183 static double
184 getGoalViewOffset ()
185 {
186   return (globals->get_current_view()
187           ->get_goal_view_offset() * SGD_RADIANS_TO_DEGREES);
188 }
189
190 static void
191 setGoalViewOffset (double offset)
192 {
193     while ( offset < 0 ) {
194         offset += 360.0;
195     }
196     while ( offset > 360.0 ) {
197         offset -= 360.0;
198     }
199     // Snap to center if we are close
200     if ( fabs(offset) < 1.0 ||  fabs(offset) > 359.0 ) {
201         offset = 0.0;
202     }
203
204     globals->get_current_view()
205         ->set_goal_view_offset(offset * SGD_DEGREES_TO_RADIANS);
206 }
207
208
209 /**
210  * Pilot position offset from CG.
211  */
212 static float
213 getPilotPositionXOffset ()
214 {
215   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
216   float * offset = pilot_view->get_pilot_offset();
217   return offset[0];
218 }
219
220 static void
221 setPilotPositionXOffset (float x)
222 {
223   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
224   float * offset = pilot_view->get_pilot_offset();
225   pilot_view->set_pilot_offset(x, offset[1], offset[2]);
226 }
227
228 static float
229 getPilotPositionYOffset ()
230 {
231   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
232   float * offset = pilot_view->get_pilot_offset();
233   return offset[1];
234 }
235
236 static void
237 setPilotPositionYOffset (float y)
238 {
239   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
240   float * offset = pilot_view->get_pilot_offset();
241   pilot_view->set_pilot_offset(offset[0], y, offset[2]);
242 }
243
244 static float
245 getPilotPositionZOffset ()
246 {
247   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
248   float * offset = pilot_view->get_pilot_offset();
249   return offset[2];
250 }
251
252 static void
253 setPilotPositionZOffset (float z)
254 {
255   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
256   float * offset = pilot_view->get_pilot_offset();
257   pilot_view->set_pilot_offset(offset[0], offset[1], z);
258 }
259
260
261 /**
262  * Return the current Zulu time.
263  */
264 static string 
265 getDateString ()
266 {
267   string out;
268   char buf[64];
269   struct tm * t = globals->get_time_params()->getGmt();
270   sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
271           t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
272           t->tm_hour, t->tm_min, t->tm_sec);
273   out = buf;
274   return out;
275 }
276
277
278 /**
279  * Set the current Zulu time.
280  */
281 static void
282 setDateString (string date_string)
283 {
284   SGTime * st = globals->get_time_params();
285   struct tm * current_time = st->getGmt();
286   struct tm new_time;
287
288                                 // Scan for basic ISO format
289                                 // YYYY-MM-DDTHH:MM:SS
290   int ret = sscanf(date_string.c_str(), "%d-%d-%dT%d:%d:%d",
291                    &(new_time.tm_year), &(new_time.tm_mon),
292                    &(new_time.tm_mday), &(new_time.tm_hour),
293                    &(new_time.tm_min), &(new_time.tm_sec));
294
295                                 // Be pretty picky about this, so
296                                 // that strange things don't happen
297                                 // if the save file has been edited
298                                 // by hand.
299   if (ret != 6) {
300     SG_LOG(SG_INPUT, SG_ALERT, "Date/time string " << date_string
301            << " not in YYYY-MM-DDTHH:MM:SS format; skipped");
302     return;
303   }
304
305                                 // OK, it looks like we got six
306                                 // values, one way or another.
307   new_time.tm_year -= 1900;
308   new_time.tm_mon -= 1;
309
310                                 // Now, tell flight gear to use
311                                 // the new time.  This was far
312                                 // too difficult, by the way.
313   long int warp =
314     mktime(&new_time) - mktime(current_time) + globals->get_warp();
315   double lon = current_aircraft.fdm_state->get_Longitude();
316   double lat = current_aircraft.fdm_state->get_Latitude();
317   globals->set_warp(warp);
318   st->update(lon, lat, warp);
319   fgUpdateSkyAndLightingParams();
320 }
321
322 /**
323  * Return the GMT as a string.
324  */
325 static string 
326 getGMTString ()
327 {
328   string out;
329   char buf[16];
330   struct tm * t = globals->get_time_params()->getGmt();
331   sprintf(buf, " %.2d:%.2d:%.2d",
332           t->tm_hour, t->tm_min, t->tm_sec);
333   out = buf;
334   return out;
335 }
336
337
338 /**
339  * Get the texture rendering state.
340  */
341 static bool
342 getTextures ()
343 {
344   return (material_lib.get_step() == 0);
345 }
346
347
348 /**
349  * Set the texture rendering state.
350  */
351 static void
352 setTextures (bool textures)
353 {
354   if (textures)
355     material_lib.set_step(0);
356   else
357     material_lib.set_step(1);
358 }
359
360
361 /**
362  * Return the magnetic variation
363  */
364 static double
365 getMagVar ()
366 {
367   return globals->get_mag()->get_magvar() * SGD_RADIANS_TO_DEGREES;
368 }
369
370
371 /**
372  * Return the magnetic dip
373  */
374 static double
375 getMagDip ()
376 {
377   return globals->get_mag()->get_magdip() * SGD_RADIANS_TO_DEGREES;
378 }
379
380
381 /**
382  * Return the current heading in degrees.
383  */
384 static double
385 getHeadingMag ()
386 {
387   return current_aircraft.fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES - getMagVar();
388 }
389
390
391 /**
392  * Return the current engine0 rpm
393  */
394 static double
395 getRPM ()
396 {
397   if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
398       return current_aircraft.fdm_state->get_engine(0)->get_RPM();
399   } else {
400       return 0.0;
401   }
402 }
403
404
405 /**
406  * Return the current engine0 EGT.
407  */
408 static double
409 getEGT ()
410 {
411   if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
412       return current_aircraft.fdm_state->get_engine(0)->get_EGT();
413   } else {
414       return 0.0;
415   }
416 }
417
418 /**
419  * Return the current engine0 CHT.
420  */
421 static double
422 getCHT ()
423 {
424   if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
425       return current_aircraft.fdm_state->get_engine(0)->get_CHT();
426   } else {
427       return 0.0;
428   }
429 }
430
431 /**
432  * Return the current engine0 Oil Temp.
433  */
434 static double
435 getOilTemp ()
436 {
437   if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
438       return current_aircraft.fdm_state->get_engine(0)->get_Oil_Temp();
439   } else {
440       return 0.0;
441   }
442 }
443
444 /**
445  * Return the current engine0 Manifold Pressure.
446  */
447 static double
448 getMP ()
449 {
450   if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
451       return current_aircraft.fdm_state->get_engine(0)->get_Manifold_Pressure();
452   } else {
453       return 0.0;
454   }
455 }
456
457
458 /**
459  * Return the current engine0 fuel flow
460  */
461 static double
462 getFuelFlow ()
463 {
464   if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
465       return current_aircraft.fdm_state->get_engine(0)->get_Fuel_Flow();
466   } else {
467       return 0.0;
468   }
469 }
470
471 /**
472  * Return the current engine0 running flag
473  */
474 static bool
475 getRunningFlag ()
476 {
477   if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
478       return current_aircraft.fdm_state->get_engine(0)->get_Running_Flag();
479   } else {
480       return false;
481   }
482 }
483
484 /**
485  * Return the current engine0 cranking flag
486  */
487 static bool
488 getCrankingFlag ()
489 {
490   if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
491       return current_aircraft.fdm_state->get_engine(0)->get_Cranking_Flag();
492   } else {
493       return false;
494   }
495 }
496
497 /**
498  * Return the fuel level in tank 1
499  */
500 static double
501 getTank1Fuel ()
502 {
503   return current_aircraft.fdm_state->get_Tank1Fuel();
504 }
505
506 static void
507 setTank1Fuel ( double gals )
508 {
509   current_aircraft.fdm_state->set_Tank1Fuel( gals );
510 }
511
512 /**
513  * Return the fuel level in tank 2
514  */
515 static double
516 getTank2Fuel ()
517 {
518   return current_aircraft.fdm_state->get_Tank2Fuel();
519 }
520
521 static void
522 setTank2Fuel ( double gals )
523 {
524   current_aircraft.fdm_state->set_Tank2Fuel( gals );
525 }
526
527
528 /**
529  * Get the autopilot altitude lock (true=on).
530  */
531 static bool
532 getAPAltitudeLock ()
533 {
534     return (current_autopilot->get_AltitudeEnabled() &&
535             current_autopilot->get_AltitudeMode()
536             == FGAutopilot::FG_ALTITUDE_LOCK);
537 }
538
539
540 /**
541  * Set the autopilot altitude lock (true=on).
542  */
543 static void
544 setAPAltitudeLock (bool lock)
545 {
546   current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_LOCK);
547   current_autopilot->set_AltitudeEnabled(lock);
548 }
549
550
551 /**
552  * Get the autopilot target altitude in feet.
553  */
554 static double
555 getAPAltitude ()
556 {
557   return current_autopilot->get_TargetAltitude() * SG_METER_TO_FEET;
558 }
559
560
561 /**
562  * Set the autopilot target altitude in feet.
563  */
564 static void
565 setAPAltitude (double altitude)
566 {
567     current_autopilot->set_TargetAltitude( altitude * SG_FEET_TO_METER );
568 }
569
570 /**
571  * Get the autopilot altitude lock (true=on).
572  */
573 static bool
574 getAPGSLock ()
575 {
576     return (current_autopilot->get_AltitudeEnabled() &&
577             (current_autopilot->get_AltitudeMode()
578              == FGAutopilot::FG_ALTITUDE_GS1));
579 }
580
581
582 /**
583  * Set the autopilot altitude lock (true=on).
584  */
585 static void
586 setAPGSLock (bool lock)
587 {
588   current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_GS1);
589   current_autopilot->set_AltitudeEnabled(lock);
590 }
591
592
593 /**
594  * Get the autopilot terrain lock (true=on).
595  */
596 static bool
597 getAPTerrainLock ()
598 {
599     return (current_autopilot->get_AltitudeEnabled() &&
600             (current_autopilot->get_AltitudeMode()
601              == FGAutopilot::FG_ALTITUDE_TERRAIN));
602 }
603
604
605 /**
606  * Set the autopilot terrain lock (true=on).
607  */
608 static void
609 setAPTerrainLock (bool lock)
610 {
611   current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_TERRAIN);
612   current_autopilot->set_AltitudeEnabled(lock);
613   current_autopilot->set_TargetAGL(
614       current_aircraft.fdm_state->get_Altitude_AGL() * SG_FEET_TO_METER
615     );
616   cout << "Target AGL = "
617        << current_aircraft.fdm_state->get_Altitude_AGL() * SG_FEET_TO_METER
618        << endl;
619 }
620
621
622 /**
623  * Get the autopilot target altitude in feet.
624  */
625 static double
626 getAPClimb ()
627 {
628   return current_autopilot->get_TargetClimbRate() * SG_METER_TO_FEET;
629 }
630
631
632 /**
633  * Set the autopilot target altitude in feet.
634  */
635 static void
636 setAPClimb (double rate)
637 {
638     current_autopilot->set_TargetClimbRate( rate * SG_FEET_TO_METER );
639 }
640
641
642 /**
643  * Get the autopilot heading lock (true=on).
644  */
645 static bool
646 getAPHeadingLock ()
647 {
648     return
649       (current_autopilot->get_HeadingEnabled() &&
650        current_autopilot->get_HeadingMode() == DEFAULT_AP_HEADING_LOCK);
651 }
652
653
654 /**
655  * Set the autopilot heading lock (true=on).
656  */
657 static void
658 setAPHeadingLock (bool lock)
659 {
660     if (lock) {
661         current_autopilot->set_HeadingMode(DEFAULT_AP_HEADING_LOCK);
662         current_autopilot->set_HeadingEnabled(true);
663     } else {
664         current_autopilot->set_HeadingEnabled(false);
665     }
666 }
667
668
669 /**
670  * Get the autopilot heading bug in degrees.
671  */
672 static double
673 getAPHeadingBug ()
674 {
675   return current_autopilot->get_DGTargetHeading();
676 }
677
678
679 /**
680  * Set the autopilot heading bug in degrees.
681  */
682 static void
683 setAPHeadingBug (double heading)
684 {
685   current_autopilot->set_DGTargetHeading( heading );
686 }
687
688
689 /**
690  * Get the autopilot wing leveler lock (true=on).
691  */
692 static bool
693 getAPWingLeveler ()
694 {
695     return
696       (current_autopilot->get_HeadingEnabled() &&
697        current_autopilot->get_HeadingMode() == FGAutopilot::FG_TC_HEADING_LOCK);
698 }
699
700
701 /**
702  * Set the autopilot wing leveler lock (true=on).
703  */
704 static void
705 setAPWingLeveler (bool lock)
706 {
707     if (lock) {
708         current_autopilot->set_HeadingMode(FGAutopilot::FG_TC_HEADING_LOCK);
709         current_autopilot->set_HeadingEnabled(true);
710     } else {
711         current_autopilot->set_HeadingEnabled(false);
712     }
713 }
714
715 /**
716  * Return true if the autopilot is locked to NAV1.
717  */
718 static bool
719 getAPNAV1Lock ()
720 {
721   return
722     (current_autopilot->get_HeadingEnabled() &&
723      current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_NAV1);
724 }
725
726
727 /**
728  * Set the autopilot NAV1 lock.
729  */
730 static void
731 setAPNAV1Lock (bool lock)
732 {
733   if (lock) {
734     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_NAV1);
735     current_autopilot->set_HeadingEnabled(true);
736   } else if (current_autopilot->get_HeadingMode() ==
737              FGAutopilot::FG_HEADING_NAV1) {
738     current_autopilot->set_HeadingEnabled(false);
739   }
740 }
741
742 /**
743  * Get the autopilot autothrottle lock.
744  */
745 static bool
746 getAPAutoThrottleLock ()
747 {
748   return current_autopilot->get_AutoThrottleEnabled();
749 }
750
751
752 /**
753  * Set the autothrottle lock.
754  */
755 static void
756 setAPAutoThrottleLock (bool lock)
757 {
758   current_autopilot->set_AutoThrottleEnabled(lock);
759 }
760
761
762 // kludge
763 static double
764 getAPRudderControl ()
765 {
766     if (getAPHeadingLock())
767         return current_autopilot->get_TargetHeading();
768     else
769         return globals->get_controls()->get_rudder();
770 }
771
772 // kludge
773 static void
774 setAPRudderControl (double value)
775 {
776     if (getAPHeadingLock()) {
777         SG_LOG(SG_GENERAL, SG_DEBUG, "setAPRudderControl " << value );
778         value -= current_autopilot->get_TargetHeading();
779         current_autopilot->HeadingAdjust(value < 0.0 ? -1.0 : 1.0);
780     } else {
781         globals->get_controls()->set_rudder(value);
782     }
783 }
784
785 // kludge
786 static double
787 getAPElevatorControl ()
788 {
789   if (getAPAltitudeLock())
790       return current_autopilot->get_TargetAltitude();
791   else
792     return globals->get_controls()->get_elevator();
793 }
794
795 // kludge
796 static void
797 setAPElevatorControl (double value)
798 {
799     if (getAPAltitudeLock()) {
800         SG_LOG(SG_GENERAL, SG_DEBUG, "setAPElevatorControl " << value );
801         value -= current_autopilot->get_TargetAltitude();
802         current_autopilot->AltitudeAdjust(value < 0.0 ? 100.0 : -100.0);
803     } else {
804         globals->get_controls()->set_elevator(value);
805     }
806 }
807
808 // kludge
809 static double
810 getAPThrottleControl ()
811 {
812   if (getAPAutoThrottleLock())
813     return 0.0;                 // always resets
814   else
815     return globals->get_controls()->get_throttle(0);
816 }
817
818 // kludge
819 static void
820 setAPThrottleControl (double value)
821 {
822   if (getAPAutoThrottleLock())
823     current_autopilot->AutoThrottleAdjust(value < 0.0 ? -0.01 : 0.01);
824   else
825     globals->get_controls()->set_throttle(0, value);
826 }
827
828
829 /**
830  * Get the current visibility (meters).
831  */
832 static double
833 getVisibility ()
834 {
835 #ifndef FG_OLD_WEATHER
836   return WeatherDatabase->getWeatherVisibility();
837 #else
838   return current_weather.get_visibility();
839 #endif
840 }
841
842
843 /**
844  * Set the current visibility (meters).
845  */
846 static void
847 setVisibility (double visibility)
848 {
849 #ifndef FG_OLD_WEATHER
850   WeatherDatabase->setWeatherVisibility(visibility);
851 #else
852   current_weather.set_visibility(visibility);
853 #endif
854 }
855
856 /**
857  * Get the current wind north velocity (feet/second).
858  */
859 static double
860 getWindNorth ()
861 {
862   return current_aircraft.fdm_state->get_V_north_airmass();
863 }
864
865
866 /**
867  * Set the current wind north velocity (feet/second).
868  */
869 static void
870 setWindNorth (double speed)
871 {
872   current_aircraft.fdm_state
873     ->set_Velocities_Local_Airmass(speed, getWindEast(), getWindDown());
874 }
875
876
877 /**
878  * Get the current wind east velocity (feet/second).
879  */
880 static double
881 getWindEast ()
882 {
883   return current_aircraft.fdm_state->get_V_east_airmass();
884 }
885
886
887 /**
888  * Set the current wind east velocity (feet/second).
889  */
890 static void
891 setWindEast (double speed)
892 {
893   cout << "Set wind-east to " << speed << endl;
894   current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
895                                                            speed,
896                                                            getWindDown());
897 }
898
899
900 /**
901  * Get the current wind down velocity (feet/second).
902  */
903 static double
904 getWindDown ()
905 {
906   return current_aircraft.fdm_state->get_V_down_airmass();
907 }
908
909
910 /**
911  * Set the current wind down velocity (feet/second).
912  */
913 static void
914 setWindDown (double speed)
915 {
916   current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
917                                                            getWindEast(),
918                                                            speed);
919 }
920
921 /*
922  * Set the current engine0 running flag.
923  */
924 static void
925 setRunningFlag (bool flag)
926 {
927   if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
928     current_aircraft.fdm_state->get_engine(0)->set_Running_Flag( flag );
929   }
930 }
931
932 /*
933  * Set the current engine0 cranking flag.
934  */
935 //Although there is no real reason to want to tell the engine that it is cranking,
936 //this is currently necessary to avoid the cranking sound being played 
937 //before the engine inits.
938 static void
939 setCrankingFlag (bool flag)
940 {
941   if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
942     current_aircraft.fdm_state->get_engine(0)->set_Cranking_Flag( flag );
943   }
944 }
945
946 static double
947 getFOV ()
948 {
949   return globals->get_current_view()->get_fov();
950 }
951
952 static void
953 setFOV (double fov)
954 {
955   if ( fov < 180 ) {
956       globals->get_current_view()->set_fov( fov );
957   }
958 }
959
960 static long
961 getWarp ()
962 {
963   return globals->get_warp();
964 }
965
966 static void
967 setWarp (long warp)
968 {
969   globals->set_warp(warp);
970 }
971
972 static long
973 getWarpDelta ()
974 {
975   return globals->get_warp_delta();
976 }
977
978 static void
979 setWarpDelta (long delta)
980 {
981   globals->set_warp_delta(delta);
982 }
983
984 static void
985 setViewAxisLong (double axis)
986 {
987   axisLong = axis;
988 }
989
990 static void
991 setViewAxisLat (double axis)
992 {
993   axisLat = axis;
994 }
995
996 static bool
997 getWindingCCW ()
998 {
999   return winding_ccw;
1000 }
1001
1002 static void
1003 setWindingCCW (bool state)
1004 {
1005   winding_ccw = state;
1006   if ( winding_ccw )
1007     glFrontFace ( GL_CCW );
1008   else
1009     glFrontFace ( GL_CW );
1010 }
1011
1012 static bool
1013 getFullScreen ()
1014 {
1015 #if defined(FX) && !defined(WIN32)
1016   return global_fullscreen;
1017 #else
1018   return false;
1019 #endif
1020 }
1021
1022 static void
1023 setFullScreen (bool state)
1024 {
1025 #if defined(FX) && !defined(WIN32)
1026   global_fullscreen = state;
1027 #  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
1028   XMesaSetFXmode( global_fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
1029 #  endif
1030 #endif
1031 }
1032
1033 static bool
1034 getFDMDataLogging ()
1035 {
1036   return fdm_data_logging;
1037 }
1038
1039 static void
1040 setFDMDataLogging (bool state)
1041 {
1042                                 // kludge; no getter or setter available
1043   if (state != fdm_data_logging) {
1044     fgToggleFDMdataLogging();
1045     fdm_data_logging = state;
1046   }
1047 }
1048
1049 \f
1050 ////////////////////////////////////////////////////////////////////////
1051 // Tie the properties.
1052 ////////////////////////////////////////////////////////////////////////
1053
1054 void
1055 fgInitProps ()
1056 {
1057                                 // Simulation
1058   fgTie("/sim/freeze", getFreeze, setFreeze);
1059   fgTie("/sim/aircraft-dir", getAircraftDir, setAircraftDir);
1060   fgTie("/sim/view/offset-deg", getViewOffset, setViewOffset);
1061   fgSetArchivable("/sim/view/offset-deg");
1062   fgTie("/sim/view/goal-offset-deg", getGoalViewOffset, setGoalViewOffset);
1063   fgSetArchivable("/sim/view/goal-offset-deg");
1064   fgTie("/sim/view/pilot/x-offset-m",
1065         getPilotPositionXOffset, setPilotPositionXOffset);
1066   fgSetArchivable("/sim/view/pilot/x-offset-m");
1067   fgTie("/sim/view/pilot/y-offset-m",
1068         getPilotPositionYOffset, setPilotPositionYOffset);
1069   fgSetArchivable("/sim/view/pilot/y-offset-m");
1070   fgTie("/sim/view/pilot/z-offset-m",
1071         getPilotPositionZOffset, setPilotPositionZOffset);
1072   fgSetArchivable("/sim/view/pilot/z-offset-m");
1073   fgTie("/sim/time/gmt", getDateString, setDateString);
1074   fgSetArchivable("/sim/time/gmt");
1075   fgTie("/sim/time/gmt-string", getGMTString);
1076   fgTie("/sim/rendering/textures", getTextures, setTextures);
1077
1078                                 // Orientation
1079   fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
1080
1081                                 // Engine
1082   fgTie("/engines/engine[0]/rpm", getRPM);
1083   fgTie("/engines/engine[0]/egt-degf", getEGT);
1084   fgTie("/engines/engine[0]/cht-degf", getCHT);
1085   fgTie("/engines/engine[0]/oil-temperature-degf", getOilTemp);
1086   fgTie("/engines/engine[0]/mp-osi", getMP);
1087   fgTie("/engines/engine[0]/fuel-flow-gph", getFuelFlow);
1088   fgTie("/engines/engine[0]/running", getRunningFlag, setRunningFlag);
1089   fgTie("/engines/engine[0]/cranking", getCrankingFlag, setCrankingFlag);
1090
1091   //consumables
1092   fgTie("/consumables/fuel/tank[0]/level-gal_us",
1093         getTank1Fuel, setTank1Fuel, false);
1094   fgSetArchivable("/consumables/fuel/tank[0]/level-gal_us");
1095   fgTie("/consumables/fuel/tank[1]/level-gal_us",
1096         getTank2Fuel, setTank2Fuel, false);
1097   fgSetArchivable("/consumables/fuel/tank[1]/level-gal_us");
1098
1099                                 // Autopilot
1100   fgTie("/autopilot/locks/altitude", getAPAltitudeLock, setAPAltitudeLock);
1101   fgSetArchivable("/autopilot/locks/altitude");
1102   fgTie("/autopilot/settings/altitude-ft", getAPAltitude, setAPAltitude);
1103   fgSetArchivable("/autopilot/settings/altitude-ft");
1104   fgTie("/autopilot/locks/glide-slope", getAPGSLock, setAPGSLock);
1105   fgSetArchivable("/autopilot/locks/glide-slope");
1106   fgTie("/autopilot/locks/terrain", getAPTerrainLock, setAPTerrainLock);
1107   fgSetArchivable("/autopilot/locks/terrain");
1108   fgTie("/autopilot/settings/agl-ft", getAPAltitude, setAPAltitude);
1109   fgSetArchivable("/autopilot/settings/agl-ft");
1110   fgTie("/autopilot/settings/climb-rate-fpm", getAPClimb, setAPClimb, false);
1111   fgSetArchivable("/autopilot/settings/climb-rate-fpm");
1112   fgTie("/autopilot/locks/heading", getAPHeadingLock, setAPHeadingLock);
1113   fgSetArchivable("/autopilot/locks/heading");
1114   fgTie("/autopilot/settings/heading-bug-deg",
1115         getAPHeadingBug, setAPHeadingBug, false);
1116   fgSetArchivable("/autopilot/settings/heading-bug-deg");
1117   fgTie("/autopilot/locks/wing-leveler", getAPWingLeveler, setAPWingLeveler);
1118   fgSetArchivable("/autopilot/locks/wing-leveler");
1119   fgTie("/autopilot/locks/nav[0]", getAPNAV1Lock, setAPNAV1Lock);
1120   fgSetArchivable("/autopilot/locks/nav[0]");
1121   fgTie("/autopilot/locks/auto-throttle",
1122         getAPAutoThrottleLock, setAPAutoThrottleLock);
1123   fgSetArchivable("/autopilot/locks/auto-throttle");
1124   fgTie("/autopilot/control-overrides/rudder",
1125         getAPRudderControl, setAPRudderControl);
1126   fgSetArchivable("/autopilot/control-overrides/rudder");
1127   fgTie("/autopilot/control-overrides/elevator",
1128         getAPElevatorControl, setAPElevatorControl);
1129   fgSetArchivable("/autopilot/control-overrides/elevator");
1130   fgTie("/autopilot/control-overrides/throttle",
1131         getAPThrottleControl, setAPThrottleControl);
1132   fgSetArchivable("/autopilot/control-overrides/throttle");
1133
1134                                 // Environment
1135   fgTie("/environment/visibility-m", getVisibility, setVisibility);
1136   fgSetArchivable("/environment/visibility-m");
1137   fgTie("/environment/wind-north-fps", getWindNorth, setWindNorth);
1138   fgSetArchivable("/environment/wind-north-fps");
1139   fgTie("/environment/wind-east-fps", getWindEast, setWindEast);
1140   fgSetArchivable("/environment/wind-east-fps");
1141   fgTie("/environment/wind-down-fps", getWindDown, setWindDown);
1142   fgSetArchivable("/environment/wind-down-fps");
1143
1144   fgTie("/environment/magnetic-variation-deg", getMagVar);
1145   fgTie("/environment/magnetic-dip-deg", getMagDip);
1146
1147                                 // View
1148   fgTie("/sim/field-of-view", getFOV, setFOV);
1149   fgSetArchivable("/sim/field-of-view");
1150   fgTie("/sim/time/warp", getWarp, setWarp, false);
1151   fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
1152   fgTie("/sim/view/axes/long", (double(*)())0, setViewAxisLong);
1153   fgTie("/sim/view/axes/lat", (double(*)())0, setViewAxisLat);
1154
1155                                 // Misc. Temporary junk.
1156   fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW, false);
1157   fgTie("/sim/temp/full-screen", getFullScreen, setFullScreen);
1158   fgTie("/sim/temp/fdm-data-logging", getFDMDataLogging, setFDMDataLogging);
1159         
1160 }
1161
1162
1163 void
1164 fgUpdateProps ()
1165 {
1166   _set_view_from_axes();
1167 }
1168
1169
1170 \f
1171 ////////////////////////////////////////////////////////////////////////
1172 // Save and restore.
1173 ////////////////////////////////////////////////////////////////////////
1174
1175
1176 /**
1177  * Save the current state of the simulator to a stream.
1178  */
1179 bool
1180 fgSaveFlight (ostream &output)
1181 {
1182   try {
1183     writeProperties(output, globals->get_props());
1184   } catch (const sg_exception &e) {
1185     guiErrorMessage("Error saving flight: ", e);
1186     return false;
1187   }
1188   return true;
1189 }
1190
1191
1192 /**
1193  * Restore the current state of the simulator from a stream.
1194  */
1195 bool
1196 fgLoadFlight (istream &input)
1197 {
1198   SGPropertyNode props;
1199   try {
1200     readProperties(input, &props);
1201   } catch (const sg_exception &e) {
1202     guiErrorMessage("Error reading saved flight: ", e);
1203     return false;
1204   }
1205   copyProperties(&props, globals->get_props());
1206   // When loading a flight, make it the
1207   // new initial state.
1208   globals->saveInitialState();
1209   return true;
1210 }
1211
1212
1213 \f
1214 ////////////////////////////////////////////////////////////////////////
1215 // Implementation of FGCondition.
1216 ////////////////////////////////////////////////////////////////////////
1217
1218 FGCondition::FGCondition ()
1219 {
1220 }
1221
1222 FGCondition::~FGCondition ()
1223 {
1224 }
1225
1226
1227 \f
1228 ////////////////////////////////////////////////////////////////////////
1229 // Implementation of FGPropertyCondition.
1230 ////////////////////////////////////////////////////////////////////////
1231
1232 FGPropertyCondition::FGPropertyCondition (const string &propname)
1233   : _node(fgGetNode(propname, true))
1234 {
1235 }
1236
1237 FGPropertyCondition::~FGPropertyCondition ()
1238 {
1239 }
1240
1241
1242 \f
1243 ////////////////////////////////////////////////////////////////////////
1244 // Implementation of FGNotCondition.
1245 ////////////////////////////////////////////////////////////////////////
1246
1247 FGNotCondition::FGNotCondition (FGCondition * condition)
1248   : _condition(condition)
1249 {
1250 }
1251
1252 FGNotCondition::~FGNotCondition ()
1253 {
1254   delete _condition;
1255 }
1256
1257 bool
1258 FGNotCondition::test () const
1259 {
1260   return !(_condition->test());
1261 }
1262
1263
1264 \f
1265 ////////////////////////////////////////////////////////////////////////
1266 // Implementation of FGAndCondition.
1267 ////////////////////////////////////////////////////////////////////////
1268
1269 FGAndCondition::FGAndCondition ()
1270 {
1271 }
1272
1273 FGAndCondition::~FGAndCondition ()
1274 {
1275   for (unsigned int i = 0; i < _conditions.size(); i++)
1276     delete _conditions[i];
1277 }
1278
1279 bool
1280 FGAndCondition::test () const
1281 {
1282   int nConditions = _conditions.size();
1283   for (int i = 0; i < nConditions; i++) {
1284     if (!_conditions[i]->test())
1285       return false;
1286   }
1287   return true;
1288 }
1289
1290 void
1291 FGAndCondition::addCondition (FGCondition * condition)
1292 {
1293   _conditions.push_back(condition);
1294 }
1295
1296
1297 \f
1298 ////////////////////////////////////////////////////////////////////////
1299 // Implementation of FGOrCondition.
1300 ////////////////////////////////////////////////////////////////////////
1301
1302 FGOrCondition::FGOrCondition ()
1303 {
1304 }
1305
1306 FGOrCondition::~FGOrCondition ()
1307 {
1308   for (unsigned int i = 0; i < _conditions.size(); i++)
1309     delete _conditions[i];
1310 }
1311
1312 bool
1313 FGOrCondition::test () const
1314 {
1315   int nConditions = _conditions.size();
1316   for (int i = 0; i < nConditions; i++) {
1317     if (_conditions[i]->test())
1318       return true;
1319   }
1320   return false;
1321 }
1322
1323 void
1324 FGOrCondition::addCondition (FGCondition * condition)
1325 {
1326   _conditions.push_back(condition);
1327 }
1328
1329
1330 \f
1331 ////////////////////////////////////////////////////////////////////////
1332 // Implementation of FGComparisonCondition.
1333 ////////////////////////////////////////////////////////////////////////
1334
1335 static int
1336 doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
1337 {
1338   switch (left->getType()) {
1339   case SGPropertyNode::BOOL: {
1340     bool v1 = left->getBoolValue();
1341     bool v2 = right->getBoolValue();
1342     if (v1 < v2)
1343       return FGComparisonCondition::LESS_THAN;
1344     else if (v1 > v2)
1345       return FGComparisonCondition::GREATER_THAN;
1346     else
1347       return FGComparisonCondition::EQUALS;
1348     break;
1349   }
1350   case SGPropertyNode::INT: {
1351     int v1 = left->getIntValue();
1352     int v2 = right->getIntValue();
1353     if (v1 < v2)
1354       return FGComparisonCondition::LESS_THAN;
1355     else if (v1 > v2)
1356       return FGComparisonCondition::GREATER_THAN;
1357     else
1358       return FGComparisonCondition::EQUALS;
1359     break;
1360   }
1361   case SGPropertyNode::LONG: {
1362     long v1 = left->getLongValue();
1363     long v2 = right->getLongValue();
1364     if (v1 < v2)
1365       return FGComparisonCondition::LESS_THAN;
1366     else if (v1 > v2)
1367       return FGComparisonCondition::GREATER_THAN;
1368     else
1369       return FGComparisonCondition::EQUALS;
1370     break;
1371   }
1372   case SGPropertyNode::FLOAT: {
1373     float v1 = left->getFloatValue();
1374     float v2 = right->getFloatValue();
1375     if (v1 < v2)
1376       return FGComparisonCondition::LESS_THAN;
1377     else if (v1 > v2)
1378       return FGComparisonCondition::GREATER_THAN;
1379     else
1380       return FGComparisonCondition::EQUALS;
1381     break;
1382   }
1383   case SGPropertyNode::DOUBLE: {
1384     double v1 = left->getDoubleValue();
1385     double v2 = right->getDoubleValue();
1386     if (v1 < v2)
1387       return FGComparisonCondition::LESS_THAN;
1388     else if (v1 > v2)
1389       return FGComparisonCondition::GREATER_THAN;
1390     else
1391       return FGComparisonCondition::EQUALS;
1392     break;
1393   }
1394   case SGPropertyNode::STRING: 
1395   case SGPropertyNode::NONE:
1396   case SGPropertyNode::UNSPECIFIED: {
1397     string v1 = left->getStringValue();
1398     string v2 = right->getStringValue();
1399     if (v1 < v2)
1400       return FGComparisonCondition::LESS_THAN;
1401     else if (v1 > v2)
1402       return FGComparisonCondition::GREATER_THAN;
1403     else
1404       return FGComparisonCondition::EQUALS;
1405     break;
1406   }
1407   }
1408   throw sg_exception("Unrecognized node type");
1409   return 0;
1410 }
1411
1412
1413 FGComparisonCondition::FGComparisonCondition (Type type, bool reverse)
1414   : _type(type),
1415     _reverse(reverse),
1416     _left_property(0),
1417     _right_property(0),
1418     _right_value(0)
1419 {
1420 }
1421
1422 FGComparisonCondition::~FGComparisonCondition ()
1423 {
1424   delete _right_value;
1425 }
1426
1427 bool
1428 FGComparisonCondition::test () const
1429 {
1430                                 // Always fail if incompletely specified
1431   if (_left_property == 0 ||
1432       (_right_property == 0 && _right_value == 0))
1433     return false;
1434
1435                                 // Get LESS_THAN, EQUALS, or GREATER_THAN
1436   int cmp =
1437     doComparison(_left_property,
1438                  (_right_property != 0 ? _right_property : _right_value));
1439   if (!_reverse)
1440     return (cmp == _type);
1441   else
1442     return (cmp != _type);
1443 }
1444
1445 void
1446 FGComparisonCondition::setLeftProperty (const string &propname)
1447 {
1448   _left_property = fgGetNode(propname, true);
1449 }
1450
1451 void
1452 FGComparisonCondition::setRightProperty (const string &propname)
1453 {
1454   delete _right_value;
1455   _right_value = 0;
1456   _right_property = fgGetNode(propname, true);
1457 }
1458
1459 void
1460 FGComparisonCondition::setRightValue (const SGPropertyNode *node)
1461 {
1462   _right_property = 0;
1463   delete _right_value;
1464   _right_value = new SGPropertyNode(*node);
1465 }
1466
1467
1468 \f
1469 ////////////////////////////////////////////////////////////////////////
1470 // Read a condition and use it if necessary.
1471 ////////////////////////////////////////////////////////////////////////
1472
1473                                 // Forward declaration
1474 static FGCondition * readCondition (const SGPropertyNode * node);
1475
1476 static FGCondition *
1477 readPropertyCondition (const SGPropertyNode * node)
1478 {
1479   return new FGPropertyCondition(node->getStringValue());
1480 }
1481
1482 static FGCondition *
1483 readNotCondition (const SGPropertyNode * node)
1484 {
1485   int nChildren = node->nChildren();
1486   for (int i = 0; i < nChildren; i++) {
1487     const SGPropertyNode * child = node->getChild(i);
1488     FGCondition * condition = readCondition(child);
1489     if (condition != 0)
1490       return new FGNotCondition(condition);
1491   }
1492   SG_LOG(SG_COCKPIT, SG_ALERT, "Panel: empty 'not' condition");
1493   return 0;
1494 }
1495
1496 static FGCondition *
1497 readAndConditions (const SGPropertyNode * node)
1498 {
1499   FGAndCondition * andCondition = new FGAndCondition;
1500   int nChildren = node->nChildren();
1501   for (int i = 0; i < nChildren; i++) {
1502     const SGPropertyNode * child = node->getChild(i);
1503     FGCondition * condition = readCondition(child);
1504     if (condition != 0)
1505       andCondition->addCondition(condition);
1506   }
1507   return andCondition;
1508 }
1509
1510 static FGCondition *
1511 readOrConditions (const SGPropertyNode * node)
1512 {
1513   FGOrCondition * orCondition = new FGOrCondition;
1514   int nChildren = node->nChildren();
1515   for (int i = 0; i < nChildren; i++) {
1516     const SGPropertyNode * child = node->getChild(i);
1517     FGCondition * condition = readCondition(child);
1518     if (condition != 0)
1519       orCondition->addCondition(condition);
1520   }
1521   return orCondition;
1522 }
1523
1524 static FGCondition *
1525 readComparison (const SGPropertyNode * node,
1526                 FGComparisonCondition::Type type,
1527                 bool reverse)
1528 {
1529   FGComparisonCondition * condition = new FGComparisonCondition(type, reverse);
1530   condition->setLeftProperty(node->getStringValue("property[0]"));
1531   if (node->hasValue("property[1]"))
1532     condition->setRightProperty(node->getStringValue("property[1]"));
1533   else
1534     condition->setRightValue(node->getChild("value", 0));
1535
1536   return condition;
1537 }
1538
1539 static FGCondition *
1540 readCondition (const SGPropertyNode * node)
1541 {
1542   const string &name = node->getName();
1543   if (name == "property")
1544     return readPropertyCondition(node);
1545   else if (name == "not")
1546     return readNotCondition(node);
1547   else if (name == "and")
1548     return readAndConditions(node);
1549   else if (name == "or")
1550     return readOrConditions(node);
1551   else if (name == "less-than")
1552     return readComparison(node, FGComparisonCondition::LESS_THAN, false);
1553   else if (name == "less-than-equals")
1554     return readComparison(node, FGComparisonCondition::GREATER_THAN, true);
1555   else if (name == "greater-than")
1556     return readComparison(node, FGComparisonCondition::GREATER_THAN, false);
1557   else if (name == "greater-than-equals")
1558     return readComparison(node, FGComparisonCondition::LESS_THAN, true);
1559   else if (name == "equals")
1560     return readComparison(node, FGComparisonCondition::EQUALS, false);
1561   else if (name == "not-equals")
1562     return readComparison(node, FGComparisonCondition::EQUALS, true);
1563   else
1564     return 0;
1565 }
1566
1567
1568 \f
1569 ////////////////////////////////////////////////////////////////////////
1570 // Implementation of FGConditional.
1571 ////////////////////////////////////////////////////////////////////////
1572
1573 FGConditional::FGConditional ()
1574   : _condition (0)
1575 {
1576 }
1577
1578 FGConditional::~FGConditional ()
1579 {
1580   delete _condition;
1581 }
1582
1583 void
1584 FGConditional::setCondition (FGCondition * condition)
1585 {
1586   delete _condition;
1587   _condition = condition;
1588 }
1589
1590 bool
1591 FGConditional::test () const
1592 {
1593   return ((_condition == 0) || _condition->test());
1594 }
1595
1596
1597 \f
1598 // The top-level is always an implicit 'and' group
1599 FGCondition *
1600 fgReadCondition (const SGPropertyNode * node)
1601 {
1602   return readAndConditions(node);
1603 }
1604
1605
1606 // end of fg_props.cxx