]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_props.cxx
c883abe899dc1c055e90bd807f8b6bc5d43fd2c0
[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 PAUSED    ****    SIM IS PAUSED    ****");
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 /**
361  * Pilot position offset from CG.
362  */
363 static float
364 getPilotPositionXOffset ()
365 {
366   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
367   float * offset = pilot_view->get_pilot_offset();
368   return offset[0];
369 }
370
371 static void
372 setPilotPositionXOffset (float x)
373 {
374   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
375   float * offset = pilot_view->get_pilot_offset();
376   pilot_view->set_pilot_offset(x, offset[1], offset[2]);
377 }
378
379 static float
380 getPilotPositionYOffset ()
381 {
382   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
383   float * offset = pilot_view->get_pilot_offset();
384   return offset[1];
385 }
386
387 static void
388 setPilotPositionYOffset (float y)
389 {
390   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
391   float * offset = pilot_view->get_pilot_offset();
392   pilot_view->set_pilot_offset(offset[0], y, offset[2]);
393 }
394
395 static float
396 getPilotPositionZOffset ()
397 {
398   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
399   float * offset = pilot_view->get_pilot_offset();
400   return offset[2];
401 }
402
403 static void
404 setPilotPositionZOffset (float z)
405 {
406   FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
407   float * offset = pilot_view->get_pilot_offset();
408   pilot_view->set_pilot_offset(offset[0], offset[1], z);
409 }
410
411
412 /**
413  * Return the current Zulu time.
414  */
415 static string 
416 getDateString ()
417 {
418   string out;
419   char buf[64];
420   struct tm * t = globals->get_time_params()->getGmt();
421   sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
422           t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
423           t->tm_hour, t->tm_min, t->tm_sec);
424   out = buf;
425   return out;
426 }
427
428
429 /**
430  * Set the current Zulu time.
431  */
432 static void
433 setDateString (string date_string)
434 {
435   SGTime * st = globals->get_time_params();
436   struct tm * current_time = st->getGmt();
437   struct tm new_time;
438
439                                 // Scan for basic ISO format
440                                 // YYYY-MM-DDTHH:MM:SS
441   int ret = sscanf(date_string.c_str(), "%d-%d-%dT%d:%d:%d",
442                    &(new_time.tm_year), &(new_time.tm_mon),
443                    &(new_time.tm_mday), &(new_time.tm_hour),
444                    &(new_time.tm_min), &(new_time.tm_sec));
445
446                                 // Be pretty picky about this, so
447                                 // that strange things don't happen
448                                 // if the save file has been edited
449                                 // by hand.
450   if (ret != 6) {
451     SG_LOG(SG_INPUT, SG_ALERT, "Date/time string " << date_string
452            << " not in YYYY-MM-DDTHH:MM:SS format; skipped");
453     return;
454   }
455
456                                 // OK, it looks like we got six
457                                 // values, one way or another.
458   new_time.tm_year -= 1900;
459   new_time.tm_mon -= 1;
460
461                                 // Now, tell flight gear to use
462                                 // the new time.  This was far
463                                 // too difficult, by the way.
464   long int warp =
465     mktime(&new_time) - mktime(current_time) + globals->get_warp();
466   double lon = current_aircraft.fdm_state->get_Longitude();
467   double lat = current_aircraft.fdm_state->get_Latitude();
468   globals->set_warp(warp);
469   st->update(lon, lat, warp);
470   fgUpdateSkyAndLightingParams();
471 }
472
473 /**
474  * Return the GMT as a string.
475  */
476 static string 
477 getGMTString ()
478 {
479   string out;
480   char buf[16];
481   struct tm * t = globals->get_time_params()->getGmt();
482   sprintf(buf, " %.2d:%.2d:%.2d",
483           t->tm_hour, t->tm_min, t->tm_sec);
484   out = buf;
485   return out;
486 }
487
488
489 /**
490  * Get the texture rendering state.
491  */
492 static bool
493 getTextures ()
494 {
495   return (material_lib.get_step() == 0);
496 }
497
498
499 /**
500  * Set the texture rendering state.
501  */
502 static void
503 setTextures (bool textures)
504 {
505   if (textures)
506     material_lib.set_step(0);
507   else
508     material_lib.set_step(1);
509 }
510
511
512 /**
513  * Return the magnetic variation
514  */
515 static double
516 getMagVar ()
517 {
518   return globals->get_mag()->get_magvar() * SGD_RADIANS_TO_DEGREES;
519 }
520
521
522 /**
523  * Return the magnetic dip
524  */
525 static double
526 getMagDip ()
527 {
528   return globals->get_mag()->get_magdip() * SGD_RADIANS_TO_DEGREES;
529 }
530
531
532 /**
533  * Return the current heading in degrees.
534  */
535 static double
536 getHeadingMag ()
537 {
538   return current_aircraft.fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES - getMagVar();
539 }
540
541
542 /**
543  * Return the fuel level in tank 1
544  */
545 static double
546 getTank1Fuel ()
547 {
548   return current_aircraft.fdm_state->get_Tank1Fuel();
549 }
550
551 static void
552 setTank1Fuel ( double gals )
553 {
554   current_aircraft.fdm_state->set_Tank1Fuel( gals );
555 }
556
557 /**
558  * Return the fuel level in tank 2
559  */
560 static double
561 getTank2Fuel ()
562 {
563   return current_aircraft.fdm_state->get_Tank2Fuel();
564 }
565
566 static void
567 setTank2Fuel ( double gals )
568 {
569   current_aircraft.fdm_state->set_Tank2Fuel( gals );
570 }
571
572
573 /**
574  * Get the autopilot altitude lock (true=on).
575  */
576 static bool
577 getAPAltitudeLock ()
578 {
579     return (current_autopilot->get_AltitudeEnabled() &&
580             current_autopilot->get_AltitudeMode()
581             == FGAutopilot::FG_ALTITUDE_LOCK);
582 }
583
584
585 /**
586  * Set the autopilot altitude lock (true=on).
587  */
588 static void
589 setAPAltitudeLock (bool lock)
590 {
591   if (lock)
592     current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_LOCK);
593   if (current_autopilot->get_AltitudeMode() == FGAutopilot::FG_ALTITUDE_LOCK)
594     current_autopilot->set_AltitudeEnabled(lock);
595 }
596
597
598 /**
599  * Get the autopilot target altitude in feet.
600  */
601 static double
602 getAPAltitude ()
603 {
604   return current_autopilot->get_TargetAltitude() * SG_METER_TO_FEET;
605 }
606
607
608 /**
609  * Set the autopilot target altitude in feet.
610  */
611 static void
612 setAPAltitude (double altitude)
613 {
614   current_autopilot->set_TargetAltitude( altitude * SG_FEET_TO_METER );
615 }
616
617 /**
618  * Get the autopilot altitude lock (true=on).
619  */
620 static bool
621 getAPGSLock ()
622 {
623     return (current_autopilot->get_AltitudeEnabled() &&
624             (current_autopilot->get_AltitudeMode()
625              == FGAutopilot::FG_ALTITUDE_GS1));
626 }
627
628
629 /**
630  * Set the autopilot altitude lock (true=on).
631  */
632 static void
633 setAPGSLock (bool lock)
634 {
635   if (lock)
636     current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_GS1);
637   if (current_autopilot->get_AltitudeMode() == FGAutopilot::FG_ALTITUDE_GS1)
638     current_autopilot->set_AltitudeEnabled(lock);
639 }
640
641
642 /**
643  * Get the autopilot terrain lock (true=on).
644  */
645 static bool
646 getAPTerrainLock ()
647 {
648     return (current_autopilot->get_AltitudeEnabled() &&
649             (current_autopilot->get_AltitudeMode()
650              == FGAutopilot::FG_ALTITUDE_TERRAIN));
651 }
652
653
654 /**
655  * Set the autopilot terrain lock (true=on).
656  */
657 static void
658 setAPTerrainLock (bool lock)
659 {
660   if (lock) {
661     current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_TERRAIN);
662     current_autopilot
663       ->set_TargetAGL(current_aircraft.fdm_state->get_Altitude_AGL() *
664                       SG_FEET_TO_METER);
665     cout << "Target AGL = "
666          << current_aircraft.fdm_state->get_Altitude_AGL() * SG_FEET_TO_METER
667          << endl;
668   }
669   if (current_autopilot->get_AltitudeMode() == FGAutopilot::FG_ALTITUDE_TERRAIN)
670     current_autopilot->set_AltitudeEnabled(lock);
671 }
672
673
674 /**
675  * Get the autopilot target altitude in feet.
676  */
677 static double
678 getAPClimb ()
679 {
680   return current_autopilot->get_TargetClimbRate() * SG_METER_TO_FEET;
681 }
682
683
684 /**
685  * Set the autopilot target altitude in feet.
686  */
687 static void
688 setAPClimb (double rate)
689 {
690     current_autopilot->set_TargetClimbRate( rate * SG_FEET_TO_METER );
691 }
692
693
694 /**
695  * Get the autopilot heading lock (true=on).
696  */
697 static bool
698 getAPHeadingLock ()
699 {
700     return
701       (current_autopilot->get_HeadingEnabled() &&
702        current_autopilot->get_HeadingMode() == DEFAULT_AP_HEADING_LOCK);
703 }
704
705
706 /**
707  * Set the autopilot heading lock (true=on).
708  */
709 static void
710 setAPHeadingLock (bool lock)
711 {
712   if (lock)
713     current_autopilot->set_HeadingMode(DEFAULT_AP_HEADING_LOCK);
714   if (current_autopilot->get_HeadingMode() == DEFAULT_AP_HEADING_LOCK)
715     current_autopilot->set_HeadingEnabled(lock);
716 }
717
718
719 /**
720  * Get the autopilot heading bug in degrees.
721  */
722 static double
723 getAPHeadingBug ()
724 {
725   return current_autopilot->get_DGTargetHeading();
726 }
727
728
729 /**
730  * Set the autopilot heading bug in degrees.
731  */
732 static void
733 setAPHeadingBug (double heading)
734 {
735   current_autopilot->set_DGTargetHeading( heading );
736 }
737
738
739 /**
740  * Get the autopilot wing leveler lock (true=on).
741  */
742 static bool
743 getAPWingLeveler ()
744 {
745     return
746       (current_autopilot->get_HeadingEnabled() &&
747        current_autopilot->get_HeadingMode() == FGAutopilot::FG_TC_HEADING_LOCK);
748 }
749
750
751 /**
752  * Set the autopilot wing leveler lock (true=on).
753  */
754 static void
755 setAPWingLeveler (bool lock)
756 {
757     if (lock)
758         current_autopilot->set_HeadingMode(FGAutopilot::FG_TC_HEADING_LOCK);
759     if (current_autopilot->get_HeadingMode() == FGAutopilot::FG_TC_HEADING_LOCK)
760       current_autopilot->set_HeadingEnabled(lock);
761 }
762
763 /**
764  * Return true if the autopilot is locked to NAV1.
765  */
766 static bool
767 getAPNAV1Lock ()
768 {
769   return
770     (current_autopilot->get_HeadingEnabled() &&
771      current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_NAV1);
772 }
773
774
775 /**
776  * Set the autopilot NAV1 lock.
777  */
778 static void
779 setAPNAV1Lock (bool lock)
780 {
781   if (lock)
782     current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_NAV1);
783   if (current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_NAV1)
784     current_autopilot->set_HeadingEnabled(lock);
785 }
786
787 /**
788  * Get the autopilot autothrottle lock.
789  */
790 static bool
791 getAPAutoThrottleLock ()
792 {
793   return current_autopilot->get_AutoThrottleEnabled();
794 }
795
796
797 /**
798  * Set the autothrottle lock.
799  */
800 static void
801 setAPAutoThrottleLock (bool lock)
802 {
803   current_autopilot->set_AutoThrottleEnabled(lock);
804 }
805
806
807 // kludge
808 static double
809 getAPRudderControl ()
810 {
811     if (getAPHeadingLock())
812         return current_autopilot->get_TargetHeading();
813     else
814         return globals->get_controls()->get_rudder();
815 }
816
817 // kludge
818 static void
819 setAPRudderControl (double value)
820 {
821     if (getAPHeadingLock()) {
822         SG_LOG(SG_GENERAL, SG_DEBUG, "setAPRudderControl " << value );
823         value -= current_autopilot->get_TargetHeading();
824         current_autopilot->HeadingAdjust(value < 0.0 ? -1.0 : 1.0);
825     } else {
826         globals->get_controls()->set_rudder(value);
827     }
828 }
829
830 // kludge
831 static double
832 getAPElevatorControl ()
833 {
834   if (getAPAltitudeLock())
835       return current_autopilot->get_TargetAltitude();
836   else
837     return globals->get_controls()->get_elevator();
838 }
839
840 // kludge
841 static void
842 setAPElevatorControl (double value)
843 {
844     if (value != 0 && getAPAltitudeLock()) {
845         SG_LOG(SG_GENERAL, SG_DEBUG, "setAPElevatorControl " << value );
846         value -= current_autopilot->get_TargetAltitude();
847         current_autopilot->AltitudeAdjust(value < 0.0 ? 100.0 : -100.0);
848     } else {
849         globals->get_controls()->set_elevator(value);
850     }
851 }
852
853 // kludge
854 static double
855 getAPThrottleControl ()
856 {
857   if (getAPAutoThrottleLock())
858     return 0.0;                 // always resets
859   else
860     return globals->get_controls()->get_throttle(0);
861 }
862
863 // kludge
864 static void
865 setAPThrottleControl (double value)
866 {
867   if (getAPAutoThrottleLock())
868     current_autopilot->AutoThrottleAdjust(value < 0.0 ? -0.01 : 0.01);
869   else
870     globals->get_controls()->set_throttle(FGControls::ALL_ENGINES, value);
871 }
872
873
874 /**
875  * Get the current visibility (meters).
876  */
877 static double
878 getVisibility ()
879 {
880 #ifndef FG_OLD_WEATHER
881   return WeatherDatabase->getWeatherVisibility();
882 #else
883   return current_weather.get_visibility();
884 #endif
885 }
886
887
888 /**
889  * Set the current visibility (meters).
890  */
891 static void
892 setVisibility (double visibility)
893 {
894 #ifndef FG_OLD_WEATHER
895   WeatherDatabase->setWeatherVisibility(visibility);
896 #else
897   current_weather.set_visibility(visibility);
898 #endif
899 }
900
901 /**
902  * Get the current wind north velocity (feet/second).
903  */
904 static double
905 getWindNorth ()
906 {
907   return current_aircraft.fdm_state->get_V_north_airmass();
908 }
909
910
911 /**
912  * Set the current wind north velocity (feet/second).
913  */
914 static void
915 setWindNorth (double speed)
916 {
917   current_aircraft.fdm_state
918     ->set_Velocities_Local_Airmass(speed, getWindEast(), getWindDown());
919 }
920
921
922 /**
923  * Get the current wind east velocity (feet/second).
924  */
925 static double
926 getWindEast ()
927 {
928   return current_aircraft.fdm_state->get_V_east_airmass();
929 }
930
931
932 /**
933  * Set the current wind east velocity (feet/second).
934  */
935 static void
936 setWindEast (double speed)
937 {
938   cout << "Set wind-east to " << speed << endl;
939   current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
940                                                            speed,
941                                                            getWindDown());
942 }
943
944
945 /**
946  * Get the current wind down velocity (feet/second).
947  */
948 static double
949 getWindDown ()
950 {
951   return current_aircraft.fdm_state->get_V_down_airmass();
952 }
953
954
955 /**
956  * Set the current wind down velocity (feet/second).
957  */
958 static void
959 setWindDown (double speed)
960 {
961   current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
962                                                            getWindEast(),
963                                                            speed);
964 }
965
966 /*
967  * Set the current engine0 running flag.
968  */
969 static void
970 setRunningFlag (bool flag)
971 {
972   if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
973     current_aircraft.fdm_state->get_engine(0)->set_Running_Flag( flag );
974   }
975 }
976
977 /*
978  * Set the current engine0 cranking flag.
979  */
980 //Although there is no real reason to want to tell the engine that it is cranking,
981 //this is currently necessary to avoid the cranking sound being played 
982 //before the engine inits.
983 static void
984 setCrankingFlag (bool flag)
985 {
986   if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
987     current_aircraft.fdm_state->get_engine(0)->set_Cranking_Flag( flag );
988   }
989 }
990
991 static double
992 getFOV ()
993 {
994   return globals->get_current_view()->get_fov();
995 }
996
997 static void
998 setFOV (double fov)
999 {
1000   if ( fov < 180 ) {
1001       globals->get_current_view()->set_fov( fov );
1002   }
1003 }
1004
1005 static long
1006 getWarp ()
1007 {
1008   return globals->get_warp();
1009 }
1010
1011 static void
1012 setWarp (long warp)
1013 {
1014   globals->set_warp(warp);
1015 }
1016
1017 static long
1018 getWarpDelta ()
1019 {
1020   return globals->get_warp_delta();
1021 }
1022
1023 static void
1024 setWarpDelta (long delta)
1025 {
1026   globals->set_warp_delta(delta);
1027 }
1028
1029 static void
1030 setViewAxisLong (double axis)
1031 {
1032   axisLong = axis;
1033 }
1034
1035 static void
1036 setViewAxisLat (double axis)
1037 {
1038   axisLat = axis;
1039 }
1040
1041 static bool
1042 getWindingCCW ()
1043 {
1044   return winding_ccw;
1045 }
1046
1047 static void
1048 setWindingCCW (bool state)
1049 {
1050   winding_ccw = state;
1051   if ( winding_ccw )
1052     glFrontFace ( GL_CCW );
1053   else
1054     glFrontFace ( GL_CW );
1055 }
1056
1057 static bool
1058 getFullScreen ()
1059 {
1060 #if defined(FX) && !defined(WIN32)
1061   return globals->get_fullscreen();
1062 #else
1063   return false;
1064 #endif
1065 }
1066
1067 static void
1068 setFullScreen (bool state)
1069 {
1070 #if defined(FX) && !defined(WIN32)
1071   globals->set_fullscreen(state);
1072 #  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
1073   XMesaSetFXmode( state ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
1074 #  endif
1075 #endif
1076 }
1077
1078 static bool
1079 getFDMDataLogging ()
1080 {
1081   return fdm_data_logging;
1082 }
1083
1084 static void
1085 setFDMDataLogging (bool state)
1086 {
1087                                 // kludge; no getter or setter available
1088   if (state != fdm_data_logging) {
1089     fgToggleFDMdataLogging();
1090     fdm_data_logging = state;
1091   }
1092 }
1093
1094 \f
1095 ////////////////////////////////////////////////////////////////////////
1096 // Tie the properties.
1097 ////////////////////////////////////////////////////////////////////////
1098
1099 void
1100 fgInitProps ()
1101 {
1102                                 // Simulation
1103   fgTie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
1104   fgTie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
1105   fgTie("/sim/freeze", getFreeze, setFreeze);
1106   fgTie("/sim/aircraft-dir", getAircraftDir, setAircraftDir);
1107   fgTie("/sim/view/offset-deg", getViewOffset, setViewOffset, false);
1108   fgSetArchivable("/sim/view/offset-deg");
1109   fgTie("/sim/view/goal-offset-deg", getGoalViewOffset, setGoalViewOffset, false);
1110   fgSetArchivable("/sim/view/goal-offset-deg");
1111   fgTie("/sim/view/pilot/x-offset-m",
1112         getPilotPositionXOffset, setPilotPositionXOffset);
1113   fgSetArchivable("/sim/view/pilot/x-offset-m");
1114   fgTie("/sim/view/pilot/y-offset-m",
1115         getPilotPositionYOffset, setPilotPositionYOffset);
1116   fgSetArchivable("/sim/view/pilot/y-offset-m");
1117   fgTie("/sim/view/pilot/z-offset-m",
1118         getPilotPositionZOffset, setPilotPositionZOffset);
1119   fgSetArchivable("/sim/view/pilot/z-offset-m");
1120   fgTie("/sim/time/gmt", getDateString, setDateString);
1121   fgSetArchivable("/sim/time/gmt");
1122   fgTie("/sim/time/gmt-string", getGMTString);
1123   fgTie("/sim/rendering/textures", getTextures, setTextures);
1124
1125                                 // Orientation
1126   fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
1127
1128   //consumables
1129   fgTie("/consumables/fuel/tank[0]/level-gal_us",
1130         getTank1Fuel, setTank1Fuel, false);
1131   fgSetArchivable("/consumables/fuel/tank[0]/level-gal_us");
1132   fgTie("/consumables/fuel/tank[1]/level-gal_us",
1133         getTank2Fuel, setTank2Fuel, false);
1134   fgSetArchivable("/consumables/fuel/tank[1]/level-gal_us");
1135
1136                                 // Autopilot
1137   fgTie("/autopilot/locks/altitude", getAPAltitudeLock, setAPAltitudeLock);
1138   fgSetArchivable("/autopilot/locks/altitude");
1139   std::cout << "[AP] altitude = " << fgGetDouble("/autopilot/settings/altitude-ft") << std::endl;
1140   fgTie("/autopilot/settings/altitude-ft", getAPAltitude, setAPAltitude);
1141   fgSetArchivable("/autopilot/settings/altitude-ft");
1142   std::cout << "[AP] altitude = " << fgGetDouble("/autopilot/settings/altitude-ft") << std::endl;
1143   fgTie("/autopilot/locks/glide-slope", getAPGSLock, setAPGSLock);
1144   fgSetArchivable("/autopilot/locks/glide-slope");
1145   fgTie("/autopilot/locks/terrain", getAPTerrainLock, setAPTerrainLock);
1146   fgSetArchivable("/autopilot/locks/terrain");
1147   fgTie("/autopilot/settings/climb-rate-fpm", getAPClimb, setAPClimb, false);
1148   fgSetArchivable("/autopilot/settings/climb-rate-fpm");
1149   fgTie("/autopilot/locks/heading", getAPHeadingLock, setAPHeadingLock);
1150   fgSetArchivable("/autopilot/locks/heading");
1151   fgTie("/autopilot/settings/heading-bug-deg",
1152         getAPHeadingBug, setAPHeadingBug);
1153   fgSetArchivable("/autopilot/settings/heading-bug-deg");
1154   fgTie("/autopilot/locks/wing-leveler", getAPWingLeveler, setAPWingLeveler);
1155   fgSetArchivable("/autopilot/locks/wing-leveler");
1156   fgTie("/autopilot/locks/nav[0]", getAPNAV1Lock, setAPNAV1Lock);
1157   fgSetArchivable("/autopilot/locks/nav[0]");
1158   fgTie("/autopilot/locks/auto-throttle",
1159         getAPAutoThrottleLock, setAPAutoThrottleLock);
1160   fgSetArchivable("/autopilot/locks/auto-throttle");
1161   fgTie("/autopilot/control-overrides/rudder",
1162         getAPRudderControl, setAPRudderControl);
1163   fgSetArchivable("/autopilot/control-overrides/rudder");
1164   fgTie("/autopilot/control-overrides/elevator",
1165         getAPElevatorControl, setAPElevatorControl);
1166   fgSetArchivable("/autopilot/control-overrides/elevator");
1167   fgTie("/autopilot/control-overrides/throttle",
1168         getAPThrottleControl, setAPThrottleControl);
1169   fgSetArchivable("/autopilot/control-overrides/throttle");
1170
1171                                 // Environment
1172   fgTie("/environment/visibility-m", getVisibility, setVisibility);
1173   fgSetArchivable("/environment/visibility-m");
1174   fgTie("/environment/wind-north-fps", getWindNorth, setWindNorth);
1175   fgSetArchivable("/environment/wind-north-fps");
1176   fgTie("/environment/wind-east-fps", getWindEast, setWindEast);
1177   fgSetArchivable("/environment/wind-east-fps");
1178   fgTie("/environment/wind-down-fps", getWindDown, setWindDown);
1179   fgSetArchivable("/environment/wind-down-fps");
1180
1181   fgTie("/environment/magnetic-variation-deg", getMagVar);
1182   fgTie("/environment/magnetic-dip-deg", getMagDip);
1183
1184                                 // View
1185   fgTie("/sim/field-of-view", getFOV, setFOV);
1186   fgSetArchivable("/sim/field-of-view");
1187   fgTie("/sim/time/warp", getWarp, setWarp, false);
1188   fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
1189   fgTie("/sim/view/axes/long", (double(*)())0, setViewAxisLong);
1190   fgTie("/sim/view/axes/lat", (double(*)())0, setViewAxisLat);
1191
1192                                 // Misc. Temporary junk.
1193   fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW, false);
1194   fgTie("/sim/temp/full-screen", getFullScreen, setFullScreen);
1195   fgTie("/sim/temp/fdm-data-logging", getFDMDataLogging, setFDMDataLogging);
1196         
1197 }
1198
1199
1200 void
1201 fgUpdateProps ()
1202 {
1203   _set_view_from_axes();
1204 }
1205
1206
1207 \f
1208 ////////////////////////////////////////////////////////////////////////
1209 // Save and restore.
1210 ////////////////////////////////////////////////////////////////////////
1211
1212
1213 /**
1214  * Save the current state of the simulator to a stream.
1215  */
1216 bool
1217 fgSaveFlight (ostream &output)
1218 {
1219   try {
1220     writeProperties(output, globals->get_props());
1221   } catch (const sg_exception &e) {
1222     guiErrorMessage("Error saving flight: ", e);
1223     return false;
1224   }
1225   return true;
1226 }
1227
1228
1229 /**
1230  * Restore the current state of the simulator from a stream.
1231  */
1232 bool
1233 fgLoadFlight (istream &input)
1234 {
1235   SGPropertyNode props;
1236   try {
1237     readProperties(input, &props);
1238   } catch (const sg_exception &e) {
1239     guiErrorMessage("Error reading saved flight: ", e);
1240     return false;
1241   }
1242   copyProperties(&props, globals->get_props());
1243   // When loading a flight, make it the
1244   // new initial state.
1245   globals->saveInitialState();
1246   return true;
1247 }
1248
1249
1250 \f
1251 ////////////////////////////////////////////////////////////////////////
1252 // Implementation of FGCondition.
1253 ////////////////////////////////////////////////////////////////////////
1254
1255 FGCondition::FGCondition ()
1256 {
1257 }
1258
1259 FGCondition::~FGCondition ()
1260 {
1261 }
1262
1263
1264 \f
1265 ////////////////////////////////////////////////////////////////////////
1266 // Implementation of FGPropertyCondition.
1267 ////////////////////////////////////////////////////////////////////////
1268
1269 FGPropertyCondition::FGPropertyCondition (const string &propname)
1270   : _node(fgGetNode(propname, true))
1271 {
1272 }
1273
1274 FGPropertyCondition::~FGPropertyCondition ()
1275 {
1276 }
1277
1278
1279 \f
1280 ////////////////////////////////////////////////////////////////////////
1281 // Implementation of FGNotCondition.
1282 ////////////////////////////////////////////////////////////////////////
1283
1284 FGNotCondition::FGNotCondition (FGCondition * condition)
1285   : _condition(condition)
1286 {
1287 }
1288
1289 FGNotCondition::~FGNotCondition ()
1290 {
1291   delete _condition;
1292 }
1293
1294 bool
1295 FGNotCondition::test () const
1296 {
1297   return !(_condition->test());
1298 }
1299
1300
1301 \f
1302 ////////////////////////////////////////////////////////////////////////
1303 // Implementation of FGAndCondition.
1304 ////////////////////////////////////////////////////////////////////////
1305
1306 FGAndCondition::FGAndCondition ()
1307 {
1308 }
1309
1310 FGAndCondition::~FGAndCondition ()
1311 {
1312   for (unsigned int i = 0; i < _conditions.size(); i++)
1313     delete _conditions[i];
1314 }
1315
1316 bool
1317 FGAndCondition::test () const
1318 {
1319   int nConditions = _conditions.size();
1320   for (int i = 0; i < nConditions; i++) {
1321     if (!_conditions[i]->test())
1322       return false;
1323   }
1324   return true;
1325 }
1326
1327 void
1328 FGAndCondition::addCondition (FGCondition * condition)
1329 {
1330   _conditions.push_back(condition);
1331 }
1332
1333
1334 \f
1335 ////////////////////////////////////////////////////////////////////////
1336 // Implementation of FGOrCondition.
1337 ////////////////////////////////////////////////////////////////////////
1338
1339 FGOrCondition::FGOrCondition ()
1340 {
1341 }
1342
1343 FGOrCondition::~FGOrCondition ()
1344 {
1345   for (unsigned int i = 0; i < _conditions.size(); i++)
1346     delete _conditions[i];
1347 }
1348
1349 bool
1350 FGOrCondition::test () const
1351 {
1352   int nConditions = _conditions.size();
1353   for (int i = 0; i < nConditions; i++) {
1354     if (_conditions[i]->test())
1355       return true;
1356   }
1357   return false;
1358 }
1359
1360 void
1361 FGOrCondition::addCondition (FGCondition * condition)
1362 {
1363   _conditions.push_back(condition);
1364 }
1365
1366
1367 \f
1368 ////////////////////////////////////////////////////////////////////////
1369 // Implementation of FGComparisonCondition.
1370 ////////////////////////////////////////////////////////////////////////
1371
1372 static int
1373 doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
1374 {
1375   switch (left->getType()) {
1376   case SGPropertyNode::BOOL: {
1377     bool v1 = left->getBoolValue();
1378     bool v2 = right->getBoolValue();
1379     if (v1 < v2)
1380       return FGComparisonCondition::LESS_THAN;
1381     else if (v1 > v2)
1382       return FGComparisonCondition::GREATER_THAN;
1383     else
1384       return FGComparisonCondition::EQUALS;
1385     break;
1386   }
1387   case SGPropertyNode::INT: {
1388     int v1 = left->getIntValue();
1389     int v2 = right->getIntValue();
1390     if (v1 < v2)
1391       return FGComparisonCondition::LESS_THAN;
1392     else if (v1 > v2)
1393       return FGComparisonCondition::GREATER_THAN;
1394     else
1395       return FGComparisonCondition::EQUALS;
1396     break;
1397   }
1398   case SGPropertyNode::LONG: {
1399     long v1 = left->getLongValue();
1400     long v2 = right->getLongValue();
1401     if (v1 < v2)
1402       return FGComparisonCondition::LESS_THAN;
1403     else if (v1 > v2)
1404       return FGComparisonCondition::GREATER_THAN;
1405     else
1406       return FGComparisonCondition::EQUALS;
1407     break;
1408   }
1409   case SGPropertyNode::FLOAT: {
1410     float v1 = left->getFloatValue();
1411     float v2 = right->getFloatValue();
1412     if (v1 < v2)
1413       return FGComparisonCondition::LESS_THAN;
1414     else if (v1 > v2)
1415       return FGComparisonCondition::GREATER_THAN;
1416     else
1417       return FGComparisonCondition::EQUALS;
1418     break;
1419   }
1420   case SGPropertyNode::DOUBLE: {
1421     double v1 = left->getDoubleValue();
1422     double v2 = right->getDoubleValue();
1423     if (v1 < v2)
1424       return FGComparisonCondition::LESS_THAN;
1425     else if (v1 > v2)
1426       return FGComparisonCondition::GREATER_THAN;
1427     else
1428       return FGComparisonCondition::EQUALS;
1429     break;
1430   }
1431   case SGPropertyNode::STRING: 
1432   case SGPropertyNode::NONE:
1433   case SGPropertyNode::UNSPECIFIED: {
1434     string v1 = left->getStringValue();
1435     string v2 = right->getStringValue();
1436     if (v1 < v2)
1437       return FGComparisonCondition::LESS_THAN;
1438     else if (v1 > v2)
1439       return FGComparisonCondition::GREATER_THAN;
1440     else
1441       return FGComparisonCondition::EQUALS;
1442     break;
1443   }
1444   }
1445   throw sg_exception("Unrecognized node type");
1446   return 0;
1447 }
1448
1449
1450 FGComparisonCondition::FGComparisonCondition (Type type, bool reverse)
1451   : _type(type),
1452     _reverse(reverse),
1453     _left_property(0),
1454     _right_property(0),
1455     _right_value(0)
1456 {
1457 }
1458
1459 FGComparisonCondition::~FGComparisonCondition ()
1460 {
1461   delete _right_value;
1462 }
1463
1464 bool
1465 FGComparisonCondition::test () const
1466 {
1467                                 // Always fail if incompletely specified
1468   if (_left_property == 0 ||
1469       (_right_property == 0 && _right_value == 0))
1470     return false;
1471
1472                                 // Get LESS_THAN, EQUALS, or GREATER_THAN
1473   int cmp =
1474     doComparison(_left_property,
1475                  (_right_property != 0 ? _right_property : _right_value));
1476   if (!_reverse)
1477     return (cmp == _type);
1478   else
1479     return (cmp != _type);
1480 }
1481
1482 void
1483 FGComparisonCondition::setLeftProperty (const string &propname)
1484 {
1485   _left_property = fgGetNode(propname, true);
1486 }
1487
1488 void
1489 FGComparisonCondition::setRightProperty (const string &propname)
1490 {
1491   delete _right_value;
1492   _right_value = 0;
1493   _right_property = fgGetNode(propname, true);
1494 }
1495
1496 void
1497 FGComparisonCondition::setRightValue (const SGPropertyNode *node)
1498 {
1499   _right_property = 0;
1500   delete _right_value;
1501   _right_value = new SGPropertyNode(*node);
1502 }
1503
1504
1505 \f
1506 ////////////////////////////////////////////////////////////////////////
1507 // Read a condition and use it if necessary.
1508 ////////////////////////////////////////////////////////////////////////
1509
1510                                 // Forward declaration
1511 static FGCondition * readCondition (const SGPropertyNode * node);
1512
1513 static FGCondition *
1514 readPropertyCondition (const SGPropertyNode * node)
1515 {
1516   return new FGPropertyCondition(node->getStringValue());
1517 }
1518
1519 static FGCondition *
1520 readNotCondition (const SGPropertyNode * node)
1521 {
1522   int nChildren = node->nChildren();
1523   for (int i = 0; i < nChildren; i++) {
1524     const SGPropertyNode * child = node->getChild(i);
1525     FGCondition * condition = readCondition(child);
1526     if (condition != 0)
1527       return new FGNotCondition(condition);
1528   }
1529   SG_LOG(SG_COCKPIT, SG_ALERT, "Panel: empty 'not' condition");
1530   return 0;
1531 }
1532
1533 static FGCondition *
1534 readAndConditions (const SGPropertyNode * node)
1535 {
1536   FGAndCondition * andCondition = new FGAndCondition;
1537   int nChildren = node->nChildren();
1538   for (int i = 0; i < nChildren; i++) {
1539     const SGPropertyNode * child = node->getChild(i);
1540     FGCondition * condition = readCondition(child);
1541     if (condition != 0)
1542       andCondition->addCondition(condition);
1543   }
1544   return andCondition;
1545 }
1546
1547 static FGCondition *
1548 readOrConditions (const SGPropertyNode * node)
1549 {
1550   FGOrCondition * orCondition = new FGOrCondition;
1551   int nChildren = node->nChildren();
1552   for (int i = 0; i < nChildren; i++) {
1553     const SGPropertyNode * child = node->getChild(i);
1554     FGCondition * condition = readCondition(child);
1555     if (condition != 0)
1556       orCondition->addCondition(condition);
1557   }
1558   return orCondition;
1559 }
1560
1561 static FGCondition *
1562 readComparison (const SGPropertyNode * node,
1563                 FGComparisonCondition::Type type,
1564                 bool reverse)
1565 {
1566   FGComparisonCondition * condition = new FGComparisonCondition(type, reverse);
1567   condition->setLeftProperty(node->getStringValue("property[0]"));
1568   if (node->hasValue("property[1]"))
1569     condition->setRightProperty(node->getStringValue("property[1]"));
1570   else
1571     condition->setRightValue(node->getChild("value", 0));
1572
1573   return condition;
1574 }
1575
1576 static FGCondition *
1577 readCondition (const SGPropertyNode * node)
1578 {
1579   const string &name = node->getName();
1580   if (name == "property")
1581     return readPropertyCondition(node);
1582   else if (name == "not")
1583     return readNotCondition(node);
1584   else if (name == "and")
1585     return readAndConditions(node);
1586   else if (name == "or")
1587     return readOrConditions(node);
1588   else if (name == "less-than")
1589     return readComparison(node, FGComparisonCondition::LESS_THAN, false);
1590   else if (name == "less-than-equals")
1591     return readComparison(node, FGComparisonCondition::GREATER_THAN, true);
1592   else if (name == "greater-than")
1593     return readComparison(node, FGComparisonCondition::GREATER_THAN, false);
1594   else if (name == "greater-than-equals")
1595     return readComparison(node, FGComparisonCondition::LESS_THAN, true);
1596   else if (name == "equals")
1597     return readComparison(node, FGComparisonCondition::EQUALS, false);
1598   else if (name == "not-equals")
1599     return readComparison(node, FGComparisonCondition::EQUALS, true);
1600   else
1601     return 0;
1602 }
1603
1604
1605 \f
1606 ////////////////////////////////////////////////////////////////////////
1607 // Implementation of FGConditional.
1608 ////////////////////////////////////////////////////////////////////////
1609
1610 FGConditional::FGConditional ()
1611   : _condition (0)
1612 {
1613 }
1614
1615 FGConditional::~FGConditional ()
1616 {
1617   delete _condition;
1618 }
1619
1620 void
1621 FGConditional::setCondition (FGCondition * condition)
1622 {
1623   delete _condition;
1624   _condition = condition;
1625 }
1626
1627 bool
1628 FGConditional::test () const
1629 {
1630   return ((_condition == 0) || _condition->test());
1631 }
1632
1633
1634 \f
1635 // The top-level is always an implicit 'and' group
1636 FGCondition *
1637 fgReadCondition (const SGPropertyNode * node)
1638 {
1639   return readAndConditions(node);
1640 }
1641
1642
1643 // end of fg_props.cxx