1 // fg_props.cxx -- support for FlightGear properties.
3 // Written by David Megginson, started 2000.
5 // Copyright (C) 2000, 2001 David Megginson - david@megginson.com
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.
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.
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.
24 # include <simgear/compiler.h>
27 #include <simgear/misc/exception.hxx>
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>
39 # include <Weather/weather.hxx>
41 #include <Objects/matlib.hxx>
46 #include "fg_props.hxx"
47 #include "viewmgr.hxx"
49 #if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
50 SG_USING_STD(istream);
51 SG_USING_STD(ostream);
54 static double getWindNorth ();
55 static double getWindEast ();
56 static double getWindDown ();
58 // Allow the view to be set from two axes (i.e. a joystick hat)
59 // This needs to be in FGViewer itself, somehow.
60 static double axisLong = 0.0;
61 static double axisLat = 0.0;
63 static bool winding_ccw = true; // FIXME: temporary
65 static bool fdm_data_logging = false; // FIXME: temporary
72 _set_view_from_axes ()
74 // Take no action when hat is centered
75 if ( ( axisLong < 0.01 ) &&
76 ( axisLong > -0.01 ) &&
84 /* Do all the quick and easy cases */
85 if (axisLong < 0) { // Longitudinal axis forward
86 if (axisLat == axisLong)
88 else if (axisLat == - axisLong)
90 else if (axisLat == 0)
92 } else if (axisLong > 0) { // Longitudinal axis backward
93 if (axisLat == - axisLong)
95 else if (axisLat == axisLong)
97 else if (axisLat == 0)
99 } else if (axisLong == 0) { // Longitudinal axis neutral
102 else if (axisLat > 0)
104 else return; /* And assertion failure maybe? */
107 /* Do all the difficult cases */
109 viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axisLat, -axisLong );
110 if ( viewDir < -1 ) viewDir += 360;
112 // SG_LOG(SG_INPUT, SG_ALERT, "Joystick Lat=" << axisLat << " and Long="
113 // << axisLong << " gave angle=" << viewDir );
115 globals->get_current_view()->set_goal_view_offset(viewDir*SGD_DEGREES_TO_RADIANS);
116 // globals->get_current_view()->set_view_offset(viewDir*SGD_DEGREES_TO_RADIANS);
120 ////////////////////////////////////////////////////////////////////////
121 // Default property bindings (not yet handled by any module).
122 ////////////////////////////////////////////////////////////////////////
124 struct LogClassMapping {
127 LogClassMapping(sgDebugClass cc, string nname) { c = cc; name = nname; }
130 LogClassMapping log_class_mappings [] = {
131 LogClassMapping(SG_NONE, "none"),
132 LogClassMapping(SG_TERRAIN, "terrain"),
133 LogClassMapping(SG_ASTRO, "astro"),
134 LogClassMapping(SG_FLIGHT, "flight"),
135 LogClassMapping(SG_INPUT, "input"),
136 LogClassMapping(SG_GL, "gl"),
137 LogClassMapping(SG_VIEW, "view"),
138 LogClassMapping(SG_COCKPIT, "cockpit"),
139 LogClassMapping(SG_GENERAL, "general"),
140 LogClassMapping(SG_MATH, "math"),
141 LogClassMapping(SG_EVENT, "event"),
142 LogClassMapping(SG_AIRCRAFT, "aircraft"),
143 LogClassMapping(SG_AUTOPILOT, "autopilot"),
144 LogClassMapping(SG_IO, "io"),
145 LogClassMapping(SG_CLIPPER, "clipper"),
146 LogClassMapping(SG_NETWORK, "network"),
147 LogClassMapping(SG_UNDEFD, "")
152 * Get the logging classes.
157 sgDebugClass classes = logbuf::get_log_classes();
159 for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
160 if ((classes&log_class_mappings[i].c) > 0) {
161 if (result != (string)"")
163 result += log_class_mappings[i].name;
170 static void addLoggingClass (const string &name)
172 sgDebugClass classes = logbuf::get_log_classes();
173 for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
174 if (name == log_class_mappings[i].name) {
175 logbuf::set_log_classes(sgDebugClass(classes|log_class_mappings[i].c));
179 SG_LOG(SG_GENERAL, SG_ALERT, "Unknown logging class: " << name);
184 * Set the logging classes.
187 setLoggingClasses (string classes)
189 logbuf::set_log_classes(SG_NONE);
191 if (classes == "none") {
192 SG_LOG(SG_GENERAL, SG_INFO, "Disabled all logging classes");
196 if (classes == "" || classes == "all") { // default
197 logbuf::set_log_classes(SG_ALL);
198 SG_LOG(SG_GENERAL, SG_INFO, "Enabled all logging classes: "
199 << getLoggingClasses());
203 string rest = classes;
205 int sep = rest.find('|');
207 name = rest.substr(0, sep);
208 rest = rest.substr(sep+1);
209 addLoggingClass(name);
210 sep = rest.find('|');
212 addLoggingClass(rest);
213 SG_LOG(SG_GENERAL, SG_INFO, "Set logging classes to "
214 << getLoggingClasses());
219 * Get the logging priority.
222 getLoggingPriority ()
224 switch (logbuf::get_log_priority()) {
236 SG_LOG(SG_GENERAL, SG_WARN, "Internal: Unknown logging priority number: "
237 << logbuf::get_log_priority());
244 * Set the logging priority.
247 setLoggingPriority (string priority)
249 if (priority == "bulk") {
250 logbuf::set_log_priority(SG_BULK);
251 } else if (priority == "debug") {
252 logbuf::set_log_priority(SG_DEBUG);
253 } else if (priority == "" || priority == "info") { // default
254 logbuf::set_log_priority(SG_INFO);
255 } else if (priority == "warn") {
256 logbuf::set_log_priority(SG_WARN);
257 } else if (priority == "alert") {
258 logbuf::set_log_priority(SG_ALERT);
260 SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority " << priority);
262 SG_LOG(SG_GENERAL, SG_INFO, "Logging priority is " << getLoggingPriority());
267 * Get the pause state of the sim.
272 return globals->get_freeze();
277 * Set the pause state of the sim.
280 setFreeze (bool freeze)
282 globals->set_freeze(freeze);
285 current_atcdisplay->CancelRepeatingMessage();
286 current_atcdisplay->RegisterRepeatingMessage("**** SIM IS PAUSED **** SIM IS PAUSED ****");
289 current_atcdisplay->CancelRepeatingMessage();
294 * Return the current aircraft directory (UIUC) as a string.
304 * Set the current aircraft directory (UIUC).
307 setAircraftDir (string dir)
309 if (getAircraftDir() != dir) {
311 // needReinit(); FIXME!!
317 * Get the current view offset in degrees.
322 return (globals->get_current_view()
323 ->get_view_offset() * SGD_RADIANS_TO_DEGREES);
328 setViewOffset (double offset)
330 globals->get_current_view()->set_view_offset(offset * SGD_DEGREES_TO_RADIANS);
336 return (globals->get_current_view()
337 ->get_goal_view_offset() * SGD_RADIANS_TO_DEGREES);
341 setGoalViewOffset (double offset)
343 while ( offset < 0 ) {
346 while ( offset > 360.0 ) {
349 // Snap to center if we are close
350 if ( fabs(offset) < 1.0 || fabs(offset) > 359.0 ) {
354 globals->get_current_view()
355 ->set_goal_view_offset(offset * SGD_DEGREES_TO_RADIANS);
360 * Pilot position offset from CG.
363 getPilotPositionXOffset ()
365 FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
366 float * offset = pilot_view->get_pilot_offset();
371 setPilotPositionXOffset (float x)
373 FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
374 float * offset = pilot_view->get_pilot_offset();
375 pilot_view->set_pilot_offset(x, offset[1], offset[2]);
379 getPilotPositionYOffset ()
381 FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
382 float * offset = pilot_view->get_pilot_offset();
387 setPilotPositionYOffset (float y)
389 FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
390 float * offset = pilot_view->get_pilot_offset();
391 pilot_view->set_pilot_offset(offset[0], y, offset[2]);
395 getPilotPositionZOffset ()
397 FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
398 float * offset = pilot_view->get_pilot_offset();
403 setPilotPositionZOffset (float z)
405 FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
406 float * offset = pilot_view->get_pilot_offset();
407 pilot_view->set_pilot_offset(offset[0], offset[1], z);
412 * Return the current Zulu time.
419 struct tm * t = globals->get_time_params()->getGmt();
420 sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
421 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
422 t->tm_hour, t->tm_min, t->tm_sec);
429 * Set the current Zulu time.
432 setDateString (string date_string)
434 SGTime * st = globals->get_time_params();
435 struct tm * current_time = st->getGmt();
438 // Scan for basic ISO format
439 // YYYY-MM-DDTHH:MM:SS
440 int ret = sscanf(date_string.c_str(), "%d-%d-%dT%d:%d:%d",
441 &(new_time.tm_year), &(new_time.tm_mon),
442 &(new_time.tm_mday), &(new_time.tm_hour),
443 &(new_time.tm_min), &(new_time.tm_sec));
445 // Be pretty picky about this, so
446 // that strange things don't happen
447 // if the save file has been edited
450 SG_LOG(SG_INPUT, SG_ALERT, "Date/time string " << date_string
451 << " not in YYYY-MM-DDTHH:MM:SS format; skipped");
455 // OK, it looks like we got six
456 // values, one way or another.
457 new_time.tm_year -= 1900;
458 new_time.tm_mon -= 1;
460 // Now, tell flight gear to use
461 // the new time. This was far
462 // too difficult, by the way.
464 mktime(&new_time) - mktime(current_time) + globals->get_warp();
465 double lon = current_aircraft.fdm_state->get_Longitude();
466 double lat = current_aircraft.fdm_state->get_Latitude();
467 globals->set_warp(warp);
468 st->update(lon, lat, warp);
469 fgUpdateSkyAndLightingParams();
473 * Return the GMT as a string.
480 struct tm * t = globals->get_time_params()->getGmt();
481 sprintf(buf, " %.2d:%.2d:%.2d",
482 t->tm_hour, t->tm_min, t->tm_sec);
489 * Get the texture rendering state.
494 return (material_lib.get_step() == 0);
499 * Set the texture rendering state.
502 setTextures (bool textures)
505 material_lib.set_step(0);
507 material_lib.set_step(1);
512 * Return the magnetic variation
517 return globals->get_mag()->get_magvar() * SGD_RADIANS_TO_DEGREES;
522 * Return the magnetic dip
527 return globals->get_mag()->get_magdip() * SGD_RADIANS_TO_DEGREES;
532 * Return the current heading in degrees.
537 return current_aircraft.fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES - getMagVar();
542 * Return the fuel level in tank 1
547 return current_aircraft.fdm_state->get_Tank1Fuel();
551 setTank1Fuel ( double gals )
553 current_aircraft.fdm_state->set_Tank1Fuel( gals );
557 * Return the fuel level in tank 2
562 return current_aircraft.fdm_state->get_Tank2Fuel();
566 setTank2Fuel ( double gals )
568 current_aircraft.fdm_state->set_Tank2Fuel( gals );
573 * Get the autopilot altitude lock (true=on).
578 return (current_autopilot->get_AltitudeEnabled() &&
579 current_autopilot->get_AltitudeMode()
580 == FGAutopilot::FG_ALTITUDE_LOCK);
585 * Set the autopilot altitude lock (true=on).
588 setAPAltitudeLock (bool lock)
590 current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_LOCK);
591 current_autopilot->set_AltitudeEnabled(lock);
596 * Get the autopilot target altitude in feet.
601 return current_autopilot->get_TargetAltitude() * SG_METER_TO_FEET;
606 * Set the autopilot target altitude in feet.
609 setAPAltitude (double altitude)
611 current_autopilot->set_TargetAltitude( altitude * SG_FEET_TO_METER );
615 * Get the autopilot altitude lock (true=on).
620 return (current_autopilot->get_AltitudeEnabled() &&
621 (current_autopilot->get_AltitudeMode()
622 == FGAutopilot::FG_ALTITUDE_GS1));
627 * Set the autopilot altitude lock (true=on).
630 setAPGSLock (bool lock)
632 current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_GS1);
633 current_autopilot->set_AltitudeEnabled(lock);
638 * Get the autopilot terrain lock (true=on).
643 return (current_autopilot->get_AltitudeEnabled() &&
644 (current_autopilot->get_AltitudeMode()
645 == FGAutopilot::FG_ALTITUDE_TERRAIN));
650 * Set the autopilot terrain lock (true=on).
653 setAPTerrainLock (bool lock)
655 current_autopilot->set_AltitudeMode(FGAutopilot::FG_ALTITUDE_TERRAIN);
656 current_autopilot->set_AltitudeEnabled(lock);
657 current_autopilot->set_TargetAGL(
658 current_aircraft.fdm_state->get_Altitude_AGL() * SG_FEET_TO_METER
660 cout << "Target AGL = "
661 << current_aircraft.fdm_state->get_Altitude_AGL() * SG_FEET_TO_METER
667 * Get the autopilot target altitude in feet.
672 return current_autopilot->get_TargetClimbRate() * SG_METER_TO_FEET;
677 * Set the autopilot target altitude in feet.
680 setAPClimb (double rate)
682 current_autopilot->set_TargetClimbRate( rate * SG_FEET_TO_METER );
687 * Get the autopilot heading lock (true=on).
693 (current_autopilot->get_HeadingEnabled() &&
694 current_autopilot->get_HeadingMode() == DEFAULT_AP_HEADING_LOCK);
699 * Set the autopilot heading lock (true=on).
702 setAPHeadingLock (bool lock)
705 current_autopilot->set_HeadingMode(DEFAULT_AP_HEADING_LOCK);
706 current_autopilot->set_HeadingEnabled(true);
708 current_autopilot->set_HeadingEnabled(false);
714 * Get the autopilot heading bug in degrees.
719 return current_autopilot->get_DGTargetHeading();
724 * Set the autopilot heading bug in degrees.
727 setAPHeadingBug (double heading)
729 current_autopilot->set_DGTargetHeading( heading );
734 * Get the autopilot wing leveler lock (true=on).
740 (current_autopilot->get_HeadingEnabled() &&
741 current_autopilot->get_HeadingMode() == FGAutopilot::FG_TC_HEADING_LOCK);
746 * Set the autopilot wing leveler lock (true=on).
749 setAPWingLeveler (bool lock)
752 current_autopilot->set_HeadingMode(FGAutopilot::FG_TC_HEADING_LOCK);
753 current_autopilot->set_HeadingEnabled(true);
755 current_autopilot->set_HeadingEnabled(false);
760 * Return true if the autopilot is locked to NAV1.
766 (current_autopilot->get_HeadingEnabled() &&
767 current_autopilot->get_HeadingMode() == FGAutopilot::FG_HEADING_NAV1);
772 * Set the autopilot NAV1 lock.
775 setAPNAV1Lock (bool lock)
778 current_autopilot->set_HeadingMode(FGAutopilot::FG_HEADING_NAV1);
779 current_autopilot->set_HeadingEnabled(true);
780 } else if (current_autopilot->get_HeadingMode() ==
781 FGAutopilot::FG_HEADING_NAV1) {
782 current_autopilot->set_HeadingEnabled(false);
787 * Get the autopilot autothrottle lock.
790 getAPAutoThrottleLock ()
792 return current_autopilot->get_AutoThrottleEnabled();
797 * Set the autothrottle lock.
800 setAPAutoThrottleLock (bool lock)
802 current_autopilot->set_AutoThrottleEnabled(lock);
808 getAPRudderControl ()
810 if (getAPHeadingLock())
811 return current_autopilot->get_TargetHeading();
813 return globals->get_controls()->get_rudder();
818 setAPRudderControl (double value)
820 if (getAPHeadingLock()) {
821 SG_LOG(SG_GENERAL, SG_DEBUG, "setAPRudderControl " << value );
822 value -= current_autopilot->get_TargetHeading();
823 current_autopilot->HeadingAdjust(value < 0.0 ? -1.0 : 1.0);
825 globals->get_controls()->set_rudder(value);
831 getAPElevatorControl ()
833 if (getAPAltitudeLock())
834 return current_autopilot->get_TargetAltitude();
836 return globals->get_controls()->get_elevator();
841 setAPElevatorControl (double value)
843 if (getAPAltitudeLock()) {
844 SG_LOG(SG_GENERAL, SG_DEBUG, "setAPElevatorControl " << value );
845 value -= current_autopilot->get_TargetAltitude();
846 current_autopilot->AltitudeAdjust(value < 0.0 ? 100.0 : -100.0);
848 globals->get_controls()->set_elevator(value);
854 getAPThrottleControl ()
856 if (getAPAutoThrottleLock())
857 return 0.0; // always resets
859 return globals->get_controls()->get_throttle(0);
864 setAPThrottleControl (double value)
866 if (getAPAutoThrottleLock())
867 current_autopilot->AutoThrottleAdjust(value < 0.0 ? -0.01 : 0.01);
869 globals->get_controls()->set_throttle(FGControls::ALL_ENGINES, value);
874 * Get the current visibility (meters).
879 #ifndef FG_OLD_WEATHER
880 return WeatherDatabase->getWeatherVisibility();
882 return current_weather.get_visibility();
888 * Set the current visibility (meters).
891 setVisibility (double visibility)
893 #ifndef FG_OLD_WEATHER
894 WeatherDatabase->setWeatherVisibility(visibility);
896 current_weather.set_visibility(visibility);
901 * Get the current wind north velocity (feet/second).
906 return current_aircraft.fdm_state->get_V_north_airmass();
911 * Set the current wind north velocity (feet/second).
914 setWindNorth (double speed)
916 current_aircraft.fdm_state
917 ->set_Velocities_Local_Airmass(speed, getWindEast(), getWindDown());
922 * Get the current wind east velocity (feet/second).
927 return current_aircraft.fdm_state->get_V_east_airmass();
932 * Set the current wind east velocity (feet/second).
935 setWindEast (double speed)
937 cout << "Set wind-east to " << speed << endl;
938 current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
945 * Get the current wind down velocity (feet/second).
950 return current_aircraft.fdm_state->get_V_down_airmass();
955 * Set the current wind down velocity (feet/second).
958 setWindDown (double speed)
960 current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
966 * Set the current engine0 running flag.
969 setRunningFlag (bool flag)
971 if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
972 current_aircraft.fdm_state->get_engine(0)->set_Running_Flag( flag );
977 * Set the current engine0 cranking flag.
979 //Although there is no real reason to want to tell the engine that it is cranking,
980 //this is currently necessary to avoid the cranking sound being played
981 //before the engine inits.
983 setCrankingFlag (bool flag)
985 if ( current_aircraft.fdm_state->get_num_engines() > 0 ) {
986 current_aircraft.fdm_state->get_engine(0)->set_Cranking_Flag( flag );
993 return globals->get_current_view()->get_fov();
1000 globals->get_current_view()->set_fov( fov );
1007 return globals->get_warp();
1013 globals->set_warp(warp);
1019 return globals->get_warp_delta();
1023 setWarpDelta (long delta)
1025 globals->set_warp_delta(delta);
1029 setViewAxisLong (double axis)
1035 setViewAxisLat (double axis)
1047 setWindingCCW (bool state)
1049 winding_ccw = state;
1051 glFrontFace ( GL_CCW );
1053 glFrontFace ( GL_CW );
1059 #if defined(FX) && !defined(WIN32)
1060 return global_fullscreen;
1067 setFullScreen (bool state)
1069 #if defined(FX) && !defined(WIN32)
1070 global_fullscreen = state;
1071 # if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
1072 XMesaSetFXmode( global_fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
1078 getFDMDataLogging ()
1080 return fdm_data_logging;
1084 setFDMDataLogging (bool state)
1086 // kludge; no getter or setter available
1087 if (state != fdm_data_logging) {
1088 fgToggleFDMdataLogging();
1089 fdm_data_logging = state;
1094 ////////////////////////////////////////////////////////////////////////
1095 // Tie the properties.
1096 ////////////////////////////////////////////////////////////////////////
1102 fgTie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
1103 fgTie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
1104 fgTie("/sim/freeze", getFreeze, setFreeze);
1105 fgTie("/sim/aircraft-dir", getAircraftDir, setAircraftDir);
1106 fgTie("/sim/view/offset-deg", getViewOffset, setViewOffset, false);
1107 fgSetArchivable("/sim/view/offset-deg");
1108 fgTie("/sim/view/goal-offset-deg", getGoalViewOffset, setGoalViewOffset, false);
1109 fgSetArchivable("/sim/view/goal-offset-deg");
1110 fgTie("/sim/view/pilot/x-offset-m",
1111 getPilotPositionXOffset, setPilotPositionXOffset);
1112 fgSetArchivable("/sim/view/pilot/x-offset-m");
1113 fgTie("/sim/view/pilot/y-offset-m",
1114 getPilotPositionYOffset, setPilotPositionYOffset);
1115 fgSetArchivable("/sim/view/pilot/y-offset-m");
1116 fgTie("/sim/view/pilot/z-offset-m",
1117 getPilotPositionZOffset, setPilotPositionZOffset);
1118 fgSetArchivable("/sim/view/pilot/z-offset-m");
1119 fgTie("/sim/time/gmt", getDateString, setDateString);
1120 fgSetArchivable("/sim/time/gmt");
1121 fgTie("/sim/time/gmt-string", getGMTString);
1122 fgTie("/sim/rendering/textures", getTextures, setTextures);
1125 fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
1128 fgTie("/consumables/fuel/tank[0]/level-gal_us",
1129 getTank1Fuel, setTank1Fuel, false);
1130 fgSetArchivable("/consumables/fuel/tank[0]/level-gal_us");
1131 fgTie("/consumables/fuel/tank[1]/level-gal_us",
1132 getTank2Fuel, setTank2Fuel, false);
1133 fgSetArchivable("/consumables/fuel/tank[1]/level-gal_us");
1136 fgTie("/autopilot/locks/altitude", getAPAltitudeLock, setAPAltitudeLock);
1137 fgSetArchivable("/autopilot/locks/altitude");
1138 fgTie("/autopilot/settings/altitude-ft", getAPAltitude, setAPAltitude);
1139 fgSetArchivable("/autopilot/settings/altitude-ft");
1140 fgTie("/autopilot/locks/glide-slope", getAPGSLock, setAPGSLock);
1141 fgSetArchivable("/autopilot/locks/glide-slope");
1142 fgTie("/autopilot/locks/terrain", getAPTerrainLock, setAPTerrainLock);
1143 fgSetArchivable("/autopilot/locks/terrain");
1144 fgTie("/autopilot/settings/agl-ft", getAPAltitude, setAPAltitude);
1145 fgSetArchivable("/autopilot/settings/agl-ft");
1146 fgTie("/autopilot/settings/climb-rate-fpm", getAPClimb, setAPClimb, false);
1147 fgSetArchivable("/autopilot/settings/climb-rate-fpm");
1148 fgTie("/autopilot/locks/heading", getAPHeadingLock, setAPHeadingLock);
1149 fgSetArchivable("/autopilot/locks/heading");
1150 fgTie("/autopilot/settings/heading-bug-deg",
1151 getAPHeadingBug, setAPHeadingBug, false);
1152 fgSetArchivable("/autopilot/settings/heading-bug-deg");
1153 fgTie("/autopilot/locks/wing-leveler", getAPWingLeveler, setAPWingLeveler);
1154 fgSetArchivable("/autopilot/locks/wing-leveler");
1155 fgTie("/autopilot/locks/nav[0]", getAPNAV1Lock, setAPNAV1Lock);
1156 fgSetArchivable("/autopilot/locks/nav[0]");
1157 fgTie("/autopilot/locks/auto-throttle",
1158 getAPAutoThrottleLock, setAPAutoThrottleLock);
1159 fgSetArchivable("/autopilot/locks/auto-throttle");
1160 fgTie("/autopilot/control-overrides/rudder",
1161 getAPRudderControl, setAPRudderControl);
1162 fgSetArchivable("/autopilot/control-overrides/rudder");
1163 fgTie("/autopilot/control-overrides/elevator",
1164 getAPElevatorControl, setAPElevatorControl);
1165 fgSetArchivable("/autopilot/control-overrides/elevator");
1166 fgTie("/autopilot/control-overrides/throttle",
1167 getAPThrottleControl, setAPThrottleControl);
1168 fgSetArchivable("/autopilot/control-overrides/throttle");
1171 fgTie("/environment/visibility-m", getVisibility, setVisibility);
1172 fgSetArchivable("/environment/visibility-m");
1173 fgTie("/environment/wind-north-fps", getWindNorth, setWindNorth);
1174 fgSetArchivable("/environment/wind-north-fps");
1175 fgTie("/environment/wind-east-fps", getWindEast, setWindEast);
1176 fgSetArchivable("/environment/wind-east-fps");
1177 fgTie("/environment/wind-down-fps", getWindDown, setWindDown);
1178 fgSetArchivable("/environment/wind-down-fps");
1180 fgTie("/environment/magnetic-variation-deg", getMagVar);
1181 fgTie("/environment/magnetic-dip-deg", getMagDip);
1184 fgTie("/sim/field-of-view", getFOV, setFOV);
1185 fgSetArchivable("/sim/field-of-view");
1186 fgTie("/sim/time/warp", getWarp, setWarp, false);
1187 fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
1188 fgTie("/sim/view/axes/long", (double(*)())0, setViewAxisLong);
1189 fgTie("/sim/view/axes/lat", (double(*)())0, setViewAxisLat);
1191 // Misc. Temporary junk.
1192 fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW, false);
1193 fgTie("/sim/temp/full-screen", getFullScreen, setFullScreen);
1194 fgTie("/sim/temp/fdm-data-logging", getFDMDataLogging, setFDMDataLogging);
1202 _set_view_from_axes();
1207 ////////////////////////////////////////////////////////////////////////
1208 // Save and restore.
1209 ////////////////////////////////////////////////////////////////////////
1213 * Save the current state of the simulator to a stream.
1216 fgSaveFlight (ostream &output)
1219 writeProperties(output, globals->get_props());
1220 } catch (const sg_exception &e) {
1221 guiErrorMessage("Error saving flight: ", e);
1229 * Restore the current state of the simulator from a stream.
1232 fgLoadFlight (istream &input)
1234 SGPropertyNode props;
1236 readProperties(input, &props);
1237 } catch (const sg_exception &e) {
1238 guiErrorMessage("Error reading saved flight: ", e);
1241 copyProperties(&props, globals->get_props());
1242 // When loading a flight, make it the
1243 // new initial state.
1244 globals->saveInitialState();
1250 ////////////////////////////////////////////////////////////////////////
1251 // Implementation of FGCondition.
1252 ////////////////////////////////////////////////////////////////////////
1254 FGCondition::FGCondition ()
1258 FGCondition::~FGCondition ()
1264 ////////////////////////////////////////////////////////////////////////
1265 // Implementation of FGPropertyCondition.
1266 ////////////////////////////////////////////////////////////////////////
1268 FGPropertyCondition::FGPropertyCondition (const string &propname)
1269 : _node(fgGetNode(propname, true))
1273 FGPropertyCondition::~FGPropertyCondition ()
1279 ////////////////////////////////////////////////////////////////////////
1280 // Implementation of FGNotCondition.
1281 ////////////////////////////////////////////////////////////////////////
1283 FGNotCondition::FGNotCondition (FGCondition * condition)
1284 : _condition(condition)
1288 FGNotCondition::~FGNotCondition ()
1294 FGNotCondition::test () const
1296 return !(_condition->test());
1301 ////////////////////////////////////////////////////////////////////////
1302 // Implementation of FGAndCondition.
1303 ////////////////////////////////////////////////////////////////////////
1305 FGAndCondition::FGAndCondition ()
1309 FGAndCondition::~FGAndCondition ()
1311 for (unsigned int i = 0; i < _conditions.size(); i++)
1312 delete _conditions[i];
1316 FGAndCondition::test () const
1318 int nConditions = _conditions.size();
1319 for (int i = 0; i < nConditions; i++) {
1320 if (!_conditions[i]->test())
1327 FGAndCondition::addCondition (FGCondition * condition)
1329 _conditions.push_back(condition);
1334 ////////////////////////////////////////////////////////////////////////
1335 // Implementation of FGOrCondition.
1336 ////////////////////////////////////////////////////////////////////////
1338 FGOrCondition::FGOrCondition ()
1342 FGOrCondition::~FGOrCondition ()
1344 for (unsigned int i = 0; i < _conditions.size(); i++)
1345 delete _conditions[i];
1349 FGOrCondition::test () const
1351 int nConditions = _conditions.size();
1352 for (int i = 0; i < nConditions; i++) {
1353 if (_conditions[i]->test())
1360 FGOrCondition::addCondition (FGCondition * condition)
1362 _conditions.push_back(condition);
1367 ////////////////////////////////////////////////////////////////////////
1368 // Implementation of FGComparisonCondition.
1369 ////////////////////////////////////////////////////////////////////////
1372 doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
1374 switch (left->getType()) {
1375 case SGPropertyNode::BOOL: {
1376 bool v1 = left->getBoolValue();
1377 bool v2 = right->getBoolValue();
1379 return FGComparisonCondition::LESS_THAN;
1381 return FGComparisonCondition::GREATER_THAN;
1383 return FGComparisonCondition::EQUALS;
1386 case SGPropertyNode::INT: {
1387 int v1 = left->getIntValue();
1388 int v2 = right->getIntValue();
1390 return FGComparisonCondition::LESS_THAN;
1392 return FGComparisonCondition::GREATER_THAN;
1394 return FGComparisonCondition::EQUALS;
1397 case SGPropertyNode::LONG: {
1398 long v1 = left->getLongValue();
1399 long v2 = right->getLongValue();
1401 return FGComparisonCondition::LESS_THAN;
1403 return FGComparisonCondition::GREATER_THAN;
1405 return FGComparisonCondition::EQUALS;
1408 case SGPropertyNode::FLOAT: {
1409 float v1 = left->getFloatValue();
1410 float v2 = right->getFloatValue();
1412 return FGComparisonCondition::LESS_THAN;
1414 return FGComparisonCondition::GREATER_THAN;
1416 return FGComparisonCondition::EQUALS;
1419 case SGPropertyNode::DOUBLE: {
1420 double v1 = left->getDoubleValue();
1421 double v2 = right->getDoubleValue();
1423 return FGComparisonCondition::LESS_THAN;
1425 return FGComparisonCondition::GREATER_THAN;
1427 return FGComparisonCondition::EQUALS;
1430 case SGPropertyNode::STRING:
1431 case SGPropertyNode::NONE:
1432 case SGPropertyNode::UNSPECIFIED: {
1433 string v1 = left->getStringValue();
1434 string v2 = right->getStringValue();
1436 return FGComparisonCondition::LESS_THAN;
1438 return FGComparisonCondition::GREATER_THAN;
1440 return FGComparisonCondition::EQUALS;
1444 throw sg_exception("Unrecognized node type");
1449 FGComparisonCondition::FGComparisonCondition (Type type, bool reverse)
1458 FGComparisonCondition::~FGComparisonCondition ()
1460 delete _right_value;
1464 FGComparisonCondition::test () const
1466 // Always fail if incompletely specified
1467 if (_left_property == 0 ||
1468 (_right_property == 0 && _right_value == 0))
1471 // Get LESS_THAN, EQUALS, or GREATER_THAN
1473 doComparison(_left_property,
1474 (_right_property != 0 ? _right_property : _right_value));
1476 return (cmp == _type);
1478 return (cmp != _type);
1482 FGComparisonCondition::setLeftProperty (const string &propname)
1484 _left_property = fgGetNode(propname, true);
1488 FGComparisonCondition::setRightProperty (const string &propname)
1490 delete _right_value;
1492 _right_property = fgGetNode(propname, true);
1496 FGComparisonCondition::setRightValue (const SGPropertyNode *node)
1498 _right_property = 0;
1499 delete _right_value;
1500 _right_value = new SGPropertyNode(*node);
1505 ////////////////////////////////////////////////////////////////////////
1506 // Read a condition and use it if necessary.
1507 ////////////////////////////////////////////////////////////////////////
1509 // Forward declaration
1510 static FGCondition * readCondition (const SGPropertyNode * node);
1512 static FGCondition *
1513 readPropertyCondition (const SGPropertyNode * node)
1515 return new FGPropertyCondition(node->getStringValue());
1518 static FGCondition *
1519 readNotCondition (const SGPropertyNode * node)
1521 int nChildren = node->nChildren();
1522 for (int i = 0; i < nChildren; i++) {
1523 const SGPropertyNode * child = node->getChild(i);
1524 FGCondition * condition = readCondition(child);
1526 return new FGNotCondition(condition);
1528 SG_LOG(SG_COCKPIT, SG_ALERT, "Panel: empty 'not' condition");
1532 static FGCondition *
1533 readAndConditions (const SGPropertyNode * node)
1535 FGAndCondition * andCondition = new FGAndCondition;
1536 int nChildren = node->nChildren();
1537 for (int i = 0; i < nChildren; i++) {
1538 const SGPropertyNode * child = node->getChild(i);
1539 FGCondition * condition = readCondition(child);
1541 andCondition->addCondition(condition);
1543 return andCondition;
1546 static FGCondition *
1547 readOrConditions (const SGPropertyNode * node)
1549 FGOrCondition * orCondition = new FGOrCondition;
1550 int nChildren = node->nChildren();
1551 for (int i = 0; i < nChildren; i++) {
1552 const SGPropertyNode * child = node->getChild(i);
1553 FGCondition * condition = readCondition(child);
1555 orCondition->addCondition(condition);
1560 static FGCondition *
1561 readComparison (const SGPropertyNode * node,
1562 FGComparisonCondition::Type type,
1565 FGComparisonCondition * condition = new FGComparisonCondition(type, reverse);
1566 condition->setLeftProperty(node->getStringValue("property[0]"));
1567 if (node->hasValue("property[1]"))
1568 condition->setRightProperty(node->getStringValue("property[1]"));
1570 condition->setRightValue(node->getChild("value", 0));
1575 static FGCondition *
1576 readCondition (const SGPropertyNode * node)
1578 const string &name = node->getName();
1579 if (name == "property")
1580 return readPropertyCondition(node);
1581 else if (name == "not")
1582 return readNotCondition(node);
1583 else if (name == "and")
1584 return readAndConditions(node);
1585 else if (name == "or")
1586 return readOrConditions(node);
1587 else if (name == "less-than")
1588 return readComparison(node, FGComparisonCondition::LESS_THAN, false);
1589 else if (name == "less-than-equals")
1590 return readComparison(node, FGComparisonCondition::GREATER_THAN, true);
1591 else if (name == "greater-than")
1592 return readComparison(node, FGComparisonCondition::GREATER_THAN, false);
1593 else if (name == "greater-than-equals")
1594 return readComparison(node, FGComparisonCondition::LESS_THAN, true);
1595 else if (name == "equals")
1596 return readComparison(node, FGComparisonCondition::EQUALS, false);
1597 else if (name == "not-equals")
1598 return readComparison(node, FGComparisonCondition::EQUALS, true);
1605 ////////////////////////////////////////////////////////////////////////
1606 // Implementation of FGConditional.
1607 ////////////////////////////////////////////////////////////////////////
1609 FGConditional::FGConditional ()
1614 FGConditional::~FGConditional ()
1620 FGConditional::setCondition (FGCondition * condition)
1623 _condition = condition;
1627 FGConditional::test () const
1629 return ((_condition == 0) || _condition->test());
1634 // The top-level is always an implicit 'and' group
1636 fgReadCondition (const SGPropertyNode * node)
1638 return readAndConditions(node);
1642 // end of fg_props.cxx