]> git.mxchange.org Git - simgear.git/commitdiff
Implement #327 Add condition checking the range of a value
authorTorsten Dreyer <Torsten@t3r.de>
Wed, 24 Aug 2011 19:26:02 +0000 (21:26 +0200)
committerTorsten Dreyer <Torsten@t3r.de>
Wed, 24 Aug 2011 19:26:02 +0000 (21:26 +0200)
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.

simgear/props/condition.cxx

index 85c539cfe7183e001cb164a32538fe5c8ce4d0e2..d60cb440ffeec4124bc850948505bfb1c080bf99 100644 (file)
@@ -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;
 }\f
 ////////////////////////////////////////////////////////////////////////
 // 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;