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