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