]> git.mxchange.org Git - simgear.git/blob - simgear/props/condition.cxx
Merge branch 'topics/condexp' into next
[simgear.git] / simgear / props / condition.cxx
1 // condition.cxx - Declarations and inline methods for property conditions.
2 //
3 // Written by David Megginson, started 2000.
4 // CLO May 2003 - Split out condition specific code.
5 //
6 // This file is in the Public Domain, and comes with no warranty.
7 //
8 // $Id$
9
10 #ifdef HAVE_CONFIG_H
11 #  include <simgear_config.h>
12 #endif
13
14 // #include <iostream>
15
16 #include <simgear/structure/exception.hxx>
17
18 #include "props.hxx"
19 #include "condition.hxx"
20
21 #include <simgear/math/SGMath.hxx>
22 #include <simgear/structure/SGExpression.hxx>
23
24 using std::istream;
25 using std::ostream;
26 \f
27 /**
28  * Condition for a single property.
29  *
30  * This condition is true only if the property returns a boolean
31  * true value.
32  */
33 class SGPropertyCondition : public SGCondition
34 {
35 public:
36   SGPropertyCondition ( SGPropertyNode *prop_root,
37                         const char * propname  );
38   virtual ~SGPropertyCondition ();
39   virtual bool test () const { return _node->getBoolValue(); }
40 private:
41   SGConstPropertyNode_ptr _node;
42 };
43
44
45 /**
46  * Condition for a 'not' operator.
47  *
48  * This condition is true only if the child condition is false.
49  */
50 class SGNotCondition : public SGCondition
51 {
52 public:
53   SGNotCondition (SGCondition * condition);
54   virtual ~SGNotCondition ();
55   virtual bool test () const;
56 private:
57   SGSharedPtr<SGCondition> _condition;
58 };
59
60
61 /**
62  * Condition for an 'and' group.
63  *
64  * This condition is true only if all of the conditions
65  * in the group are true.
66  */
67 class SGAndCondition : public SGCondition
68 {
69 public:
70   SGAndCondition ();
71   virtual ~SGAndCondition ();
72   virtual bool test () const;
73                                 // transfer pointer ownership
74   virtual void addCondition (SGCondition * condition);
75 private:
76   std::vector<SGSharedPtr<SGCondition> > _conditions;
77 };
78
79
80 /**
81  * Condition for an 'or' group.
82  *
83  * This condition is true if at least one of the conditions in the
84  * group is true.
85  */
86 class SGOrCondition : public SGCondition
87 {
88 public:
89   SGOrCondition ();
90   virtual ~SGOrCondition ();
91   virtual bool test () const;
92                                 // transfer pointer ownership
93   virtual void addCondition (SGCondition * condition);
94 private:
95   std::vector<SGSharedPtr<SGCondition> > _conditions;
96 };
97
98
99 /**
100  * Abstract base class for property comparison conditions.
101  */
102 class SGComparisonCondition : public SGCondition
103 {
104 public:
105   enum Type {
106     LESS_THAN,
107     GREATER_THAN,
108     EQUALS
109   };
110   SGComparisonCondition (Type type, bool reverse = false);
111   virtual ~SGComparisonCondition ();
112   virtual bool test () const;
113   virtual void setLeftProperty( SGPropertyNode *prop_root,
114                                 const char * propname );
115   virtual void setRightProperty( SGPropertyNode *prop_root,
116                                  const char * propname );
117   // will make a local copy
118   virtual void setLeftValue (const SGPropertyNode * value);
119   virtual void setRightValue (const SGPropertyNode * value);
120   
121   void setLeftDExpression(SGExpressiond* dexp);
122   void setRightDExpression(SGExpressiond* dexp);
123   
124 private:
125   Type _type;
126   bool _reverse;
127   SGPropertyNode_ptr _left_property;
128   SGPropertyNode_ptr _right_property;
129   
130   SGSharedPtr<SGExpressiond> _left_dexp;
131   SGSharedPtr<SGExpressiond> _right_dexp;
132 };
133
134
135 ////////////////////////////////////////////////////////////////////////
136 // Implementation of SGCondition.
137 ////////////////////////////////////////////////////////////////////////
138
139 SGCondition::SGCondition ()
140 {
141 }
142
143 SGCondition::~SGCondition ()
144 {
145 }
146
147
148 \f
149 ////////////////////////////////////////////////////////////////////////
150 // Implementation of SGPropertyCondition.
151 ////////////////////////////////////////////////////////////////////////
152
153 SGPropertyCondition::SGPropertyCondition ( SGPropertyNode *prop_root,
154                                            const char *propname )
155     : _node( prop_root->getNode(propname, true) )
156 {
157 }
158
159 SGPropertyCondition::~SGPropertyCondition ()
160 {
161 }
162
163
164 \f
165 ////////////////////////////////////////////////////////////////////////
166 // Implementation of SGNotCondition.
167 ////////////////////////////////////////////////////////////////////////
168
169 SGNotCondition::SGNotCondition (SGCondition * condition)
170   : _condition(condition)
171 {
172 }
173
174 SGNotCondition::~SGNotCondition ()
175 {
176 }
177
178 bool
179 SGNotCondition::test () const
180 {
181   return !(_condition->test());
182 }
183
184
185 \f
186 ////////////////////////////////////////////////////////////////////////
187 // Implementation of SGAndCondition.
188 ////////////////////////////////////////////////////////////////////////
189
190 SGAndCondition::SGAndCondition ()
191 {
192 }
193
194 SGAndCondition::~SGAndCondition ()
195 {
196 }
197
198 bool
199 SGAndCondition::test () const
200 {
201   int nConditions = _conditions.size();
202   for (int i = 0; i < nConditions; i++) {
203     if (!_conditions[i]->test())
204       return false;
205   }
206   return true;
207 }
208
209 void
210 SGAndCondition::addCondition (SGCondition * condition)
211 {
212   _conditions.push_back(condition);
213 }
214
215
216 \f
217 ////////////////////////////////////////////////////////////////////////
218 // Implementation of SGOrCondition.
219 ////////////////////////////////////////////////////////////////////////
220
221 SGOrCondition::SGOrCondition ()
222 {
223 }
224
225 SGOrCondition::~SGOrCondition ()
226 {
227 }
228
229 bool
230 SGOrCondition::test () const
231 {
232   int nConditions = _conditions.size();
233   for (int i = 0; i < nConditions; i++) {
234     if (_conditions[i]->test())
235       return true;
236   }
237   return false;
238 }
239
240 void
241 SGOrCondition::addCondition (SGCondition * condition)
242 {
243   _conditions.push_back(condition);
244 }
245
246
247 \f
248 ////////////////////////////////////////////////////////////////////////
249 // Implementation of SGComparisonCondition.
250 ////////////////////////////////////////////////////////////////////////
251
252 static int
253 doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
254 {
255   using namespace simgear;
256   switch (left->getType()) {
257   case props::BOOL: {
258     bool v1 = left->getBoolValue();
259     bool v2 = right->getBoolValue();
260     if (v1 < v2)
261       return SGComparisonCondition::LESS_THAN;
262     else if (v1 > v2)
263       return SGComparisonCondition::GREATER_THAN;
264     else
265       return SGComparisonCondition::EQUALS;
266     break;
267   }
268   case props::INT: {
269     int v1 = left->getIntValue();
270     int v2 = right->getIntValue();
271     if (v1 < v2)
272       return SGComparisonCondition::LESS_THAN;
273     else if (v1 > v2)
274       return SGComparisonCondition::GREATER_THAN;
275     else
276       return SGComparisonCondition::EQUALS;
277     break;
278   }
279   case props::LONG: {
280     long v1 = left->getLongValue();
281     long v2 = right->getLongValue();
282     if (v1 < v2)
283       return SGComparisonCondition::LESS_THAN;
284     else if (v1 > v2)
285       return SGComparisonCondition::GREATER_THAN;
286     else
287       return SGComparisonCondition::EQUALS;
288     break;
289   }
290   case props::FLOAT: {
291     float v1 = left->getFloatValue();
292     float v2 = right->getFloatValue();
293     if (v1 < v2)
294       return SGComparisonCondition::LESS_THAN;
295     else if (v1 > v2)
296       return SGComparisonCondition::GREATER_THAN;
297     else
298       return SGComparisonCondition::EQUALS;
299     break;
300   }
301   case props::DOUBLE: {
302     double v1 = left->getDoubleValue();
303     double v2 = right->getDoubleValue();
304     if (v1 < v2)
305       return SGComparisonCondition::LESS_THAN;
306     else if (v1 > v2)
307       return SGComparisonCondition::GREATER_THAN;
308     else
309       return SGComparisonCondition::EQUALS;
310     break;
311   }
312   case props::STRING:
313   case props::NONE:
314   case props::UNSPECIFIED: {
315     string v1 = left->getStringValue();
316     string v2 = right->getStringValue();
317     if (v1 < v2)
318       return SGComparisonCondition::LESS_THAN;
319     else if (v1 > v2)
320       return SGComparisonCondition::GREATER_THAN;
321     else
322       return SGComparisonCondition::EQUALS;
323     break;
324   }
325   default:
326     throw sg_exception("condition: unrecognized node type in comparison");
327   }
328   
329   return 0;
330 }
331
332
333 SGComparisonCondition::SGComparisonCondition (Type type, bool reverse)
334   : _type(type),
335     _reverse(reverse)
336 {
337 }
338
339 SGComparisonCondition::~SGComparisonCondition ()
340 {
341 }
342
343 bool
344 SGComparisonCondition::test () const
345 {
346                                 // Always fail if incompletely specified
347   if (!_left_property || !_right_property)
348     return false;
349
350   // Get LESS_THAN, EQUALS, or GREATER_THAN
351   if (_left_dexp) {
352     _left_property->setDoubleValue(_left_dexp->getValue(NULL));
353   }
354   
355   if (_right_dexp) {
356     _right_property->setDoubleValue(_right_dexp->getValue(NULL));
357   }
358         
359   int cmp = doComparison(_left_property, _right_property);
360   if (!_reverse)
361     return (cmp == _type);
362   else
363     return (cmp != _type);
364 }
365
366 void
367 SGComparisonCondition::setLeftProperty( SGPropertyNode *prop_root,
368                                         const char * propname )
369 {
370   _left_property = prop_root->getNode(propname, true);
371 }
372
373 void
374 SGComparisonCondition::setRightProperty( SGPropertyNode *prop_root,
375                                          const char * propname )
376 {
377   _right_property = prop_root->getNode(propname, true);
378 }
379
380 void
381 SGComparisonCondition::setLeftValue (const SGPropertyNode *node)
382 {
383   _left_property = new SGPropertyNode(*node);
384 }
385
386
387 void
388 SGComparisonCondition::setRightValue (const SGPropertyNode *node)
389 {
390   _right_property = new SGPropertyNode(*node);
391 }
392
393 void
394 SGComparisonCondition::setLeftDExpression(SGExpressiond* dexp)
395 {
396   _left_property = new SGPropertyNode();
397   _left_dexp = dexp;
398 }
399
400 void
401 SGComparisonCondition::setRightDExpression(SGExpressiond* dexp)
402 {
403   _right_property = new SGPropertyNode();
404   _right_dexp = dexp;
405 }\f
406 ////////////////////////////////////////////////////////////////////////
407 // Read a condition and use it if necessary.
408 ////////////////////////////////////////////////////////////////////////
409
410                                 // Forward declaration
411 static SGCondition * readCondition( SGPropertyNode *prop_root,
412                                     const SGPropertyNode *node );
413
414 static SGCondition *
415 readPropertyCondition( SGPropertyNode *prop_root,
416                        const SGPropertyNode *node )
417 {
418   return new SGPropertyCondition( prop_root, node->getStringValue() );
419 }
420
421 static SGCondition *
422 readNotCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
423 {
424   int nChildren = node->nChildren();
425   for (int i = 0; i < nChildren; i++) {
426     const SGPropertyNode * child = node->getChild(i);
427     SGCondition * condition = readCondition(prop_root, child);
428     if (condition != 0)
429       return new SGNotCondition(condition);
430   }
431   SG_LOG(SG_COCKPIT, SG_ALERT, "empty 'not' condition");
432   return 0;
433 }
434
435 static SGCondition *
436 readAndConditions( SGPropertyNode *prop_root, const SGPropertyNode *node )
437 {
438   SGAndCondition * andCondition = new SGAndCondition;
439   int nChildren = node->nChildren();
440   for (int i = 0; i < nChildren; i++) {
441     const SGPropertyNode * child = node->getChild(i);
442     SGCondition * condition = readCondition(prop_root, child);
443     if (condition != 0)
444       andCondition->addCondition(condition);
445   }
446   return andCondition;
447 }
448
449 static SGCondition *
450 readOrConditions( SGPropertyNode *prop_root, const SGPropertyNode *node )
451 {
452   SGOrCondition * orCondition = new SGOrCondition;
453   int nChildren = node->nChildren();
454   for (int i = 0; i < nChildren; i++) {
455     const SGPropertyNode * child = node->getChild(i);
456     SGCondition * condition = readCondition(prop_root, child);
457     if (condition != 0)
458       orCondition->addCondition(condition);
459   }
460   return orCondition;
461 }
462
463 static SGCondition *
464 readComparison( SGPropertyNode *prop_root,
465                 const SGPropertyNode *node,
466                 SGComparisonCondition::Type type,
467                 bool reverse)
468 {
469   SGComparisonCondition * condition = new SGComparisonCondition(type, reverse);
470   if (node->nChildren() != 2) {
471     throw sg_exception("condition: comparison without two children");
472   }
473   
474   const SGPropertyNode* left = node->getChild(0), 
475     *right = node->getChild(1);
476   string leftName(left->getName());
477   if (leftName == "property") {
478     condition->setLeftProperty(prop_root, left->getStringValue());
479   } else if (leftName == "value") {
480     condition->setLeftValue(left);
481   } else if (leftName == "expression") {
482     SGExpressiond* exp = SGReadDoubleExpression(prop_root, left->getChild(0));
483     condition->setLeftDExpression(exp);
484   } else {
485     throw sg_exception("Unknown condition comparison left child:" + leftName);
486   }
487     
488   string rightName(right->getName());
489   if (rightName == "property") {
490     condition->setRightProperty(prop_root, right->getStringValue());
491   } else if (rightName == "value") {
492     condition->setRightValue(right);
493   } else if (rightName == "expression") {
494     SGExpressiond* exp = SGReadDoubleExpression(prop_root, right->getChild(0));
495     condition->setRightDExpression(exp);
496   } else {
497     throw sg_exception("Unknown condition comparison right child:" + rightName);
498   }
499   
500   return condition;
501 }
502
503 static SGCondition *
504 readCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
505 {
506   const string &name = node->getName();
507   if (name == "property")
508     return readPropertyCondition(prop_root, node);
509   else if (name == "not")
510     return readNotCondition(prop_root, node);
511   else if (name == "and")
512     return readAndConditions(prop_root, node);
513   else if (name == "or")
514     return readOrConditions(prop_root, node);
515   else if (name == "less-than")
516     return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN,
517                           false);
518   else if (name == "less-than-equals")
519     return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN,
520                           true);
521   else if (name == "greater-than")
522     return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN,
523                           false);
524   else if (name == "greater-than-equals")
525     return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN,
526                           true);
527   else if (name == "equals")
528     return readComparison(prop_root, node, SGComparisonCondition::EQUALS,
529                           false);
530   else if (name == "not-equals")
531     return readComparison(prop_root, node, SGComparisonCondition::EQUALS, true);
532   else
533     return 0;
534 }
535
536
537 \f
538 ////////////////////////////////////////////////////////////////////////
539 // Implementation of SGConditional.
540 ////////////////////////////////////////////////////////////////////////
541
542 SGConditional::SGConditional ()
543   : _condition (0)
544 {
545 }
546
547 SGConditional::~SGConditional ()
548 {
549 }
550
551 void
552 SGConditional::setCondition (SGCondition * condition)
553 {
554   _condition = condition;
555 }
556
557 bool
558 SGConditional::test () const
559 {
560   return ((_condition == 0) || _condition->test());
561 }
562
563
564 \f
565 // The top-level is always an implicit 'and' group
566 SGCondition *
567 sgReadCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
568 {
569   return readAndConditions(prop_root, node);
570 }
571
572
573 // end of condition.cxx