JSBSim Flight Dynamics Model  1.0 (02 March 2017)
An Open Source Flight Dynamics and Control Software Library in C++
FGCondition.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Module: FGCondition.cpp
4  Author: Jon S. Berndt
5  Date started: 1/2/2003
6 
7  -------------- Copyright (C) 2003 Jon S. Berndt (jon@jsbsim.org) --------------
8 
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free Software
11  Foundation; either version 2 of the License, or (at your option) any later
12  version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17  details.
18 
19  You should have received a copy of the GNU Lesser General Public License along with
20  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21  Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23  Further information about the GNU Lesser General Public License can also be found on
24  the world wide web at http://www.gnu.org.
25 
26 HISTORY
27 --------------------------------------------------------------------------------
28 
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30 COMMENTS, REFERENCES, and NOTES
31 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
32 
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34 INCLUDES
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
36 
37 #include "FGCondition.h"
38 #include "FGPropertyValue.h"
39 #include "input_output/FGXMLElement.h"
40 #include "input_output/FGPropertyManager.h"
41 #include <iostream>
42 #include <cstdlib>
43 
44 using namespace std;
45 
46 namespace JSBSim {
47 
48 IDENT(IdSrc,"$Id: FGCondition.cpp,v 1.21 2015/02/27 20:36:47 bcoconni Exp $");
49 IDENT(IdHdr,ID_CONDITION);
50 
51 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52 CLASS IMPLEMENTATION
53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
54 
55 string FGCondition::indent = " ";
56 
57 // This constructor is called when tests are inside an element
58 FGCondition::FGCondition(Element* element, FGPropertyManager* PropertyManager) :
59  isGroup(true)
60 {
61  string property1, property2, logic;
62  Element* condition_element;
63 
64  InitializeConditionals();
65 
66  TestParam1 = TestParam2 = 0L;
67  TestValue = 0.0;
68  Comparison = ecUndef;
69  Logic = elUndef;
70  conditions.clear();
71 
72  logic = element->GetAttributeValue("logic");
73  if (!logic.empty()) {
74  if (logic == "OR") Logic = eOR;
75  else if (logic == "AND") Logic = eAND;
76  else { // error
77  cerr << "Unrecognized LOGIC token " << logic << endl;
78  }
79  } else {
80  Logic = eAND; // default
81  }
82 
83  condition_element = element->GetElement();
84  if (condition_element != 0) {
85  while (condition_element) {
86  conditions.push_back(new FGCondition(condition_element, PropertyManager));
87  condition_element = element->GetNextElement();
88  }
89  } else {
90  for (unsigned int i=0; i<element->GetNumDataLines(); i++) {
91  string data = element->GetDataLine(i);
92  conditions.push_back(new FGCondition(data, PropertyManager));
93  }
94  }
95 
96  Debug(0);
97 }
98 
99 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100 // This constructor is called when there are no nested test groups inside the
101 // condition
102 
103 FGCondition::FGCondition(const string& test, FGPropertyManager* PropertyManager) :
104  isGroup(false)
105 {
106  string property1, property2, compare_string;
107  vector <string> test_strings;
108 
109  InitializeConditionals();
110 
111  TestParam1 = TestParam2 = 0L;
112  TestValue = 0.0;
113  Comparison = ecUndef;
114  Logic = elUndef;
115  conditions.clear();
116 
117  test_strings = split(test, ' ');
118  if (test_strings.size() == 3) {
119  property1 = test_strings[0];
120  conditional = test_strings[1];
121  property2 = test_strings[2];
122  } else {
123  cerr << endl << " Conditional test is invalid: \"" << test
124  << "\" has " << test_strings.size() << " elements in the "
125  << "test condition." << endl;
126  exit(-1);
127  }
128 
129  FGPropertyNode *node = PropertyManager->GetNode(property1, false);
130  if (node) {
131  TestParam1 = new FGPropertyValue(node);
132  } else {
133  TestParam1 = new FGPropertyValue(property1, PropertyManager);
134  }
135  Comparison = mComparison[conditional];
136  if (Comparison == ecUndef) {
137  throw("Comparison operator: \""+conditional+"\" does not exist. Please check the conditional.");
138  }
139  if (is_number(property2)) {
140  TestValue = atof(property2.c_str());
141  } else {
142  node = PropertyManager->GetNode(property2, false);
143  if (node) {
144  TestParam2 = new FGPropertyValue(node);
145  } else {
146  TestParam2 = new FGPropertyValue(property2, PropertyManager);
147  }
148  }
149 }
150 
151 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152 
153 void FGCondition::InitializeConditionals(void)
154 {
155  mComparison["EQ"] = eEQ;
156  mComparison["NE"] = eNE;
157  mComparison["GT"] = eGT;
158  mComparison["GE"] = eGE;
159  mComparison["LT"] = eLT;
160  mComparison["LE"] = eLE;
161  mComparison["eq"] = eEQ;
162  mComparison["ne"] = eNE;
163  mComparison["gt"] = eGT;
164  mComparison["ge"] = eGE;
165  mComparison["lt"] = eLT;
166  mComparison["le"] = eLE;
167  mComparison["=="] = eEQ;
168  mComparison["!="] = eNE;
169  mComparison[">"] = eGT;
170  mComparison[">="] = eGE;
171  mComparison["<"] = eLT;
172  mComparison["<="] = eLE;
173 }
174 
175 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176 
177 FGCondition::~FGCondition(void)
178 {
179  delete TestParam1;
180  delete TestParam2;
181  for (unsigned int i=0; i<conditions.size(); i++) delete conditions[i];
182 
183  Debug(1);
184 }
185 
186 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187 
188 bool FGCondition::Evaluate(void )
189 {
190  bool pass = false;
191  double compareValue;
192 
193  if (TestParam1 == 0L) {
194 
195  if (Logic == eAND) {
196 
197  pass = true;
198  for (unsigned int i=0; i<conditions.size(); i++) {
199  if (!conditions[i]->Evaluate()) pass = false;
200  }
201 
202  } else { // Logic must be eOR
203 
204  pass = false;
205  for (unsigned int i=0; i<conditions.size(); i++) {
206  if (conditions[i]->Evaluate()) pass = true;
207  }
208 
209  }
210 
211  } else {
212 
213  if (TestParam2 != 0L) compareValue = TestParam2->getDoubleValue();
214  else compareValue = TestValue;
215 
216  switch (Comparison) {
217  case ecUndef:
218  cerr << "Undefined comparison operator." << endl;
219  break;
220  case eEQ:
221  pass = TestParam1->getDoubleValue() == compareValue;
222  break;
223  case eNE:
224  pass = TestParam1->getDoubleValue() != compareValue;
225  break;
226  case eGT:
227  pass = TestParam1->getDoubleValue() > compareValue;
228  break;
229  case eGE:
230  pass = TestParam1->getDoubleValue() >= compareValue;
231  break;
232  case eLT:
233  pass = TestParam1->getDoubleValue() < compareValue;
234  break;
235  case eLE:
236  pass = TestParam1->getDoubleValue() <= compareValue;
237  break;
238  default:
239  cerr << "Unknown comparison operator." << endl;
240  }
241  }
242 
243  return pass;
244 }
245 
246 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247 
248 void FGCondition::PrintCondition(string indent)
249 {
250  string scratch;
251 
252  if (isGroup) {
253 
254  switch(Logic) {
255  case (elUndef):
256  scratch = " UNSET";
257  cerr << "unset logic for test condition" << endl;
258  break;
259  case (eAND):
260  scratch = indent + "if all of the following are true: {";
261  break;
262  case (eOR):
263  scratch = indent + "if any of the following are true: {";
264  break;
265  default:
266  scratch = " UNKNOWN";
267  cerr << "Unknown logic for test condition" << endl;
268  }
269  cout << scratch << endl;
270 
271  for (unsigned int i=0; i<conditions.size(); i++) {
272  conditions[i]->PrintCondition(indent + " ");
273  cout << endl;
274  }
275 
276  cout << indent << "}";
277 
278  } else {
279  if (TestParam2 != 0L)
280  cout << indent << TestParam1->GetName() << " "
281  << conditional << " "
282  << TestParam2->GetName();
283  else
284  cout << indent << TestParam1->GetName() << " "
285  << conditional << " " << TestValue;
286  }
287 }
288 
289 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
290 // The bitmasked value choices are as follows:
291 // unset: In this case (the default) JSBSim would only print
292 // out the normally expected messages, essentially echoing
293 // the config files as they are read. If the environment
294 // variable is not set, debug_lvl is set to 1 internally
295 // 0: This requests JSBSim not to output any messages
296 // whatsoever.
297 // 1: This value explicity requests the normal JSBSim
298 // startup messages
299 // 2: This value asks for a message to be printed out when
300 // a class is instantiated
301 // 4: When this value is set, a message is displayed when a
302 // FGModel object executes its Run() method
303 // 8: When this value is set, various runtime state variables
304 // are printed out periodically
305 // 16: When set various parameters are sanity checked and
306 // a message is printed out when they go out of bounds
307 
308 void FGCondition::Debug(int from)
309 {
310  if (debug_lvl <= 0) return;
311 
312  if (debug_lvl & 1) { // Standard console startup message output
313  if (from == 0) { // Constructor
314 
315  }
316  }
317  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
318  if (from == 0) cout << "Instantiated: FGCondition" << endl;
319  if (from == 1) cout << "Destroyed: FGCondition" << endl;
320  }
321  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
322  }
323  if (debug_lvl & 8 ) { // Runtime state variables
324  }
325  if (debug_lvl & 16) { // Sanity checking
326  }
327  if (debug_lvl & 64) {
328  if (from == 0) { // Constructor
329  cout << IdSrc << endl;
330  cout << IdHdr << endl;
331  }
332  }
333 }
334 
335 } //namespace JSBSim
336 
STL namespace.