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 writeProperties(output, globals->get_props(), write_all);
641 } catch (const sg_exception &e) {
642 guiErrorMessage("Error saving flight: ", e);
650 * Restore the current state of the simulator from a stream.
653 fgLoadFlight (istream &input)
655 SGPropertyNode props;
657 readProperties(input, &props);
658 } catch (const sg_exception &e) {
659 guiErrorMessage("Error reading saved flight: ", e);
662 copyProperties(&props, globals->get_props());
663 // When loading a flight, make it the
664 // new initial state.
665 globals->saveInitialState();
671 ////////////////////////////////////////////////////////////////////////
672 // Implementation of FGCondition.
673 ////////////////////////////////////////////////////////////////////////
675 FGCondition::FGCondition ()
679 FGCondition::~FGCondition ()
685 ////////////////////////////////////////////////////////////////////////
686 // Implementation of FGPropertyCondition.
687 ////////////////////////////////////////////////////////////////////////
689 FGPropertyCondition::FGPropertyCondition (const string &propname)
690 : _node(fgGetNode(propname, true))
694 FGPropertyCondition::~FGPropertyCondition ()
700 ////////////////////////////////////////////////////////////////////////
701 // Implementation of FGNotCondition.
702 ////////////////////////////////////////////////////////////////////////
704 FGNotCondition::FGNotCondition (FGCondition * condition)
705 : _condition(condition)
709 FGNotCondition::~FGNotCondition ()
715 FGNotCondition::test () const
717 return !(_condition->test());
722 ////////////////////////////////////////////////////////////////////////
723 // Implementation of FGAndCondition.
724 ////////////////////////////////////////////////////////////////////////
726 FGAndCondition::FGAndCondition ()
730 FGAndCondition::~FGAndCondition ()
732 for (unsigned int i = 0; i < _conditions.size(); i++)
733 delete _conditions[i];
737 FGAndCondition::test () const
739 int nConditions = _conditions.size();
740 for (int i = 0; i < nConditions; i++) {
741 if (!_conditions[i]->test())
748 FGAndCondition::addCondition (FGCondition * condition)
750 _conditions.push_back(condition);
755 ////////////////////////////////////////////////////////////////////////
756 // Implementation of FGOrCondition.
757 ////////////////////////////////////////////////////////////////////////
759 FGOrCondition::FGOrCondition ()
763 FGOrCondition::~FGOrCondition ()
765 for (unsigned int i = 0; i < _conditions.size(); i++)
766 delete _conditions[i];
770 FGOrCondition::test () const
772 int nConditions = _conditions.size();
773 for (int i = 0; i < nConditions; i++) {
774 if (_conditions[i]->test())
781 FGOrCondition::addCondition (FGCondition * condition)
783 _conditions.push_back(condition);
788 ////////////////////////////////////////////////////////////////////////
789 // Implementation of FGComparisonCondition.
790 ////////////////////////////////////////////////////////////////////////
793 doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
795 switch (left->getType()) {
796 case SGPropertyNode::BOOL: {
797 bool v1 = left->getBoolValue();
798 bool v2 = right->getBoolValue();
800 return FGComparisonCondition::LESS_THAN;
802 return FGComparisonCondition::GREATER_THAN;
804 return FGComparisonCondition::EQUALS;
807 case SGPropertyNode::INT: {
808 int v1 = left->getIntValue();
809 int v2 = right->getIntValue();
811 return FGComparisonCondition::LESS_THAN;
813 return FGComparisonCondition::GREATER_THAN;
815 return FGComparisonCondition::EQUALS;
818 case SGPropertyNode::LONG: {
819 long v1 = left->getLongValue();
820 long v2 = right->getLongValue();
822 return FGComparisonCondition::LESS_THAN;
824 return FGComparisonCondition::GREATER_THAN;
826 return FGComparisonCondition::EQUALS;
829 case SGPropertyNode::FLOAT: {
830 float v1 = left->getFloatValue();
831 float v2 = right->getFloatValue();
833 return FGComparisonCondition::LESS_THAN;
835 return FGComparisonCondition::GREATER_THAN;
837 return FGComparisonCondition::EQUALS;
840 case SGPropertyNode::DOUBLE: {
841 double v1 = left->getDoubleValue();
842 double v2 = right->getDoubleValue();
844 return FGComparisonCondition::LESS_THAN;
846 return FGComparisonCondition::GREATER_THAN;
848 return FGComparisonCondition::EQUALS;
851 case SGPropertyNode::STRING:
852 case SGPropertyNode::NONE:
853 case SGPropertyNode::UNSPECIFIED: {
854 string v1 = left->getStringValue();
855 string v2 = right->getStringValue();
857 return FGComparisonCondition::LESS_THAN;
859 return FGComparisonCondition::GREATER_THAN;
861 return FGComparisonCondition::EQUALS;
865 throw sg_exception("Unrecognized node type");
870 FGComparisonCondition::FGComparisonCondition (Type type, bool reverse)
879 FGComparisonCondition::~FGComparisonCondition ()
885 FGComparisonCondition::test () const
887 // Always fail if incompletely specified
888 if (_left_property == 0 ||
889 (_right_property == 0 && _right_value == 0))
892 // Get LESS_THAN, EQUALS, or GREATER_THAN
894 doComparison(_left_property,
895 (_right_property != 0 ? _right_property : _right_value));
897 return (cmp == _type);
899 return (cmp != _type);
903 FGComparisonCondition::setLeftProperty (const string &propname)
905 _left_property = fgGetNode(propname, true);
909 FGComparisonCondition::setRightProperty (const string &propname)
913 _right_property = fgGetNode(propname, true);
917 FGComparisonCondition::setRightValue (const SGPropertyNode *node)
921 _right_value = new SGPropertyNode(*node);
926 ////////////////////////////////////////////////////////////////////////
927 // Read a condition and use it if necessary.
928 ////////////////////////////////////////////////////////////////////////
930 // Forward declaration
931 static FGCondition * readCondition (const SGPropertyNode * node);
934 readPropertyCondition (const SGPropertyNode * node)
936 return new FGPropertyCondition(node->getStringValue());
940 readNotCondition (const SGPropertyNode * node)
942 int nChildren = node->nChildren();
943 for (int i = 0; i < nChildren; i++) {
944 const SGPropertyNode * child = node->getChild(i);
945 FGCondition * condition = readCondition(child);
947 return new FGNotCondition(condition);
949 SG_LOG(SG_COCKPIT, SG_ALERT, "Panel: empty 'not' condition");
954 readAndConditions (const SGPropertyNode * node)
956 FGAndCondition * andCondition = new FGAndCondition;
957 int nChildren = node->nChildren();
958 for (int i = 0; i < nChildren; i++) {
959 const SGPropertyNode * child = node->getChild(i);
960 FGCondition * condition = readCondition(child);
962 andCondition->addCondition(condition);
968 readOrConditions (const SGPropertyNode * node)
970 FGOrCondition * orCondition = new FGOrCondition;
971 int nChildren = node->nChildren();
972 for (int i = 0; i < nChildren; i++) {
973 const SGPropertyNode * child = node->getChild(i);
974 FGCondition * condition = readCondition(child);
976 orCondition->addCondition(condition);
982 readComparison (const SGPropertyNode * node,
983 FGComparisonCondition::Type type,
986 FGComparisonCondition * condition = new FGComparisonCondition(type, reverse);
987 condition->setLeftProperty(node->getStringValue("property[0]"));
988 if (node->hasValue("property[1]"))
989 condition->setRightProperty(node->getStringValue("property[1]"));
991 condition->setRightValue(node->getChild("value", 0));
997 readCondition (const SGPropertyNode * node)
999 const string &name = node->getName();
1000 if (name == "property")
1001 return readPropertyCondition(node);
1002 else if (name == "not")
1003 return readNotCondition(node);
1004 else if (name == "and")
1005 return readAndConditions(node);
1006 else if (name == "or")
1007 return readOrConditions(node);
1008 else if (name == "less-than")
1009 return readComparison(node, FGComparisonCondition::LESS_THAN, false);
1010 else if (name == "less-than-equals")
1011 return readComparison(node, FGComparisonCondition::GREATER_THAN, true);
1012 else if (name == "greater-than")
1013 return readComparison(node, FGComparisonCondition::GREATER_THAN, false);
1014 else if (name == "greater-than-equals")
1015 return readComparison(node, FGComparisonCondition::LESS_THAN, true);
1016 else if (name == "equals")
1017 return readComparison(node, FGComparisonCondition::EQUALS, false);
1018 else if (name == "not-equals")
1019 return readComparison(node, FGComparisonCondition::EQUALS, true);
1026 ////////////////////////////////////////////////////////////////////////
1027 // Implementation of FGConditional.
1028 ////////////////////////////////////////////////////////////////////////
1030 FGConditional::FGConditional ()
1035 FGConditional::~FGConditional ()
1041 FGConditional::setCondition (FGCondition * condition)
1044 _condition = condition;
1048 FGConditional::test () const
1050 return ((_condition == 0) || _condition->test());
1055 // The top-level is always an implicit 'and' group
1057 fgReadCondition (const SGPropertyNode * node)
1059 return readAndConditions(node);
1063 // end of fg_props.cxx