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