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 <Aircraft/aircraft.hxx>
33 #include <Time/tmp.hxx>
34 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
35 #ifndef FG_NEW_ENVIRONMENT
36 # include <WeatherCM/FGLocalWeatherDatabase.h>
38 # include <Environment/environment.hxx>
39 #endif // FG_NEW_ENVIRONMENT
40 #include <Objects/matlib.hxx>
44 #include "globals.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 #if !defined(FG_NEW_ENVIRONMENT)
55 static double getWindNorth ();
56 static double getWindEast ();
57 static double getWindDown ();
58 #endif // FG_NEW_ENVIRONMENT
60 // Allow the view to be set from two axes (i.e. a joystick hat)
61 // This needs to be in FGViewer itself, somehow.
62 static double axisLong = 0.0;
63 static double axisLat = 0.0;
65 static bool winding_ccw = true; // FIXME: temporary
67 static bool fdm_data_logging = false; // FIXME: temporary
74 _set_view_from_axes ()
76 // Take no action when hat is centered
77 if ( ( axisLong < 0.01 ) &&
78 ( axisLong > -0.01 ) &&
86 /* Do all the quick and easy cases */
87 if (axisLong < 0) { // Longitudinal axis forward
88 if (axisLat == axisLong)
90 else if (axisLat == - axisLong)
92 else if (axisLat == 0)
94 } else if (axisLong > 0) { // Longitudinal axis backward
95 if (axisLat == - axisLong)
97 else if (axisLat == axisLong)
99 else if (axisLat == 0)
101 } else if (axisLong == 0) { // Longitudinal axis neutral
104 else if (axisLat > 0)
106 else return; /* And assertion failure maybe? */
109 /* Do all the difficult cases */
111 viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axisLat, -axisLong );
112 if ( viewDir < -1 ) viewDir += 360;
114 // SG_LOG(SG_INPUT, SG_ALERT, "Joystick Lat=" << axisLat << " and Long="
115 // << axisLong << " gave angle=" << viewDir );
117 globals->get_current_view()->set_goal_view_offset(viewDir*SGD_DEGREES_TO_RADIANS);
118 // globals->get_current_view()->set_view_offset(viewDir*SGD_DEGREES_TO_RADIANS);
122 ////////////////////////////////////////////////////////////////////////
123 // Default property bindings (not yet handled by any module).
124 ////////////////////////////////////////////////////////////////////////
126 struct LogClassMapping {
129 LogClassMapping(sgDebugClass cc, string nname) { c = cc; name = nname; }
132 LogClassMapping log_class_mappings [] = {
133 LogClassMapping(SG_NONE, "none"),
134 LogClassMapping(SG_TERRAIN, "terrain"),
135 LogClassMapping(SG_ASTRO, "astro"),
136 LogClassMapping(SG_FLIGHT, "flight"),
137 LogClassMapping(SG_INPUT, "input"),
138 LogClassMapping(SG_GL, "gl"),
139 LogClassMapping(SG_VIEW, "view"),
140 LogClassMapping(SG_COCKPIT, "cockpit"),
141 LogClassMapping(SG_GENERAL, "general"),
142 LogClassMapping(SG_MATH, "math"),
143 LogClassMapping(SG_EVENT, "event"),
144 LogClassMapping(SG_AIRCRAFT, "aircraft"),
145 LogClassMapping(SG_AUTOPILOT, "autopilot"),
146 LogClassMapping(SG_IO, "io"),
147 LogClassMapping(SG_CLIPPER, "clipper"),
148 LogClassMapping(SG_NETWORK, "network"),
149 LogClassMapping(SG_UNDEFD, "")
154 * Get the logging classes.
159 sgDebugClass classes = logbuf::get_log_classes();
161 for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
162 if ((classes&log_class_mappings[i].c) > 0) {
163 if (result != (string)"")
165 result += log_class_mappings[i].name;
172 static void addLoggingClass (const string &name)
174 sgDebugClass classes = logbuf::get_log_classes();
175 for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
176 if (name == log_class_mappings[i].name) {
177 logbuf::set_log_classes(sgDebugClass(classes|log_class_mappings[i].c));
181 SG_LOG(SG_GENERAL, SG_ALERT, "Unknown logging class: " << name);
186 * Set the logging classes.
189 setLoggingClasses (string classes)
191 logbuf::set_log_classes(SG_NONE);
193 if (classes == "none") {
194 SG_LOG(SG_GENERAL, SG_INFO, "Disabled all logging classes");
198 if (classes == "" || classes == "all") { // default
199 logbuf::set_log_classes(SG_ALL);
200 SG_LOG(SG_GENERAL, SG_INFO, "Enabled all logging classes: "
201 << getLoggingClasses());
205 string rest = classes;
207 int sep = rest.find('|');
209 name = rest.substr(0, sep);
210 rest = rest.substr(sep+1);
211 addLoggingClass(name);
212 sep = rest.find('|');
214 addLoggingClass(rest);
215 SG_LOG(SG_GENERAL, SG_INFO, "Set logging classes to "
216 << getLoggingClasses());
221 * Get the logging priority.
224 getLoggingPriority ()
226 switch (logbuf::get_log_priority()) {
238 SG_LOG(SG_GENERAL, SG_WARN, "Internal: Unknown logging priority number: "
239 << logbuf::get_log_priority());
246 * Set the logging priority.
249 setLoggingPriority (string priority)
251 if (priority == "bulk") {
252 logbuf::set_log_priority(SG_BULK);
253 } else if (priority == "debug") {
254 logbuf::set_log_priority(SG_DEBUG);
255 } else if (priority == "" || priority == "info") { // default
256 logbuf::set_log_priority(SG_INFO);
257 } else if (priority == "warn") {
258 logbuf::set_log_priority(SG_WARN);
259 } else if (priority == "alert") {
260 logbuf::set_log_priority(SG_ALERT);
262 SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority " << priority);
264 SG_LOG(SG_GENERAL, SG_INFO, "Logging priority is " << getLoggingPriority());
270 * Get the pause state of the sim.
275 return globals->get_freeze();
280 * Set the pause state of the sim.
283 setFreeze (bool freeze)
285 globals->set_freeze(freeze);
288 current_atcdisplay->CancelRepeatingMessage();
289 current_atcdisplay->RegisterRepeatingMessage("**** SIM IS FROZEN **** SIM IS FROZEN ****");
292 current_atcdisplay->CancelRepeatingMessage();
298 * Return the current aircraft directory (UIUC) as a string.
308 * Set the current aircraft directory (UIUC).
311 setAircraftDir (string dir)
313 if (getAircraftDir() != dir) {
315 // needReinit(); FIXME!!
321 * Get the current view offset in degrees.
326 return (globals->get_current_view()
327 ->get_view_offset() * SGD_RADIANS_TO_DEGREES);
332 setViewOffset (double offset)
334 globals->get_current_view()->set_view_offset(offset * SGD_DEGREES_TO_RADIANS);
340 return (globals->get_current_view()
341 ->get_goal_view_offset() * SGD_RADIANS_TO_DEGREES);
345 setGoalViewOffset (double offset)
347 while ( offset < 0 ) {
350 while ( offset > 360.0 ) {
353 // Snap to center if we are close
354 if ( fabs(offset) < 1.0 || fabs(offset) > 359.0 ) {
358 globals->get_current_view()
359 ->set_goal_view_offset(offset * SGD_DEGREES_TO_RADIANS);
363 * Get the current view tilt in degrees.
368 return (globals->get_current_view()
369 ->get_view_tilt() * SGD_RADIANS_TO_DEGREES);
374 setViewTilt (double tilt)
376 globals->get_current_view()->set_view_tilt(tilt * SGD_DEGREES_TO_RADIANS);
382 return (globals->get_current_view()
383 ->get_goal_view_tilt() * SGD_RADIANS_TO_DEGREES);
387 setGoalViewTilt (double tilt)
392 while ( tilt > 360.0 ) {
395 // Snap to center if we are close
396 if ( fabs(tilt) < 1.0 || fabs(tilt) > 359.0 ) {
400 globals->get_current_view()
401 ->set_goal_view_tilt(tilt * SGD_DEGREES_TO_RADIANS);
406 * Pilot position offset from CG.
409 getPilotPositionXOffset ()
411 FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
412 float * offset = pilot_view->get_pilot_offset();
417 setPilotPositionXOffset (float x)
419 FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
420 float * offset = pilot_view->get_pilot_offset();
421 pilot_view->set_pilot_offset(x, offset[1], offset[2]);
425 getPilotPositionYOffset ()
427 FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
428 float * offset = pilot_view->get_pilot_offset();
433 setPilotPositionYOffset (float y)
435 FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
436 float * offset = pilot_view->get_pilot_offset();
437 pilot_view->set_pilot_offset(offset[0], y, offset[2]);
441 getPilotPositionZOffset ()
443 FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
444 float * offset = pilot_view->get_pilot_offset();
449 setPilotPositionZOffset (float z)
451 FGViewer * pilot_view = globals->get_viewmgr()->get_view(0);
452 float * offset = pilot_view->get_pilot_offset();
453 pilot_view->set_pilot_offset(offset[0], offset[1], z);
458 * Return the number of milliseconds elapsed since simulation started.
463 return globals->get_elapsed_time_ms();
468 * Return the current Zulu time.
475 struct tm * t = globals->get_time_params()->getGmt();
476 sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
477 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
478 t->tm_hour, t->tm_min, t->tm_sec);
485 * Set the current Zulu time.
488 setDateString (string date_string)
490 static const SGPropertyNode *cur_time_override
491 = fgGetNode("/sim/time/cur-time-override", true);
493 SGTime * st = globals->get_time_params();
494 struct tm * current_time = st->getGmt();
497 // Scan for basic ISO format
498 // YYYY-MM-DDTHH:MM:SS
499 int ret = sscanf(date_string.c_str(), "%d-%d-%dT%d:%d:%d",
500 &(new_time.tm_year), &(new_time.tm_mon),
501 &(new_time.tm_mday), &(new_time.tm_hour),
502 &(new_time.tm_min), &(new_time.tm_sec));
504 // Be pretty picky about this, so
505 // that strange things don't happen
506 // if the save file has been edited
509 SG_LOG(SG_INPUT, SG_ALERT, "Date/time string " << date_string
510 << " not in YYYY-MM-DDTHH:MM:SS format; skipped");
514 // OK, it looks like we got six
515 // values, one way or another.
516 new_time.tm_year -= 1900;
517 new_time.tm_mon -= 1;
519 // Now, tell flight gear to use
520 // the new time. This was far
521 // too difficult, by the way.
523 mktime(&new_time) - mktime(current_time) + globals->get_warp();
524 double lon = current_aircraft.fdm_state->get_Longitude();
525 double lat = current_aircraft.fdm_state->get_Latitude();
526 globals->set_warp(warp);
527 st->update(lon, lat, cur_time_override->getLongValue(), warp);
528 fgUpdateSkyAndLightingParams();
532 * Return the GMT as a string.
539 struct tm *t = globals->get_time_params()->getGmt();
540 sprintf(buf, " %.2d:%.2d:%.2d",
541 t->tm_hour, t->tm_min, t->tm_sec);
542 // cout << t << " " << buf << endl;
549 * Get the texture rendering state.
554 return (material_lib.get_step() == 0);
559 * Set the texture rendering state.
562 setTextures (bool textures)
565 material_lib.set_step(0);
567 material_lib.set_step(1);
572 * Return the magnetic variation
577 return globals->get_mag()->get_magvar() * SGD_RADIANS_TO_DEGREES;
582 * Return the magnetic dip
587 return globals->get_mag()->get_magdip() * SGD_RADIANS_TO_DEGREES;
592 * Return the current heading in degrees.
597 return current_aircraft.fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES - getMagVar();
601 #if !defined(FG_NEW_ENVIRONMENT)
604 * Get the current visibility (meters).
609 return WeatherDatabase->getWeatherVisibility();
614 * Set the current visibility (meters).
617 setVisibility (double visibility)
619 WeatherDatabase->setWeatherVisibility(visibility);
623 * Get the current wind north velocity (feet/second).
628 return current_aircraft.fdm_state->get_V_north_airmass();
633 * Set the current wind north velocity (feet/second).
636 setWindNorth (double speed)
638 current_aircraft.fdm_state
639 ->set_Velocities_Local_Airmass(speed, getWindEast(), getWindDown());
644 * Get the current wind east velocity (feet/second).
649 return current_aircraft.fdm_state->get_V_east_airmass();
654 * Set the current wind east velocity (feet/second).
657 setWindEast (double speed)
659 cout << "Set wind-east to " << speed << endl;
660 current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
667 * Get the current wind down velocity (feet/second).
672 return current_aircraft.fdm_state->get_V_down_airmass();
677 * Set the current wind down velocity (feet/second).
680 setWindDown (double speed)
682 current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
687 #endif // FG_NEW_ENVIRONMENT
692 return globals->get_current_view()->get_fov();
699 globals->get_current_view()->set_fov( fov );
706 return globals->get_warp();
712 globals->set_warp(warp);
718 return globals->get_warp_delta();
722 setWarpDelta (long delta)
724 globals->set_warp_delta(delta);
728 setViewAxisLong (double axis)
734 setViewAxisLat (double axis)
746 setWindingCCW (bool state)
750 glFrontFace ( GL_CCW );
752 glFrontFace ( GL_CW );
758 #if defined(FX) && !defined(WIN32)
759 return globals->get_fullscreen();
766 setFullScreen (bool state)
768 #if defined(FX) && !defined(WIN32)
769 globals->set_fullscreen(state);
770 # if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
771 XMesaSetFXmode( state ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
779 return fdm_data_logging;
783 setFDMDataLogging (bool state)
785 // kludge; no getter or setter available
786 if (state != fdm_data_logging) {
787 fgToggleFDMdataLogging();
788 fdm_data_logging = state;
793 ////////////////////////////////////////////////////////////////////////
794 // Tie the properties.
795 ////////////////////////////////////////////////////////////////////////
801 fgTie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
802 fgTie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
803 // fgTie("/sim/freeze", getFreeze, setFreeze);
804 fgTie("/sim/aircraft-dir", getAircraftDir, setAircraftDir);
805 fgTie("/sim/view/offset-deg", getViewOffset, setViewOffset, false);
806 fgSetArchivable("/sim/view/offset-deg");
807 fgTie("/sim/view/goal-offset-deg", getGoalViewOffset, setGoalViewOffset, false);
808 fgTie("/sim/view/tilt-deg", getViewTilt, setViewTilt, false);
809 fgSetArchivable("/sim/view/tilt-deg");
810 fgTie("/sim/view/goal-tilt-deg", getGoalViewTilt, setGoalViewTilt, false);
811 fgSetArchivable("/sim/view/goal-offset-deg");
812 fgTie("/sim/view/pilot/x-offset-m",
813 getPilotPositionXOffset, setPilotPositionXOffset);
814 fgSetArchivable("/sim/view/pilot/x-offset-m");
815 fgTie("/sim/view/pilot/y-offset-m",
816 getPilotPositionYOffset, setPilotPositionYOffset);
817 fgSetArchivable("/sim/view/pilot/y-offset-m");
818 fgTie("/sim/view/pilot/z-offset-m",
819 getPilotPositionZOffset, setPilotPositionZOffset);
820 fgSetArchivable("/sim/view/pilot/z-offset-m");
821 fgTie("/sim/time/elapsed-ms", getElapsedTime_ms);
822 fgTie("/sim/time/gmt", getDateString, setDateString);
823 fgSetArchivable("/sim/time/gmt");
824 fgTie("/sim/time/gmt-string", getGMTString);
825 fgTie("/sim/rendering/textures", getTextures, setTextures);
828 fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
831 #if !defined(FG_NEW_ENVIRONMENT)
832 fgTie("/environment/visibility-m", getVisibility, setVisibility);
833 fgSetArchivable("/environment/visibility-m");
834 fgTie("/environment/wind-from-north-fps", getWindNorth, setWindNorth);
835 fgSetArchivable("/environment/wind-from-north-fps");
836 fgTie("/environment/wind-from-east-fps", getWindEast, setWindEast);
837 fgSetArchivable("/environment/wind-from-east-fps");
838 fgTie("/environment/wind-from-down-fps", getWindDown, setWindDown);
839 fgSetArchivable("/environment/wind-from-down-fps");
842 fgTie("/environment/magnetic-variation-deg", getMagVar);
843 fgTie("/environment/magnetic-dip-deg", getMagDip);
846 fgTie("/sim/field-of-view", getFOV, setFOV);
847 fgSetArchivable("/sim/field-of-view");
848 fgTie("/sim/time/warp", getWarp, setWarp, false);
849 fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
850 fgTie("/sim/view/axes/long", (double(*)())0, setViewAxisLong);
851 fgTie("/sim/view/axes/lat", (double(*)())0, setViewAxisLat);
853 // Misc. Temporary junk.
854 fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW, false);
855 fgTie("/sim/temp/full-screen", getFullScreen, setFullScreen);
856 fgTie("/sim/temp/fdm-data-logging", getFDMDataLogging, setFDMDataLogging);
864 _set_view_from_axes();
869 ////////////////////////////////////////////////////////////////////////
871 ////////////////////////////////////////////////////////////////////////
875 * Save the current state of the simulator to a stream.
878 fgSaveFlight (ostream &output, bool write_all)
881 writeProperties(output, globals->get_props(), write_all);
882 } catch (const sg_exception &e) {
883 guiErrorMessage("Error saving flight: ", e);
891 * Restore the current state of the simulator from a stream.
894 fgLoadFlight (istream &input)
896 SGPropertyNode props;
898 readProperties(input, &props);
899 } catch (const sg_exception &e) {
900 guiErrorMessage("Error reading saved flight: ", e);
903 copyProperties(&props, globals->get_props());
904 // When loading a flight, make it the
905 // new initial state.
906 globals->saveInitialState();
912 ////////////////////////////////////////////////////////////////////////
913 // Implementation of FGCondition.
914 ////////////////////////////////////////////////////////////////////////
916 FGCondition::FGCondition ()
920 FGCondition::~FGCondition ()
926 ////////////////////////////////////////////////////////////////////////
927 // Implementation of FGPropertyCondition.
928 ////////////////////////////////////////////////////////////////////////
930 FGPropertyCondition::FGPropertyCondition (const string &propname)
931 : _node(fgGetNode(propname, true))
935 FGPropertyCondition::~FGPropertyCondition ()
941 ////////////////////////////////////////////////////////////////////////
942 // Implementation of FGNotCondition.
943 ////////////////////////////////////////////////////////////////////////
945 FGNotCondition::FGNotCondition (FGCondition * condition)
946 : _condition(condition)
950 FGNotCondition::~FGNotCondition ()
956 FGNotCondition::test () const
958 return !(_condition->test());
963 ////////////////////////////////////////////////////////////////////////
964 // Implementation of FGAndCondition.
965 ////////////////////////////////////////////////////////////////////////
967 FGAndCondition::FGAndCondition ()
971 FGAndCondition::~FGAndCondition ()
973 for (unsigned int i = 0; i < _conditions.size(); i++)
974 delete _conditions[i];
978 FGAndCondition::test () const
980 int nConditions = _conditions.size();
981 for (int i = 0; i < nConditions; i++) {
982 if (!_conditions[i]->test())
989 FGAndCondition::addCondition (FGCondition * condition)
991 _conditions.push_back(condition);
996 ////////////////////////////////////////////////////////////////////////
997 // Implementation of FGOrCondition.
998 ////////////////////////////////////////////////////////////////////////
1000 FGOrCondition::FGOrCondition ()
1004 FGOrCondition::~FGOrCondition ()
1006 for (unsigned int i = 0; i < _conditions.size(); i++)
1007 delete _conditions[i];
1011 FGOrCondition::test () const
1013 int nConditions = _conditions.size();
1014 for (int i = 0; i < nConditions; i++) {
1015 if (_conditions[i]->test())
1022 FGOrCondition::addCondition (FGCondition * condition)
1024 _conditions.push_back(condition);
1029 ////////////////////////////////////////////////////////////////////////
1030 // Implementation of FGComparisonCondition.
1031 ////////////////////////////////////////////////////////////////////////
1034 doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
1036 switch (left->getType()) {
1037 case SGPropertyNode::BOOL: {
1038 bool v1 = left->getBoolValue();
1039 bool v2 = right->getBoolValue();
1041 return FGComparisonCondition::LESS_THAN;
1043 return FGComparisonCondition::GREATER_THAN;
1045 return FGComparisonCondition::EQUALS;
1048 case SGPropertyNode::INT: {
1049 int v1 = left->getIntValue();
1050 int v2 = right->getIntValue();
1052 return FGComparisonCondition::LESS_THAN;
1054 return FGComparisonCondition::GREATER_THAN;
1056 return FGComparisonCondition::EQUALS;
1059 case SGPropertyNode::LONG: {
1060 long v1 = left->getLongValue();
1061 long v2 = right->getLongValue();
1063 return FGComparisonCondition::LESS_THAN;
1065 return FGComparisonCondition::GREATER_THAN;
1067 return FGComparisonCondition::EQUALS;
1070 case SGPropertyNode::FLOAT: {
1071 float v1 = left->getFloatValue();
1072 float v2 = right->getFloatValue();
1074 return FGComparisonCondition::LESS_THAN;
1076 return FGComparisonCondition::GREATER_THAN;
1078 return FGComparisonCondition::EQUALS;
1081 case SGPropertyNode::DOUBLE: {
1082 double v1 = left->getDoubleValue();
1083 double v2 = right->getDoubleValue();
1085 return FGComparisonCondition::LESS_THAN;
1087 return FGComparisonCondition::GREATER_THAN;
1089 return FGComparisonCondition::EQUALS;
1092 case SGPropertyNode::STRING:
1093 case SGPropertyNode::NONE:
1094 case SGPropertyNode::UNSPECIFIED: {
1095 string v1 = left->getStringValue();
1096 string v2 = right->getStringValue();
1098 return FGComparisonCondition::LESS_THAN;
1100 return FGComparisonCondition::GREATER_THAN;
1102 return FGComparisonCondition::EQUALS;
1106 throw sg_exception("Unrecognized node type");
1111 FGComparisonCondition::FGComparisonCondition (Type type, bool reverse)
1120 FGComparisonCondition::~FGComparisonCondition ()
1122 delete _right_value;
1126 FGComparisonCondition::test () const
1128 // Always fail if incompletely specified
1129 if (_left_property == 0 ||
1130 (_right_property == 0 && _right_value == 0))
1133 // Get LESS_THAN, EQUALS, or GREATER_THAN
1135 doComparison(_left_property,
1136 (_right_property != 0 ? _right_property : _right_value));
1138 return (cmp == _type);
1140 return (cmp != _type);
1144 FGComparisonCondition::setLeftProperty (const string &propname)
1146 _left_property = fgGetNode(propname, true);
1150 FGComparisonCondition::setRightProperty (const string &propname)
1152 delete _right_value;
1154 _right_property = fgGetNode(propname, true);
1158 FGComparisonCondition::setRightValue (const SGPropertyNode *node)
1160 _right_property = 0;
1161 delete _right_value;
1162 _right_value = new SGPropertyNode(*node);
1167 ////////////////////////////////////////////////////////////////////////
1168 // Read a condition and use it if necessary.
1169 ////////////////////////////////////////////////////////////////////////
1171 // Forward declaration
1172 static FGCondition * readCondition (const SGPropertyNode * node);
1174 static FGCondition *
1175 readPropertyCondition (const SGPropertyNode * node)
1177 return new FGPropertyCondition(node->getStringValue());
1180 static FGCondition *
1181 readNotCondition (const SGPropertyNode * node)
1183 int nChildren = node->nChildren();
1184 for (int i = 0; i < nChildren; i++) {
1185 const SGPropertyNode * child = node->getChild(i);
1186 FGCondition * condition = readCondition(child);
1188 return new FGNotCondition(condition);
1190 SG_LOG(SG_COCKPIT, SG_ALERT, "Panel: empty 'not' condition");
1194 static FGCondition *
1195 readAndConditions (const SGPropertyNode * node)
1197 FGAndCondition * andCondition = new FGAndCondition;
1198 int nChildren = node->nChildren();
1199 for (int i = 0; i < nChildren; i++) {
1200 const SGPropertyNode * child = node->getChild(i);
1201 FGCondition * condition = readCondition(child);
1203 andCondition->addCondition(condition);
1205 return andCondition;
1208 static FGCondition *
1209 readOrConditions (const SGPropertyNode * node)
1211 FGOrCondition * orCondition = new FGOrCondition;
1212 int nChildren = node->nChildren();
1213 for (int i = 0; i < nChildren; i++) {
1214 const SGPropertyNode * child = node->getChild(i);
1215 FGCondition * condition = readCondition(child);
1217 orCondition->addCondition(condition);
1222 static FGCondition *
1223 readComparison (const SGPropertyNode * node,
1224 FGComparisonCondition::Type type,
1227 FGComparisonCondition * condition = new FGComparisonCondition(type, reverse);
1228 condition->setLeftProperty(node->getStringValue("property[0]"));
1229 if (node->hasValue("property[1]"))
1230 condition->setRightProperty(node->getStringValue("property[1]"));
1232 condition->setRightValue(node->getChild("value", 0));
1237 static FGCondition *
1238 readCondition (const SGPropertyNode * node)
1240 const string &name = node->getName();
1241 if (name == "property")
1242 return readPropertyCondition(node);
1243 else if (name == "not")
1244 return readNotCondition(node);
1245 else if (name == "and")
1246 return readAndConditions(node);
1247 else if (name == "or")
1248 return readOrConditions(node);
1249 else if (name == "less-than")
1250 return readComparison(node, FGComparisonCondition::LESS_THAN, false);
1251 else if (name == "less-than-equals")
1252 return readComparison(node, FGComparisonCondition::GREATER_THAN, true);
1253 else if (name == "greater-than")
1254 return readComparison(node, FGComparisonCondition::GREATER_THAN, false);
1255 else if (name == "greater-than-equals")
1256 return readComparison(node, FGComparisonCondition::LESS_THAN, true);
1257 else if (name == "equals")
1258 return readComparison(node, FGComparisonCondition::EQUALS, false);
1259 else if (name == "not-equals")
1260 return readComparison(node, FGComparisonCondition::EQUALS, true);
1267 ////////////////////////////////////////////////////////////////////////
1268 // Implementation of FGConditional.
1269 ////////////////////////////////////////////////////////////////////////
1271 FGConditional::FGConditional ()
1276 FGConditional::~FGConditional ()
1282 FGConditional::setCondition (FGCondition * condition)
1285 _condition = condition;
1289 FGConditional::test () const
1291 return ((_condition == 0) || _condition->test());
1296 // The top-level is always an implicit 'and' group
1298 fgReadCondition (const SGPropertyNode * node)
1300 return readAndConditions(node);
1304 // end of fg_props.cxx