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