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"
48 #if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
49 SG_USING_STD(istream);
50 SG_USING_STD(ostream);
53 #if !defined(FG_NEW_ENVIRONMENT)
54 static double getWindNorth ();
55 static double getWindEast ();
56 static double getWindDown ();
57 #endif // FG_NEW_ENVIRONMENT
59 static bool winding_ccw = true; // FIXME: temporary
61 static bool fdm_data_logging = false; // FIXME: temporary
65 ////////////////////////////////////////////////////////////////////////
66 // Default property bindings (not yet handled by any module).
67 ////////////////////////////////////////////////////////////////////////
69 struct LogClassMapping {
72 LogClassMapping(sgDebugClass cc, string nname) { c = cc; name = nname; }
75 LogClassMapping log_class_mappings [] = {
76 LogClassMapping(SG_NONE, "none"),
77 LogClassMapping(SG_TERRAIN, "terrain"),
78 LogClassMapping(SG_ASTRO, "astro"),
79 LogClassMapping(SG_FLIGHT, "flight"),
80 LogClassMapping(SG_INPUT, "input"),
81 LogClassMapping(SG_GL, "gl"),
82 LogClassMapping(SG_VIEW, "view"),
83 LogClassMapping(SG_COCKPIT, "cockpit"),
84 LogClassMapping(SG_GENERAL, "general"),
85 LogClassMapping(SG_MATH, "math"),
86 LogClassMapping(SG_EVENT, "event"),
87 LogClassMapping(SG_AIRCRAFT, "aircraft"),
88 LogClassMapping(SG_AUTOPILOT, "autopilot"),
89 LogClassMapping(SG_IO, "io"),
90 LogClassMapping(SG_CLIPPER, "clipper"),
91 LogClassMapping(SG_NETWORK, "network"),
92 LogClassMapping(SG_UNDEFD, "")
97 * Get the logging classes.
102 sgDebugClass classes = logbuf::get_log_classes();
104 for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
105 if ((classes&log_class_mappings[i].c) > 0) {
106 if (result != (string)"")
108 result += log_class_mappings[i].name;
115 static void addLoggingClass (const string &name)
117 sgDebugClass classes = logbuf::get_log_classes();
118 for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
119 if (name == log_class_mappings[i].name) {
120 logbuf::set_log_classes(sgDebugClass(classes|log_class_mappings[i].c));
124 SG_LOG(SG_GENERAL, SG_ALERT, "Unknown logging class: " << name);
129 * Set the logging classes.
132 setLoggingClasses (string classes)
134 logbuf::set_log_classes(SG_NONE);
136 if (classes == "none") {
137 SG_LOG(SG_GENERAL, SG_INFO, "Disabled all logging classes");
141 if (classes == "" || classes == "all") { // default
142 logbuf::set_log_classes(SG_ALL);
143 SG_LOG(SG_GENERAL, SG_INFO, "Enabled all logging classes: "
144 << getLoggingClasses());
148 string rest = classes;
150 int sep = rest.find('|');
152 name = rest.substr(0, sep);
153 rest = rest.substr(sep+1);
154 addLoggingClass(name);
155 sep = rest.find('|');
157 addLoggingClass(rest);
158 SG_LOG(SG_GENERAL, SG_INFO, "Set logging classes to "
159 << getLoggingClasses());
164 * Get the logging priority.
167 getLoggingPriority ()
169 switch (logbuf::get_log_priority()) {
181 SG_LOG(SG_GENERAL, SG_WARN, "Internal: Unknown logging priority number: "
182 << logbuf::get_log_priority());
189 * Set the logging priority.
192 setLoggingPriority (string priority)
194 if (priority == "bulk") {
195 logbuf::set_log_priority(SG_BULK);
196 } else if (priority == "debug") {
197 logbuf::set_log_priority(SG_DEBUG);
198 } else if (priority == "" || priority == "info") { // default
199 logbuf::set_log_priority(SG_INFO);
200 } else if (priority == "warn") {
201 logbuf::set_log_priority(SG_WARN);
202 } else if (priority == "alert") {
203 logbuf::set_log_priority(SG_ALERT);
205 SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority " << priority);
207 SG_LOG(SG_GENERAL, SG_INFO, "Logging priority is " << getLoggingPriority());
213 * Get the pause state of the sim.
218 return globals->get_freeze();
223 * Set the pause state of the sim.
226 setFreeze (bool freeze)
228 globals->set_freeze(freeze);
231 current_atcdisplay->CancelRepeatingMessage();
232 current_atcdisplay->RegisterRepeatingMessage("**** SIM IS FROZEN **** SIM IS FROZEN ****");
235 current_atcdisplay->CancelRepeatingMessage();
241 * Return the current aircraft directory (UIUC) as a string.
251 * Set the current aircraft directory (UIUC).
254 setAircraftDir (string dir)
256 if (getAircraftDir() != dir) {
258 // needReinit(); FIXME!!
264 * Return the number of milliseconds elapsed since simulation started.
269 return globals->get_elapsed_time_ms();
274 * Return the current Zulu time.
281 struct tm * t = globals->get_time_params()->getGmt();
282 sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
283 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
284 t->tm_hour, t->tm_min, t->tm_sec);
291 * Set the current Zulu time.
294 setDateString (string date_string)
296 static const SGPropertyNode *cur_time_override
297 = fgGetNode("/sim/time/cur-time-override", true);
299 SGTime * st = globals->get_time_params();
300 struct tm * current_time = st->getGmt();
303 // Scan for basic ISO format
304 // YYYY-MM-DDTHH:MM:SS
305 int ret = sscanf(date_string.c_str(), "%d-%d-%dT%d:%d:%d",
306 &(new_time.tm_year), &(new_time.tm_mon),
307 &(new_time.tm_mday), &(new_time.tm_hour),
308 &(new_time.tm_min), &(new_time.tm_sec));
310 // Be pretty picky about this, so
311 // that strange things don't happen
312 // if the save file has been edited
315 SG_LOG(SG_INPUT, SG_ALERT, "Date/time string " << date_string
316 << " not in YYYY-MM-DDTHH:MM:SS format; skipped");
320 // OK, it looks like we got six
321 // values, one way or another.
322 new_time.tm_year -= 1900;
323 new_time.tm_mon -= 1;
325 // Now, tell flight gear to use
326 // the new time. This was far
327 // too difficult, by the way.
329 mktime(&new_time) - mktime(current_time) + globals->get_warp();
330 double lon = current_aircraft.fdm_state->get_Longitude();
331 double lat = current_aircraft.fdm_state->get_Latitude();
332 globals->set_warp(warp);
333 st->update(lon, lat, cur_time_override->getLongValue(), warp);
334 fgUpdateSkyAndLightingParams();
338 * Return the GMT as a string.
345 struct tm *t = globals->get_time_params()->getGmt();
346 sprintf(buf, " %.2d:%.2d:%.2d",
347 t->tm_hour, t->tm_min, t->tm_sec);
348 // cout << t << " " << buf << endl;
355 * Get the texture rendering state.
360 return (material_lib.get_step() == 0);
365 * Set the texture rendering state.
368 setTextures (bool textures)
371 material_lib.set_step(0);
373 material_lib.set_step(1);
378 * Return the magnetic variation
383 return globals->get_mag()->get_magvar() * SGD_RADIANS_TO_DEGREES;
388 * Return the magnetic dip
393 return globals->get_mag()->get_magdip() * SGD_RADIANS_TO_DEGREES;
398 * Return the current heading in degrees.
403 return current_aircraft.fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES - getMagVar();
407 #if !defined(FG_NEW_ENVIRONMENT)
410 * Get the current visibility (meters).
415 return WeatherDatabase->getWeatherVisibility();
420 * Set the current visibility (meters).
423 setVisibility (double visibility)
425 WeatherDatabase->setWeatherVisibility(visibility);
429 * Get the current wind north velocity (feet/second).
434 return current_aircraft.fdm_state->get_V_north_airmass();
439 * Set the current wind north velocity (feet/second).
442 setWindNorth (double speed)
444 current_aircraft.fdm_state
445 ->set_Velocities_Local_Airmass(speed, getWindEast(), getWindDown());
450 * Get the current wind east velocity (feet/second).
455 return current_aircraft.fdm_state->get_V_east_airmass();
460 * Set the current wind east velocity (feet/second).
463 setWindEast (double speed)
465 cout << "Set wind-east to " << speed << endl;
466 current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
473 * Get the current wind down velocity (feet/second).
478 return current_aircraft.fdm_state->get_V_down_airmass();
483 * Set the current wind down velocity (feet/second).
486 setWindDown (double speed)
488 current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
493 #endif // FG_NEW_ENVIRONMENT
498 return globals->get_warp();
504 globals->set_warp(warp);
510 return globals->get_warp_delta();
514 setWarpDelta (long delta)
516 globals->set_warp_delta(delta);
526 setWindingCCW (bool state)
530 glFrontFace ( GL_CCW );
532 glFrontFace ( GL_CW );
538 #if defined(FX) && !defined(WIN32)
539 return globals->get_fullscreen();
546 setFullScreen (bool state)
548 #if defined(FX) && !defined(WIN32)
549 globals->set_fullscreen(state);
550 # if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
551 XMesaSetFXmode( state ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
559 return fdm_data_logging;
563 setFDMDataLogging (bool state)
565 // kludge; no getter or setter available
566 if (state != fdm_data_logging) {
567 fgToggleFDMdataLogging();
568 fdm_data_logging = state;
573 ////////////////////////////////////////////////////////////////////////
574 // Tie the properties.
575 ////////////////////////////////////////////////////////////////////////
581 fgTie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
582 fgTie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
583 // fgTie("/sim/freeze", getFreeze, setFreeze);
584 fgTie("/sim/aircraft-dir", getAircraftDir, setAircraftDir);
586 fgTie("/sim/time/elapsed-ms", getElapsedTime_ms);
587 fgTie("/sim/time/gmt", getDateString, setDateString);
588 fgSetArchivable("/sim/time/gmt");
589 fgTie("/sim/time/gmt-string", getGMTString);
590 fgTie("/sim/rendering/textures", getTextures, setTextures);
593 fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
596 #if !defined(FG_NEW_ENVIRONMENT)
597 fgTie("/environment/visibility-m", getVisibility, setVisibility);
598 fgSetArchivable("/environment/visibility-m");
599 fgTie("/environment/wind-from-north-fps", getWindNorth, setWindNorth);
600 fgSetArchivable("/environment/wind-from-north-fps");
601 fgTie("/environment/wind-from-east-fps", getWindEast, setWindEast);
602 fgSetArchivable("/environment/wind-from-east-fps");
603 fgTie("/environment/wind-from-down-fps", getWindDown, setWindDown);
604 fgSetArchivable("/environment/wind-from-down-fps");
607 fgTie("/environment/magnetic-variation-deg", getMagVar);
608 fgTie("/environment/magnetic-dip-deg", getMagDip);
610 fgTie("/sim/time/warp", getWarp, setWarp, false);
611 fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
613 // Misc. Temporary junk.
614 fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW, false);
615 fgTie("/sim/temp/full-screen", getFullScreen, setFullScreen);
616 fgTie("/sim/temp/fdm-data-logging", getFDMDataLogging, setFDMDataLogging);
628 ////////////////////////////////////////////////////////////////////////
630 ////////////////////////////////////////////////////////////////////////
634 * Save the current state of the simulator to a stream.
637 fgSaveFlight (ostream &output, bool write_all)
640 fgSetBool("/sim/startup/onground", false);
641 fgSetArchivable("/sim/startup/onground");
642 fgSetBool("/sim/startup/trim", false);
643 fgSetArchivable("/sim/startup/trim");
644 fgSetString("/sim/startup/speed-set", "UVW");
645 fgSetArchivable("/sim/startup/speed-set");
648 writeProperties(output, globals->get_props(), write_all);
649 } catch (const sg_exception &e) {
650 guiErrorMessage("Error saving flight: ", e);
658 * Restore the current state of the simulator from a stream.
661 fgLoadFlight (istream &input)
663 SGPropertyNode props;
665 readProperties(input, &props);
666 } catch (const sg_exception &e) {
667 guiErrorMessage("Error reading saved flight: ", e);
671 fgSetBool("/sim/startup/onground", false);
672 fgSetBool("/sim/startup/trim", false);
673 fgSetString("/sim/startup/speed-set", "UVW");
675 copyProperties(&props, globals->get_props());
676 // When loading a flight, make it the
677 // new initial state.
678 globals->saveInitialState();
684 ////////////////////////////////////////////////////////////////////////
685 // Implementation of FGCondition.
686 ////////////////////////////////////////////////////////////////////////
688 FGCondition::FGCondition ()
692 FGCondition::~FGCondition ()
698 ////////////////////////////////////////////////////////////////////////
699 // Implementation of FGPropertyCondition.
700 ////////////////////////////////////////////////////////////////////////
702 FGPropertyCondition::FGPropertyCondition (const string &propname)
703 : _node(fgGetNode(propname, true))
707 FGPropertyCondition::~FGPropertyCondition ()
713 ////////////////////////////////////////////////////////////////////////
714 // Implementation of FGNotCondition.
715 ////////////////////////////////////////////////////////////////////////
717 FGNotCondition::FGNotCondition (FGCondition * condition)
718 : _condition(condition)
722 FGNotCondition::~FGNotCondition ()
728 FGNotCondition::test () const
730 return !(_condition->test());
735 ////////////////////////////////////////////////////////////////////////
736 // Implementation of FGAndCondition.
737 ////////////////////////////////////////////////////////////////////////
739 FGAndCondition::FGAndCondition ()
743 FGAndCondition::~FGAndCondition ()
745 for (unsigned int i = 0; i < _conditions.size(); i++)
746 delete _conditions[i];
750 FGAndCondition::test () const
752 int nConditions = _conditions.size();
753 for (int i = 0; i < nConditions; i++) {
754 if (!_conditions[i]->test())
761 FGAndCondition::addCondition (FGCondition * condition)
763 _conditions.push_back(condition);
768 ////////////////////////////////////////////////////////////////////////
769 // Implementation of FGOrCondition.
770 ////////////////////////////////////////////////////////////////////////
772 FGOrCondition::FGOrCondition ()
776 FGOrCondition::~FGOrCondition ()
778 for (unsigned int i = 0; i < _conditions.size(); i++)
779 delete _conditions[i];
783 FGOrCondition::test () const
785 int nConditions = _conditions.size();
786 for (int i = 0; i < nConditions; i++) {
787 if (_conditions[i]->test())
794 FGOrCondition::addCondition (FGCondition * condition)
796 _conditions.push_back(condition);
801 ////////////////////////////////////////////////////////////////////////
802 // Implementation of FGComparisonCondition.
803 ////////////////////////////////////////////////////////////////////////
806 doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
808 switch (left->getType()) {
809 case SGPropertyNode::BOOL: {
810 bool v1 = left->getBoolValue();
811 bool v2 = right->getBoolValue();
813 return FGComparisonCondition::LESS_THAN;
815 return FGComparisonCondition::GREATER_THAN;
817 return FGComparisonCondition::EQUALS;
820 case SGPropertyNode::INT: {
821 int v1 = left->getIntValue();
822 int v2 = right->getIntValue();
824 return FGComparisonCondition::LESS_THAN;
826 return FGComparisonCondition::GREATER_THAN;
828 return FGComparisonCondition::EQUALS;
831 case SGPropertyNode::LONG: {
832 long v1 = left->getLongValue();
833 long v2 = right->getLongValue();
835 return FGComparisonCondition::LESS_THAN;
837 return FGComparisonCondition::GREATER_THAN;
839 return FGComparisonCondition::EQUALS;
842 case SGPropertyNode::FLOAT: {
843 float v1 = left->getFloatValue();
844 float v2 = right->getFloatValue();
846 return FGComparisonCondition::LESS_THAN;
848 return FGComparisonCondition::GREATER_THAN;
850 return FGComparisonCondition::EQUALS;
853 case SGPropertyNode::DOUBLE: {
854 double v1 = left->getDoubleValue();
855 double v2 = right->getDoubleValue();
857 return FGComparisonCondition::LESS_THAN;
859 return FGComparisonCondition::GREATER_THAN;
861 return FGComparisonCondition::EQUALS;
864 case SGPropertyNode::STRING:
865 case SGPropertyNode::NONE:
866 case SGPropertyNode::UNSPECIFIED: {
867 string v1 = left->getStringValue();
868 string v2 = right->getStringValue();
870 return FGComparisonCondition::LESS_THAN;
872 return FGComparisonCondition::GREATER_THAN;
874 return FGComparisonCondition::EQUALS;
878 throw sg_exception("Unrecognized node type");
883 FGComparisonCondition::FGComparisonCondition (Type type, bool reverse)
892 FGComparisonCondition::~FGComparisonCondition ()
898 FGComparisonCondition::test () const
900 // Always fail if incompletely specified
901 if (_left_property == 0 ||
902 (_right_property == 0 && _right_value == 0))
905 // Get LESS_THAN, EQUALS, or GREATER_THAN
907 doComparison(_left_property,
908 (_right_property != 0 ? _right_property : _right_value));
910 return (cmp == _type);
912 return (cmp != _type);
916 FGComparisonCondition::setLeftProperty (const string &propname)
918 _left_property = fgGetNode(propname, true);
922 FGComparisonCondition::setRightProperty (const string &propname)
926 _right_property = fgGetNode(propname, true);
930 FGComparisonCondition::setRightValue (const SGPropertyNode *node)
934 _right_value = new SGPropertyNode(*node);
939 ////////////////////////////////////////////////////////////////////////
940 // Read a condition and use it if necessary.
941 ////////////////////////////////////////////////////////////////////////
943 // Forward declaration
944 static FGCondition * readCondition (const SGPropertyNode * node);
947 readPropertyCondition (const SGPropertyNode * node)
949 return new FGPropertyCondition(node->getStringValue());
953 readNotCondition (const SGPropertyNode * node)
955 int nChildren = node->nChildren();
956 for (int i = 0; i < nChildren; i++) {
957 const SGPropertyNode * child = node->getChild(i);
958 FGCondition * condition = readCondition(child);
960 return new FGNotCondition(condition);
962 SG_LOG(SG_COCKPIT, SG_ALERT, "Panel: empty 'not' condition");
967 readAndConditions (const SGPropertyNode * node)
969 FGAndCondition * andCondition = new FGAndCondition;
970 int nChildren = node->nChildren();
971 for (int i = 0; i < nChildren; i++) {
972 const SGPropertyNode * child = node->getChild(i);
973 FGCondition * condition = readCondition(child);
975 andCondition->addCondition(condition);
981 readOrConditions (const SGPropertyNode * node)
983 FGOrCondition * orCondition = new FGOrCondition;
984 int nChildren = node->nChildren();
985 for (int i = 0; i < nChildren; i++) {
986 const SGPropertyNode * child = node->getChild(i);
987 FGCondition * condition = readCondition(child);
989 orCondition->addCondition(condition);
995 readComparison (const SGPropertyNode * node,
996 FGComparisonCondition::Type type,
999 FGComparisonCondition * condition = new FGComparisonCondition(type, reverse);
1000 condition->setLeftProperty(node->getStringValue("property[0]"));
1001 if (node->hasValue("property[1]"))
1002 condition->setRightProperty(node->getStringValue("property[1]"));
1004 condition->setRightValue(node->getChild("value", 0));
1009 static FGCondition *
1010 readCondition (const SGPropertyNode * node)
1012 const string &name = node->getName();
1013 if (name == "property")
1014 return readPropertyCondition(node);
1015 else if (name == "not")
1016 return readNotCondition(node);
1017 else if (name == "and")
1018 return readAndConditions(node);
1019 else if (name == "or")
1020 return readOrConditions(node);
1021 else if (name == "less-than")
1022 return readComparison(node, FGComparisonCondition::LESS_THAN, false);
1023 else if (name == "less-than-equals")
1024 return readComparison(node, FGComparisonCondition::GREATER_THAN, true);
1025 else if (name == "greater-than")
1026 return readComparison(node, FGComparisonCondition::GREATER_THAN, false);
1027 else if (name == "greater-than-equals")
1028 return readComparison(node, FGComparisonCondition::LESS_THAN, true);
1029 else if (name == "equals")
1030 return readComparison(node, FGComparisonCondition::EQUALS, false);
1031 else if (name == "not-equals")
1032 return readComparison(node, FGComparisonCondition::EQUALS, true);
1039 ////////////////////////////////////////////////////////////////////////
1040 // Implementation of FGConditional.
1041 ////////////////////////////////////////////////////////////////////////
1043 FGConditional::FGConditional ()
1048 FGConditional::~FGConditional ()
1054 FGConditional::setCondition (FGCondition * condition)
1057 _condition = condition;
1061 FGConditional::test () const
1063 return ((_condition == 0) || _condition->test());
1068 // The top-level is always an implicit 'and' group
1070 fgReadCondition (const SGPropertyNode * node)
1072 return readAndConditions(node);
1076 // end of fg_props.cxx