From 09e610b900e6751da635619513a53972f9e67861 Mon Sep 17 00:00:00 2001 From: Torsten Dreyer Date: Wed, 24 Aug 2011 21:26:02 +0200 Subject: [PATCH] Implement #327 Add condition checking the range of a value New feature for elements: An (optional) element allows for fuzzy equals checks example: /foo 0.0 0.1 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 | 174 +++++++++++++++++++++--------------- 1 file changed, 104 insertions(+), 70 deletions(-) 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 _left_dexp; SGSharedPtr _right_dexp; + SGSharedPtr _precision_dexp; }; @@ -261,8 +267,20 @@ SGOrCondition::addCondition (SGCondition * condition) // Implementation of SGComparisonCondition. //////////////////////////////////////////////////////////////////////// +template +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(left->getIntValue(), right->getIntValue(), + precision ? abs(precision->getIntValue()/2) : 0 ); + + case props::LONG: + return doComp(left->getLongValue(), right->getLongValue(), + precision ? abs(precision->getLongValue()/2L) : 0L ); + + case props::FLOAT: + return doComp(left->getFloatValue(), right->getFloatValue(), + precision ? fabs(precision->getFloatValue()/2.0f) : 0.0f ); + + case props::DOUBLE: + return doComp(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; -- 2.39.5