From: Torsten Dreyer <Torsten@t3r.de>
Date: Wed, 24 Aug 2011 19:26:02 +0000 (+0200)
Subject: Implement #327 	Add condition checking the range of a value
X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=09e610b900e6751da635619513a53972f9e67861;p=simgear.git

Implement #327 	Add condition checking the range of a value

New feature for <condition> elements:
An (optional) element <precision> allows for fuzzy equals checks
example:
<condition>
  <equals>
    <property>/foo</property>
    <value type="double">0.0</value>
    <precision>0.1</precision>
  </equals>
</condition>

This condition evaluates as true if /foo is within [-0.05..0.05]
(both inclusive)
The precision tag works for int, long, float and double propeties.
It has no meaning for bool properties. For string properties,
precision sets the length of the strings to compare.
---

diff --git a/simgear/props/condition.cxx b/simgear/props/condition.cxx
index 85c539cf..d60cb440 100644
--- a/simgear/props/condition.cxx
+++ b/simgear/props/condition.cxx
@@ -126,21 +126,27 @@ public:
                                 const char * propname );
   virtual void setRightProperty( SGPropertyNode *prop_root,
                                  const char * propname );
+  virtual void setPrecisionProperty( SGPropertyNode *prop_root,
+                                 const char * propname );
   // will make a local copy
   virtual void setLeftValue (const SGPropertyNode * value);
   virtual void setRightValue (const SGPropertyNode * value);
+  virtual void setPrecisionValue (const SGPropertyNode * value);
   
   void setLeftDExpression(SGExpressiond* dexp);
   void setRightDExpression(SGExpressiond* dexp);
+  void setPrecisionDExpression(SGExpressiond* dexp);
   
 private:
   Type _type;
   bool _reverse;
   SGPropertyNode_ptr _left_property;
   SGPropertyNode_ptr _right_property;
+  SGPropertyNode_ptr _precision_property;
   
   SGSharedPtr<SGExpressiond> _left_dexp;
   SGSharedPtr<SGExpressiond> _right_dexp;
+  SGSharedPtr<SGExpressiond> _precision_dexp;
 };
 
 
@@ -261,8 +267,20 @@ SGOrCondition::addCondition (SGCondition * condition)
 // Implementation of SGComparisonCondition.
 ////////////////////////////////////////////////////////////////////////
 
+template<typename T> 
+static int doComp( T v1, T v2, T e )
+{
+  T d = v1 - v2;
+  if( d < -e )
+    return SGComparisonCondition::LESS_THAN;
+  else if( d > e )
+    return SGComparisonCondition::GREATER_THAN;
+  else
+    return SGComparisonCondition::EQUALS;
+}
+
 static int
-doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
+doComparison (const SGPropertyNode * left, const SGPropertyNode * right, const SGPropertyNode * precision )
 {
   using namespace simgear;
   switch (left->getType()) {
@@ -277,55 +295,28 @@ doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
       return SGComparisonCondition::EQUALS;
     break;
   }
-  case props::INT: {
-    int v1 = left->getIntValue();
-    int v2 = right->getIntValue();
-    if (v1 < v2)
-      return SGComparisonCondition::LESS_THAN;
-    else if (v1 > v2)
-      return SGComparisonCondition::GREATER_THAN;
-    else
-      return SGComparisonCondition::EQUALS;
-    break;
-  }
-  case props::LONG: {
-    long v1 = left->getLongValue();
-    long v2 = right->getLongValue();
-    if (v1 < v2)
-      return SGComparisonCondition::LESS_THAN;
-    else if (v1 > v2)
-      return SGComparisonCondition::GREATER_THAN;
-    else
-      return SGComparisonCondition::EQUALS;
-    break;
-  }
-  case props::FLOAT: {
-    float v1 = left->getFloatValue();
-    float v2 = right->getFloatValue();
-    if (v1 < v2)
-      return SGComparisonCondition::LESS_THAN;
-    else if (v1 > v2)
-      return SGComparisonCondition::GREATER_THAN;
-    else
-      return SGComparisonCondition::EQUALS;
-    break;
-  }
-  case props::DOUBLE: {
-    double v1 = left->getDoubleValue();
-    double v2 = right->getDoubleValue();
-    if (v1 < v2)
-      return SGComparisonCondition::LESS_THAN;
-    else if (v1 > v2)
-      return SGComparisonCondition::GREATER_THAN;
-    else
-      return SGComparisonCondition::EQUALS;
-    break;
-  }
+  case props::INT:
+    return doComp<int>(left->getIntValue(), right->getIntValue(), 
+           precision ? abs(precision->getIntValue()/2) : 0 );
+
+  case props::LONG:
+    return doComp<long>(left->getLongValue(), right->getLongValue(), 
+           precision ? abs(precision->getLongValue()/2L) : 0L );
+
+  case props::FLOAT:
+    return doComp<float>(left->getFloatValue(), right->getFloatValue(), 
+           precision ? fabs(precision->getFloatValue()/2.0f) : 0.0f );
+
+  case props::DOUBLE:
+    return doComp<double>(left->getDoubleValue(), right->getDoubleValue(), 
+           precision ? fabs(precision->getDoubleValue()/2.0) : 0.0 );
+
   case props::STRING:
   case props::NONE:
   case props::UNSPECIFIED: {
-    string v1 = left->getStringValue();
-    string v2 = right->getStringValue();
+    size_t l = precision ? precision->getLongValue() : string::npos;
+    string v1 = string(left->getStringValue()).substr(0,l);
+    string v2 = string(right->getStringValue()).substr(0,l);
     if (v1 < v2)
       return SGComparisonCondition::LESS_THAN;
     else if (v1 > v2)
@@ -367,8 +358,12 @@ SGComparisonCondition::test () const
   if (_right_dexp) {
     _right_property->setDoubleValue(_right_dexp->getValue(NULL));
   }
+
+  if (_precision_dexp) {
+    _precision_property->setDoubleValue(_precision_dexp->getValue(NULL));
+  }
         
-  int cmp = doComparison(_left_property, _right_property);
+  int cmp = doComparison(_left_property, _right_property, _precision_property );
   if (!_reverse)
     return (cmp == _type);
   else
@@ -389,12 +384,24 @@ SGComparisonCondition::setRightProperty( SGPropertyNode *prop_root,
   _right_property = prop_root->getNode(propname, true);
 }
 
+void
+SGComparisonCondition::setPrecisionProperty( SGPropertyNode *prop_root,
+                                         const char * propname )
+{
+  _precision_property = prop_root->getNode(propname, true);
+}
+
 void
 SGComparisonCondition::setLeftValue (const SGPropertyNode *node)
 {
   _left_property = new SGPropertyNode(*node);
 }
 
+void
+SGComparisonCondition::setPrecisionValue (const SGPropertyNode *node)
+{
+  _precision_property = new SGPropertyNode(*node);
+}
 
 void
 SGComparisonCondition::setRightValue (const SGPropertyNode *node)
@@ -414,6 +421,13 @@ SGComparisonCondition::setRightDExpression(SGExpressiond* dexp)
 {
   _right_property = new SGPropertyNode();
   _right_dexp = dexp;
+}
+
+void
+SGComparisonCondition::setPrecisionDExpression(SGExpressiond* dexp)
+{
+  _precision_property = new SGPropertyNode();
+  _precision_dexp = dexp;
 }
 ////////////////////////////////////////////////////////////////////////
 // Read a condition and use it if necessary.
@@ -479,34 +493,54 @@ readComparison( SGPropertyNode *prop_root,
 		bool reverse)
 {
   SGComparisonCondition * condition = new SGComparisonCondition(type, reverse);
-  if (node->nChildren() != 2) {
-    throw sg_exception("condition: comparison without two children");
+  if (node->nChildren() < 2 || node->nChildren() > 3 ) {
+    throw sg_exception("condition: comparison without two or three children");
   }
   
   const SGPropertyNode* left = node->getChild(0), 
     *right = node->getChild(1);
-  string leftName(left->getName());
-  if (leftName == "property") {
-    condition->setLeftProperty(prop_root, left->getStringValue());
-  } else if (leftName == "value") {
-    condition->setLeftValue(left);
-  } else if (leftName == "expression") {
-    SGExpressiond* exp = SGReadDoubleExpression(prop_root, left->getChild(0));
-    condition->setLeftDExpression(exp);
-  } else {
-    throw sg_exception("Unknown condition comparison left child:" + leftName);
+
+  {
+    string leftName(left->getName());
+    if (leftName == "property") {
+      condition->setLeftProperty(prop_root, left->getStringValue());
+    } else if (leftName == "value") {
+      condition->setLeftValue(left);
+    } else if (leftName == "expression") {
+      SGExpressiond* exp = SGReadDoubleExpression(prop_root, left->getChild(0));
+      condition->setLeftDExpression(exp);
+    } else {
+      throw sg_exception("Unknown condition comparison left child:" + leftName);
+    }
   }
     
-  string rightName(right->getName());
-  if (rightName == "property") {
-    condition->setRightProperty(prop_root, right->getStringValue());
-  } else if (rightName == "value") {
-    condition->setRightValue(right);
-  } else if (rightName == "expression") {
-    SGExpressiond* exp = SGReadDoubleExpression(prop_root, right->getChild(0));
-    condition->setRightDExpression(exp);
-  } else {
-    throw sg_exception("Unknown condition comparison right child:" + rightName);
+  {
+    string rightName(right->getName());
+    if (rightName == "property") {
+      condition->setRightProperty(prop_root, right->getStringValue());
+    } else if (rightName == "value") {
+      condition->setRightValue(right);
+    } else if (rightName == "expression") {
+      SGExpressiond* exp = SGReadDoubleExpression(prop_root, right->getChild(0));
+      condition->setRightDExpression(exp);
+    } else {
+      throw sg_exception("Unknown condition comparison right child:" + rightName);
+    }
+  }
+  
+  if( node->nChildren() == 3 ) {
+    const SGPropertyNode *n = node->getChild(2);
+    string name(n->getName());
+    if (name == "precision-property") {
+      condition->setPrecisionProperty(prop_root, n->getStringValue());
+    } else if (name == "precision-value") {
+      condition->setPrecisionValue(n);
+    } else if (name == "precision-expression") {
+      SGExpressiond* exp = SGReadDoubleExpression(prop_root, n->getChild(0));
+      condition->setPrecisionDExpression(exp);
+    } else {
+      throw sg_exception("Unknown condition comparison precision child:" + name );
+    }
   }
   
   return condition;