// $Id$
#ifdef HAVE_CONFIG_H
-# include <simgear/compiler.h>
+# include <simgear_config.h>
#endif
-// #include STL_IOSTREAM
+// #include <iostream>
-#include <simgear/misc/exception.hxx>
+#include <simgear/structure/exception.hxx>
#include "props.hxx"
-
#include "condition.hxx"
-SG_USING_STD(istream);
-SG_USING_STD(ostream);
+#include <simgear/structure/SGExpression.hxx>
+using std::istream;
+using std::ostream;
+\f
+/**
+ * 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(); }
+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;
+private:
+ SGSharedPtr<SGCondition> _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);
+private:
+ std::vector<SGSharedPtr<SGCondition> > _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);
+private:
+ std::vector<SGSharedPtr<SGCondition> > _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);
+
+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;
+};
-\f
////////////////////////////////////////////////////////////////////////
// Implementation of SGCondition.
////////////////////////////////////////////////////////////////////////
SGNotCondition::~SGNotCondition ()
{
- delete _condition;
}
bool
SGAndCondition::~SGAndCondition ()
{
- for (unsigned int i = 0; i < _conditions.size(); i++)
- delete _conditions[i];
}
bool
SGOrCondition::~SGOrCondition ()
{
- for (unsigned int i = 0; i < _conditions.size(); i++)
- delete _conditions[i];
}
bool
// 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()) {
- case SGPropertyNode::BOOL: {
+ case props::BOOL: {
bool v1 = left->getBoolValue();
bool v2 = right->getBoolValue();
if (v1 < v2)
return SGComparisonCondition::EQUALS;
break;
}
- case SGPropertyNode::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 SGPropertyNode::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 SGPropertyNode::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 SGPropertyNode::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 SGPropertyNode::STRING:
- case SGPropertyNode::NONE:
- case SGPropertyNode::UNSPECIFIED: {
- string v1 = left->getStringValue();
- string v2 = right->getStringValue();
+ case props::INT:
+ return doComp<int>(left->getIntValue(), right->getIntValue(),
+ precision ? std::abs(precision->getIntValue()/2) : 0 );
+
+ case props::LONG:
+ return doComp<long>(left->getLongValue(), right->getLongValue(),
+ precision ? std::abs(precision->getLongValue()/2L) : 0L );
+
+ case props::FLOAT:
+ return doComp<float>(left->getFloatValue(), right->getFloatValue(),
+ precision ? std::fabs(precision->getFloatValue()/2.0f) : 0.0f );
+
+ case props::DOUBLE:
+ return doComp<double>(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 SGComparisonCondition::LESS_THAN;
else if (v1 > v2)
return SGComparisonCondition::EQUALS;
break;
}
+ default:
+ throw sg_exception("condition: unrecognized node type in comparison");
}
- throw sg_exception("Unrecognized node type");
+
return 0;
}
SGComparisonCondition::SGComparisonCondition (Type type, bool reverse)
: _type(type),
- _reverse(reverse),
- _left_property(0),
- _right_property(0),
- _right_value(0)
+ _reverse(reverse)
{
}
SGComparisonCondition::~SGComparisonCondition ()
{
- delete _right_value;
}
bool
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
SGComparisonCondition::setRightProperty( SGPropertyNode *prop_root,
const char * propname )
{
- delete _right_value;
- _right_value = 0;
_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)
{
- _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;
+}
-\f
+void
+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.
////////////////////////////////////////////////////////////////////////
if (condition != 0)
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;
}
bool reverse)
{
SGComparisonCondition * condition = new SGComparisonCondition(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));
-
+ 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;
}
false);
else if (name == "not-equals")
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;
}
SGConditional::~SGConditional ()
{
- delete _condition;
}
void
SGConditional::setCondition (SGCondition * condition)
{
- delete _condition;
_condition = condition;
}