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