X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fprops%2Fcondition.cxx;h=1da575a4dbfe3c51623f59fc8633f5ed627ac373;hb=6672a1212cfccb2a08be21ff5271eae9b6f91b2a;hp=d50f461abc8ea59506772ca7d0f9b52139457820;hpb=525d2df3ccbf80152492a8632267f228a41ac393;p=simgear.git diff --git a/simgear/props/condition.cxx b/simgear/props/condition.cxx index d50f461a..1da575a4 100644 --- a/simgear/props/condition.cxx +++ b/simgear/props/condition.cxx @@ -1,4 +1,5 @@ -// condition.hxx - Declarations and inline methods for property conditions. +// condition.cxx - Declarations and inline methods for property conditions. +// // Written by David Megginson, started 2000. // CLO May 2003 - Split out condition specific code. // @@ -7,99 +8,224 @@ // $Id$ #ifdef HAVE_CONFIG_H -# include +# include #endif -// #include STL_IOSTREAM +// #include -#include +#include #include "props.hxx" - #include "condition.hxx" -SG_USING_STD(istream); -SG_USING_STD(ostream); - +#include + +using std::istream; +using std::ostream; +using std::string; + +/** + * Condition for a single property. + * + * This condition is true only if the property returns a boolean + * true value. + */ +class SGPropertyCondition : public SGCondition +{ +public: + SGPropertyCondition ( SGPropertyNode *prop_root, + const char * propname ); + virtual ~SGPropertyCondition (); + virtual bool test () const { return _node->getBoolValue(); } + virtual void collectDependentProperties(std::set& props) const + { props.insert(_node.get()); } +private: + SGConstPropertyNode_ptr _node; +}; + +/** + * Condition with constant value + * + */ +class SGConstantCondition : public SGCondition +{ +public: + SGConstantCondition (bool v) : _value(v) { ; } + virtual bool test () const { return _value; } +private: + bool _value; +}; + +/** + * Condition for a 'not' operator. + * + * This condition is true only if the child condition is false. + */ +class SGNotCondition : public SGCondition +{ +public: + SGNotCondition (SGCondition * condition); + virtual ~SGNotCondition (); + virtual bool test () const; + virtual void collectDependentProperties(std::set& props) const; +private: + SGConditionRef _condition; +}; + + +/** + * Condition for an 'and' group. + * + * This condition is true only if all of the conditions + * in the group are true. + */ +class SGAndCondition : public SGCondition +{ +public: + SGAndCondition (); + virtual ~SGAndCondition (); + virtual bool test () const; + // transfer pointer ownership + virtual void addCondition (SGCondition * condition); + virtual void collectDependentProperties(std::set& props) const; +private: + std::vector _conditions; +}; + + +/** + * Condition for an 'or' group. + * + * This condition is true if at least one of the conditions in the + * group is true. + */ +class SGOrCondition : public SGCondition +{ +public: + SGOrCondition (); + virtual ~SGOrCondition (); + virtual bool test () const; + // transfer pointer ownership + virtual void addCondition (SGCondition * condition); + virtual void collectDependentProperties(std::set& props) const; +private: + std::vector _conditions; +}; + + +/** + * Abstract base class for property comparison conditions. + */ +class SGComparisonCondition : public SGCondition +{ +public: + enum Type { + LESS_THAN, + GREATER_THAN, + EQUALS + }; + SGComparisonCondition (Type type, bool reverse = false); + virtual ~SGComparisonCondition (); + virtual bool test () const; + virtual void setLeftProperty( SGPropertyNode *prop_root, + 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); + + virtual void collectDependentProperties(std::set& props) const; +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; +}; - //////////////////////////////////////////////////////////////////////// -// Implementation of FGCondition. +// Implementation of SGCondition. //////////////////////////////////////////////////////////////////////// -FGCondition::FGCondition () +SGCondition::SGCondition () { } -FGCondition::~FGCondition () +SGCondition::~SGCondition () { } - //////////////////////////////////////////////////////////////////////// -// Implementation of FGPropertyCondition. +// Implementation of SGPropertyCondition. //////////////////////////////////////////////////////////////////////// -FGPropertyCondition::FGPropertyCondition ( SGPropertyNode *prop_root, +SGPropertyCondition::SGPropertyCondition ( SGPropertyNode *prop_root, const char *propname ) : _node( prop_root->getNode(propname, true) ) { - cout << "FGPropertyCondition::FGPropertyCondition()" << endl; - cout << " prop_root = " << prop_root << endl; - cout << " propname = " << propname << endl; - _node = prop_root->getNode(propname, true); - cout << " _node = " << _node << endl; } -FGPropertyCondition::~FGPropertyCondition () +SGPropertyCondition::~SGPropertyCondition () { } - //////////////////////////////////////////////////////////////////////// -// Implementation of FGNotCondition. +// Implementation of SGNotCondition. //////////////////////////////////////////////////////////////////////// -FGNotCondition::FGNotCondition (FGCondition * condition) +SGNotCondition::SGNotCondition (SGCondition * condition) : _condition(condition) { } -FGNotCondition::~FGNotCondition () +SGNotCondition::~SGNotCondition () { - delete _condition; } bool -FGNotCondition::test () const +SGNotCondition::test () const { return !(_condition->test()); } +void +SGNotCondition::collectDependentProperties(std::set& props) const +{ + _condition->collectDependentProperties(props); +} - //////////////////////////////////////////////////////////////////////// -// Implementation of FGAndCondition. +// Implementation of SGAndCondition. //////////////////////////////////////////////////////////////////////// -FGAndCondition::FGAndCondition () +SGAndCondition::SGAndCondition () { } -FGAndCondition::~FGAndCondition () +SGAndCondition::~SGAndCondition () { - for (unsigned int i = 0; i < _conditions.size(); i++) - delete _conditions[i]; } bool -FGAndCondition::test () const +SGAndCondition::test () const { - int nConditions = _conditions.size(); - for (int i = 0; i < nConditions; i++) { + for( size_t i = 0; i < _conditions.size(); i++ ) + { if (!_conditions[i]->test()) return false; } @@ -107,32 +233,36 @@ FGAndCondition::test () const } void -FGAndCondition::addCondition (FGCondition * condition) +SGAndCondition::addCondition (SGCondition * condition) { _conditions.push_back(condition); } +void +SGAndCondition::collectDependentProperties(std::set& props) const +{ + for( size_t i = 0; i < _conditions.size(); i++ ) + _conditions[i]->collectDependentProperties(props); +} + - //////////////////////////////////////////////////////////////////////// -// Implementation of FGOrCondition. +// Implementation of SGOrCondition. //////////////////////////////////////////////////////////////////////// -FGOrCondition::FGOrCondition () +SGOrCondition::SGOrCondition () { } -FGOrCondition::~FGOrCondition () +SGOrCondition::~SGOrCondition () { - for (unsigned int i = 0; i < _conditions.size(); i++) - delete _conditions[i]; } bool -FGOrCondition::test () const +SGOrCondition::test () const { - int nConditions = _conditions.size(); - for (int i = 0; i < nConditions; i++) { + for( size_t i = 0; i < _conditions.size(); i++ ) + { if (_conditions[i]->test()) return true; } @@ -140,121 +270,120 @@ FGOrCondition::test () const } void -FGOrCondition::addCondition (FGCondition * condition) +SGOrCondition::addCondition (SGCondition * condition) { _conditions.push_back(condition); } +void +SGOrCondition::collectDependentProperties(std::set& props) const +{ + for( size_t i = 0; i < _conditions.size(); i++ ) + _conditions[i]->collectDependentProperties(props); +} + - //////////////////////////////////////////////////////////////////////// -// Implementation of FGComparisonCondition. +// 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()) { - case SGPropertyNode::BOOL: { + case props::BOOL: { bool v1 = left->getBoolValue(); bool v2 = right->getBoolValue(); if (v1 < v2) - return FGComparisonCondition::LESS_THAN; + return SGComparisonCondition::LESS_THAN; else if (v1 > v2) - return FGComparisonCondition::GREATER_THAN; + return SGComparisonCondition::GREATER_THAN; else - return FGComparisonCondition::EQUALS; + return SGComparisonCondition::EQUALS; break; } - case SGPropertyNode::INT: { - int v1 = left->getIntValue(); - int v2 = right->getIntValue(); + case props::INT: + return doComp(left->getIntValue(), right->getIntValue(), + precision ? std::abs(precision->getIntValue()/2) : 0 ); + + case props::LONG: + return doComp(left->getLongValue(), right->getLongValue(), + precision ? std::abs(precision->getLongValue()/2L) : 0L ); + + case props::FLOAT: + return doComp(left->getFloatValue(), right->getFloatValue(), + precision ? std::fabs(precision->getFloatValue()/2.0f) : 0.0f ); + + case props::DOUBLE: + return doComp(left->getDoubleValue(), right->getDoubleValue(), + precision ? std::fabs(precision->getDoubleValue()/2.0) : 0.0 ); + + case props::STRING: + case props::NONE: + case props::UNSPECIFIED: { + 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 FGComparisonCondition::LESS_THAN; + return SGComparisonCondition::LESS_THAN; else if (v1 > v2) - return FGComparisonCondition::GREATER_THAN; + return SGComparisonCondition::GREATER_THAN; else - return FGComparisonCondition::EQUALS; + return SGComparisonCondition::EQUALS; break; } - case SGPropertyNode::LONG: { - long v1 = left->getLongValue(); - long v2 = right->getLongValue(); - if (v1 < v2) - return FGComparisonCondition::LESS_THAN; - else if (v1 > v2) - return FGComparisonCondition::GREATER_THAN; - else - return FGComparisonCondition::EQUALS; - break; - } - case SGPropertyNode::FLOAT: { - float v1 = left->getFloatValue(); - float v2 = right->getFloatValue(); - if (v1 < v2) - return FGComparisonCondition::LESS_THAN; - else if (v1 > v2) - return FGComparisonCondition::GREATER_THAN; - else - return FGComparisonCondition::EQUALS; - break; + default: + throw sg_exception("condition: unrecognized node type in comparison"); } - case SGPropertyNode::DOUBLE: { - double v1 = left->getDoubleValue(); - double v2 = right->getDoubleValue(); - if (v1 < v2) - return FGComparisonCondition::LESS_THAN; - else if (v1 > v2) - return FGComparisonCondition::GREATER_THAN; - else - return FGComparisonCondition::EQUALS; - break; - } - case SGPropertyNode::STRING: - case SGPropertyNode::NONE: - case SGPropertyNode::UNSPECIFIED: { - string v1 = left->getStringValue(); - string v2 = right->getStringValue(); - if (v1 < v2) - return FGComparisonCondition::LESS_THAN; - else if (v1 > v2) - return FGComparisonCondition::GREATER_THAN; - else - return FGComparisonCondition::EQUALS; - break; - } - } - throw sg_exception("Unrecognized node type"); + return 0; } -FGComparisonCondition::FGComparisonCondition (Type type, bool reverse) +SGComparisonCondition::SGComparisonCondition (Type type, bool reverse) : _type(type), - _reverse(reverse), - _left_property(0), - _right_property(0), - _right_value(0) + _reverse(reverse) { } -FGComparisonCondition::~FGComparisonCondition () +SGComparisonCondition::~SGComparisonCondition () { - delete _right_value; } bool -FGComparisonCondition::test () const +SGComparisonCondition::test () const { // Always fail if incompletely specified - if (_left_property == 0 || - (_right_property == 0 && _right_value == 0)) + if (!_left_property || !_right_property) return false; - // Get LESS_THAN, EQUALS, or GREATER_THAN - int cmp = - doComparison(_left_property, - (_right_property != 0 ? _right_property : _right_value)); + // Get LESS_THAN, EQUALS, or GREATER_THAN + if (_left_dexp) { + _left_property->setDoubleValue(_left_dexp->getValue(NULL)); + } + + 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, _precision_property ); if (!_reverse) return (cmp == _type); else @@ -262,105 +391,203 @@ FGComparisonCondition::test () const } void -FGComparisonCondition::setLeftProperty( SGPropertyNode *prop_root, +SGComparisonCondition::setLeftProperty( SGPropertyNode *prop_root, const char * propname ) { _left_property = prop_root->getNode(propname, true); } void -FGComparisonCondition::setRightProperty( SGPropertyNode *prop_root, +SGComparisonCondition::setRightProperty( SGPropertyNode *prop_root, const char * propname ) { - delete _right_value; - _right_value = 0; _right_property = prop_root->getNode(propname, true); } void -FGComparisonCondition::setRightValue (const SGPropertyNode *node) +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) { - _right_property = 0; - delete _right_value; - _right_value = new SGPropertyNode(*node); + _right_property = new SGPropertyNode(*node); } +void +SGComparisonCondition::setLeftDExpression(SGExpressiond* dexp) +{ + _left_property = new SGPropertyNode(); + _left_dexp = dexp; +} + +void +SGComparisonCondition::setRightDExpression(SGExpressiond* dexp) +{ + _right_property = new SGPropertyNode(); + _right_dexp = dexp; +} + +void +SGComparisonCondition::setPrecisionDExpression(SGExpressiond* dexp) +{ + _precision_property = new SGPropertyNode(); + _precision_dexp = dexp; +} + +void +SGComparisonCondition::collectDependentProperties(std::set& props) const +{ + if (_left_dexp) + _left_dexp->collectDependentProperties(props); + else + props.insert(_left_property); + + if (_right_dexp) + _right_dexp->collectDependentProperties(props); + else + props.insert(_right_property); + + if (_precision_dexp) + _precision_dexp->collectDependentProperties(props); + else if (_precision_property) + props.insert(_precision_property); + +} - //////////////////////////////////////////////////////////////////////// // Read a condition and use it if necessary. //////////////////////////////////////////////////////////////////////// // Forward declaration -static FGCondition * readCondition( SGPropertyNode *prop_root, +static SGCondition * readCondition( SGPropertyNode *prop_root, const SGPropertyNode *node ); -static FGCondition * +static SGCondition * readPropertyCondition( SGPropertyNode *prop_root, const SGPropertyNode *node ) { - return new FGPropertyCondition( prop_root, node->getStringValue() ); + return new SGPropertyCondition( prop_root, node->getStringValue() ); } -static FGCondition * +static SGCondition * readNotCondition( SGPropertyNode *prop_root, const SGPropertyNode *node ) { int nChildren = node->nChildren(); for (int i = 0; i < nChildren; i++) { const SGPropertyNode * child = node->getChild(i); - FGCondition * condition = readCondition(prop_root, child); + SGCondition * condition = readCondition(prop_root, child); if (condition != 0) - return new FGNotCondition(condition); + return new SGNotCondition(condition); } - SG_LOG(SG_COCKPIT, SG_ALERT, "Panel: empty 'not' condition"); + SG_LOG(SG_COCKPIT, SG_ALERT, "empty 'not' condition"); return 0; } -static FGCondition * +static SGCondition * readAndConditions( SGPropertyNode *prop_root, const SGPropertyNode *node ) { - FGAndCondition * andCondition = new FGAndCondition; + SGAndCondition * andCondition = new SGAndCondition; int nChildren = node->nChildren(); for (int i = 0; i < nChildren; i++) { const SGPropertyNode * child = node->getChild(i); - FGCondition * condition = readCondition(prop_root, child); + SGCondition * condition = readCondition(prop_root, child); if (condition != 0) andCondition->addCondition(condition); } return andCondition; } -static FGCondition * +static SGCondition * readOrConditions( SGPropertyNode *prop_root, const SGPropertyNode *node ) { - FGOrCondition * orCondition = new FGOrCondition; + SGOrCondition * orCondition = new SGOrCondition; int nChildren = node->nChildren(); for (int i = 0; i < nChildren; i++) { const SGPropertyNode * child = node->getChild(i); - FGCondition * condition = readCondition(prop_root, child); + SGCondition * condition = readCondition(prop_root, child); if (condition != 0) orCondition->addCondition(condition); } return orCondition; } -static FGCondition * +static SGCondition * readComparison( SGPropertyNode *prop_root, const SGPropertyNode *node, - FGComparisonCondition::Type type, + SGComparisonCondition::Type type, bool reverse) { - FGComparisonCondition * condition = new FGComparisonCondition(type, reverse); - condition->setLeftProperty(prop_root, node->getStringValue("property[0]")); - if (node->hasValue("property[1]")) - condition->setRightProperty(prop_root, node->getStringValue("property[1]")); - else - condition->setRightValue(node->getChild("value", 0)); - + SGComparisonCondition * condition = new SGComparisonCondition(type, reverse); + 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 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; } -static FGCondition * +static SGCondition * readCondition( SGPropertyNode *prop_root, const SGPropertyNode *node ) { const string &name = node->getName(); @@ -373,63 +600,63 @@ readCondition( SGPropertyNode *prop_root, const SGPropertyNode *node ) else if (name == "or") return readOrConditions(prop_root, node); else if (name == "less-than") - return readComparison(prop_root, node, FGComparisonCondition::LESS_THAN, + return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN, false); else if (name == "less-than-equals") - return readComparison(prop_root, node, FGComparisonCondition::GREATER_THAN, + return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN, true); else if (name == "greater-than") - return readComparison(prop_root, node, FGComparisonCondition::GREATER_THAN, + return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN, false); else if (name == "greater-than-equals") - return readComparison(prop_root, node, FGComparisonCondition::LESS_THAN, + return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN, true); else if (name == "equals") - return readComparison(prop_root, node, FGComparisonCondition::EQUALS, + return readComparison(prop_root, node, SGComparisonCondition::EQUALS, false); else if (name == "not-equals") - return readComparison(prop_root, node, FGComparisonCondition::EQUALS, true); + return readComparison(prop_root, node, SGComparisonCondition::EQUALS, true); + else if (name == "false") + return new SGConstantCondition(false); + else if (name == "true") + return new SGConstantCondition(true); else return 0; } - //////////////////////////////////////////////////////////////////////// -// Implementation of FGConditional. +// Implementation of SGConditional. //////////////////////////////////////////////////////////////////////// -FGConditional::FGConditional () +SGConditional::SGConditional () : _condition (0) { } -FGConditional::~FGConditional () +SGConditional::~SGConditional () { - delete _condition; } void -FGConditional::setCondition (FGCondition * condition) +SGConditional::setCondition (SGCondition * condition) { - delete _condition; _condition = condition; } bool -FGConditional::test () const +SGConditional::test () const { return ((_condition == 0) || _condition->test()); } - // The top-level is always an implicit 'and' group -FGCondition * -fgReadCondition( SGPropertyNode *prop_root, const SGPropertyNode *node ) +SGCondition * +sgReadCondition( SGPropertyNode *prop_root, const SGPropertyNode *node ) { return readAndConditions(prop_root, node); } -// end of fg_props.cxx +// end of condition.cxx