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