From: frohlich Date: Wed, 26 Dec 2007 19:10:40 +0000 (+0000) Subject: Modified Files: X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=0b1f074bcff315546304a5c7d9886f37a1b71a18;p=simgear.git Modified Files: Makefile.am Added Files: SGExpression.cxx SGExpression.hxx: Add not yet complete but already usable expression tree. Will be used with the panel code. --- diff --git a/simgear/structure/Makefile.am b/simgear/structure/Makefile.am index 15a31033..e538cfda 100644 --- a/simgear/structure/Makefile.am +++ b/simgear/structure/Makefile.am @@ -10,6 +10,7 @@ include_HEADERS = \ subsystem_mgr.hxx \ SGAtomic.hxx \ SGBinding.hxx \ + SGExpression.hxx \ SGReferenced.hxx \ SGSharedPtr.hxx \ SGSmplhist.hxx \ @@ -22,6 +23,7 @@ libsgstructure_a_SOURCES = \ subsystem_mgr.cxx \ SGAtomic.cxx \ SGBinding.cxx \ + SGExpression.cxx \ SGSmplhist.cxx \ SGSmplstat.cxx diff --git a/simgear/structure/SGExpression.cxx b/simgear/structure/SGExpression.cxx new file mode 100644 index 00000000..b042cb90 --- /dev/null +++ b/simgear/structure/SGExpression.cxx @@ -0,0 +1,638 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "SGExpression.hxx" + +#include +#include +#include + +template +static bool +SGReadValueFromString(const char* str, T& value) +{ + if (!str) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read string content."); + return false; + } + std::stringstream s; + s.str(std::string(str)); + s >> value; + if (s.fail()) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read string content."); + return false; + } + return true; +} + +template<> +static bool +SGReadValueFromString(const char* str, bool& value) +{ + if (!str) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read string content."); + return false; + } + std::stringstream s; + s.str(std::string(str)); + s >> value; + if (!s.fail()) + return true; + + std::string stdstr; + if (!SGReadValueFromString(str, stdstr)) + return false; + + if (stdstr == "true" || stdstr == "True" || stdstr == "TRUE") { + value = true; + return true; + } + if (stdstr == "false" || stdstr == "False" || stdstr == "FALSE") { + value = true; + return true; + } + return false; +} + +template +static bool +SGReadValueFromContent(const SGPropertyNode *node, T& value) +{ + if (!node) + return false; + return SGReadValueFromString(node->getStringValue(), value); +} + +template +static SGExpression* +SGReadIExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression); + +template +static bool +SGReadNaryOperands(SGNaryExpression* nary, + SGPropertyNode *inputRoot, const SGPropertyNode *expression) +{ + for (unsigned i = 0; i < expression->nChildren(); ++i) { + SGExpression* inputExpression; + inputExpression = SGReadIExpression(inputRoot, expression->getChild(i)); + if (!inputExpression) + return false; + nary->addOperand(inputExpression); + } +} + +// template +// static SGExpression* +// SGReadBExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression) +// { +// if (!expression) +// return 0; + +// std::string name = expression->getName(); +// if (name == "value") { +// T value; +// if (!SGReadValueFromContent(expression, value)) { +// SG_LOG(SG_IO, SG_ALERT, "Cannot read \"value\" expression."); +// return 0; +// } +// return new SGConstExpression(value); +// } + +// return 0; +// } + +template +static SGExpression* +SGReadIExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression) +{ + if (!expression) + return 0; + + std::string name = expression->getName(); + if (name == "value") { + T value; + if (!SGReadValueFromContent(expression, value)) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"value\" expression."); + return 0; + } + return new SGConstExpression(value); + } + + if (name == "property") { + if (!inputRoot) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression.\n" + "No inputRoot argument given!"); + return 0; + } + if (!expression->getStringValue()) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGPropertyNode* inputNode; + inputNode = inputRoot->getNode(expression->getStringValue(), true); + return new SGPropertyExpression(inputNode); + } + + if (name == "abs" || name == "fabs") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadIExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGAbsExpression(inputExpression); + } + + if (name == "sqr") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadIExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGSqrExpression(inputExpression); + } + + if (name == "clip") { + if (expression->nChildren() != 3) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + const SGPropertyNode* minProperty = expression->getChild("clipMin"); + T clipMin; + if (!SGReadValueFromContent(minProperty, clipMin)) + clipMin = SGMisc::min(SGLimits::min(), -SGLimits::max()); + + const SGPropertyNode* maxProperty = expression->getChild("clipMax"); + T clipMax; + if (!SGReadValueFromContent(maxProperty, clipMax)) + clipMin = SGLimits::max(); + + SGSharedPtr > inputExpression; + for (unsigned i = 0; !inputExpression && i < expression->nChildren(); ++i) + inputExpression = SGReadIExpression(inputRoot, expression->getChild(i)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGClipExpression(inputExpression, clipMin, clipMax); + } + + if (name == "div") { + if (expression->nChildren() != 2) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpressions[2] = { + SGReadIExpression(inputRoot, expression->getChild(0)), + SGReadIExpression(inputRoot, expression->getChild(1)) + }; + if (!inputExpressions[0] || !inputExpressions[1]) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGDivExpression(inputExpressions[0], inputExpressions[1]); + } + if (name == "mod") { + if (expression->nChildren() != 2) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpressions[2] = { + SGReadIExpression(inputRoot, expression->getChild(0)), + SGReadIExpression(inputRoot, expression->getChild(1)) + }; + if (!inputExpressions[0] || !inputExpressions[1]) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGModExpression(inputExpressions[0], inputExpressions[1]); + } + + if (name == "sum") { + if (expression->nChildren() < 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSumExpression* output = new SGSumExpression; + if (!SGReadNaryOperands(output, inputRoot, expression)) { + delete output; + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return output; + } + if (name == "prod" || name == "product") { + if (expression->nChildren() < 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGProductExpression* output = new SGProductExpression; + if (!SGReadNaryOperands(output, inputRoot, expression)) { + delete output; + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return output; + } + if (name == "min") { + if (expression->nChildren() < 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGMinExpression* output = new SGMinExpression; + if (!SGReadNaryOperands(output, inputRoot, expression)) { + delete output; + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return output; + } + if (name == "max") { + if (expression->nChildren() < 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGMaxExpression* output = new SGMaxExpression; + if (!SGReadNaryOperands(output, inputRoot, expression)) { + delete output; + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return output; + } + + return 0; +} + + +template +static SGExpression* +SGReadFExpression(SGPropertyNode *inputRoot, const SGPropertyNode *expression) +{ + SGExpression* r = SGReadIExpression(inputRoot, expression); + if (r) + return r; + + if (!expression) + return 0; + + std::string name = expression->getName(); + if (name == "acos") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGACosExpression(inputExpression); + } + + if (name == "asin") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGASinExpression(inputExpression); + } + + if (name == "atan") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGATanExpression(inputExpression); + } + + if (name == "ceil") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGCeilExpression(inputExpression); + } + + if (name == "cos") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGCosExpression(inputExpression); + } + + if (name == "cosh") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGCoshExpression(inputExpression); + } + + if (name == "deg2rad") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGScaleExpression(inputExpression, SGMisc::pi()/180); + } + + if (name == "exp") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGExpExpression(inputExpression); + } + + if (name == "floor") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGFloorExpression(inputExpression); + } + + if (name == "log") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGLogExpression(inputExpression); + } + + if (name == "log10") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGLog10Expression(inputExpression); + } + + if (name == "rad2deg") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGScaleExpression(inputExpression, 180/SGMisc::pi()); + } + + if (name == "sin") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGSinExpression(inputExpression); + } + + if (name == "sinh") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGSinhExpression(inputExpression); + } + + if (name == "sqrt") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGSqrtExpression(inputExpression); + } + + if (name == "tan") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGTanExpression(inputExpression); + } + + if (name == "tanh") { + if (expression->nChildren() != 1) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpression; + inputExpression = SGReadFExpression(inputRoot, expression->getChild(0)); + if (!inputExpression) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGTanhExpression(inputExpression); + } + +// if (name == "table") { +// } +// if (name == "step") { +// } +// if (name == "condition") { +// } + + if (name == "atan2") { + if (expression->nChildren() != 2) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpressions[2] = { + SGReadFExpression(inputRoot, expression->getChild(0)), + SGReadFExpression(inputRoot, expression->getChild(1)) + }; + if (!inputExpressions[0] || !inputExpressions[1]) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGAtan2Expression(inputExpressions[0], inputExpressions[1]); + } + if (name == "div") { + if (expression->nChildren() != 2) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpressions[2] = { + SGReadFExpression(inputRoot, expression->getChild(0)), + SGReadFExpression(inputRoot, expression->getChild(1)) + }; + if (!inputExpressions[0] || !inputExpressions[1]) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGDivExpression(inputExpressions[0], inputExpressions[1]); + } + if (name == "mod") { + if (expression->nChildren() != 2) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpressions[2] = { + SGReadFExpression(inputRoot, expression->getChild(0)), + SGReadFExpression(inputRoot, expression->getChild(1)) + }; + if (!inputExpressions[0] || !inputExpressions[1]) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGModExpression(inputExpressions[0], inputExpressions[1]); + } + if (name == "pow") { + if (expression->nChildren() != 2) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + SGSharedPtr > inputExpressions[2] = { + SGReadIExpression(inputRoot, expression->getChild(0)), + SGReadIExpression(inputRoot, expression->getChild(1)) + }; + if (!inputExpressions[0] || !inputExpressions[1]) { + SG_LOG(SG_IO, SG_ALERT, "Cannot read \"" << name << "\" expression."); + return 0; + } + return new SGPowExpression(inputExpressions[0], inputExpressions[1]); + } + + return 0; +} + +SGExpression* +SGReadIntExpression(SGPropertyNode *inputRoot, + const SGPropertyNode *configNode) +{ return SGReadIExpression(inputRoot, configNode); } + +SGExpression* +SGReadFloatExpression(SGPropertyNode *inputRoot, + const SGPropertyNode *configNode) +{ return SGReadFExpression(inputRoot, configNode); } + +SGExpression* +SGReadDoubleExpression(SGPropertyNode *inputRoot, + const SGPropertyNode *configNode) +{ return SGReadFExpression(inputRoot, configNode); } + +// SGExpression* +// SGReadBoolExpression(SGPropertyNode *inputRoot, +// const SGPropertyNode *configNode) +// { return SGReadBExpression(inputRoot, configNode); } diff --git a/simgear/structure/SGExpression.hxx b/simgear/structure/SGExpression.hxx new file mode 100644 index 00000000..c3e3bac5 --- /dev/null +++ b/simgear/structure/SGExpression.hxx @@ -0,0 +1,801 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef _SG_EXPRESSION_HXX +#define _SG_EXPRESSION_HXX 1 + +#include +#include +#include +#include +#include + +/// Expression tree implementation. + +template +class SGExpression : public SGReferenced { +public: + virtual ~SGExpression() {} + virtual void eval(T&) const = 0; + + T getValue() const + { T value; eval(value); return value; } + + virtual bool isConst() const { return false; } + virtual SGExpression* simplify(); +}; + +/// Constant value expression +template +class SGConstExpression : public SGExpression { +public: + SGConstExpression(const T& value = T()) : _value(value) + { } + void setValue(const T& value) + { _value = value; } + const T& getValue() const + { return _value; } + virtual void eval(T& value) const + { value = _value; } + virtual bool isConst() const { return true; } +private: + T _value; +}; + +template +SGExpression* +SGExpression::simplify() +{ + if (isConst()) + return new SGConstExpression(getValue()); + return this; +} + +template +class SGUnaryExpression : public SGExpression { +public: + const SGExpression* getOperand() const + { return _expression; } + SGExpression* getOperand() + { return _expression; } + void setOperand(SGExpression* expression) + { + if (!expression) + expression = new SGConstExpression(T()); + _expression = expression; + } + virtual bool isConst() const + { return getOperand()->isConst(); } + virtual SGExpression* simplify() + { + _expression = _expression->simplify(); + return SGExpression::simplify(); + } + +protected: + SGUnaryExpression(SGExpression* expression = 0) + { setOperand(expression); } + +private: + SGSharedPtr > _expression; +}; + +template +class SGBinaryExpression : public SGExpression { +public: + const SGExpression* getOperand(unsigned i) const + { return _expressions[i]; } + SGExpression* getOperand(unsigned i) + { return _expressions[i]; } + void setOperand(unsigned i, SGExpression* expression) + { + if (!expression) + expression = new SGConstExpression(T()); + if (2 <= i) + i = 0; + _expressions[i] = expression; + } + + virtual bool isConst() const + { return getOperand(0)->isConst() && getOperand(1)->isConst(); } + virtual SGExpression* simplify() + { + _expressions[0] = _expressions[0]->simplify(); + _expressions[1] = _expressions[1]->simplify(); + return SGExpression::simplify(); + } + +protected: + SGBinaryExpression(SGExpression* expr0, SGExpression* expr1) + { setOperand(0, expr0); setOperand(1, expr1); } + +private: + SGSharedPtr > _expressions[2]; +}; + +template +class SGNaryExpression : public SGExpression { +public: + unsigned getNumOperands() const + { return _expressions.size(); } + const SGExpression* getOperand(unsigned i) const + { return _expressions[i]; } + SGExpression* getOperand(unsigned i) + { return _expressions[i]; } + unsigned addOperand(SGExpression* expression) + { + if (!expression) + return ~unsigned(0); + _expressions.push_back(expression); + return _expressions.size() - 1; + } + + virtual bool isConst() const + { + for (unsigned i = 0; i < _expressions.size(); ++i) + if (!_expressions[i]->isConst()) + return false; + return true; + } + virtual SGExpression* simplify() + { + for (unsigned i = 0; i < _expressions.size(); ++i) + _expressions[i] = _expressions[i]->simplify(); + return SGExpression::simplify(); + } + +protected: + SGNaryExpression() + { } + SGNaryExpression(SGExpression* expr0, SGExpression* expr1) + { addOperand(expr0); addOperand(expr1); } + +private: + std::vector > > _expressions; +}; + + + + +template +class SGPropertyExpression : public SGExpression { +public: + SGPropertyExpression(const SGPropertyNode* prop) : _prop(prop) + { } + void setPropertyNode(const SGPropertyNode* prop) + { _prop = prop; } + virtual void eval(T& value) const + { doEval(value); } +private: + void doEval(float& value) const + { if (_prop) value = _prop->getFloatValue(); } + void doEval(double& value) const + { if (_prop) value = _prop->getDoubleValue(); } + void doEval(int& value) const + { if (_prop) value = _prop->getIntValue(); } + void doEval(long& value) const + { if (_prop) value = _prop->getLongValue(); } + void doEval(bool& value) const + { if (_prop) value = _prop->getBoolValue(); } + SGSharedPtr _prop; +}; + +template +class SGAbsExpression : public SGUnaryExpression { +public: + SGAbsExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = getOperand()->getValue(); if (value <= 0) value = -value; } + + using SGUnaryExpression::getOperand; +}; + +template +class SGACosExpression : public SGUnaryExpression { +public: + SGACosExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = acos(SGMisc::clip(getOperand()->getValue(), -1, 1)); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGASinExpression : public SGUnaryExpression { +public: + SGASinExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = asin(SGMisc::clip(getOperand()->getValue(), -1, 1)); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGATanExpression : public SGUnaryExpression { +public: + SGATanExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = atan(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGCeilExpression : public SGUnaryExpression { +public: + SGCeilExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = ceil(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGCosExpression : public SGUnaryExpression { +public: + SGCosExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = cos(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGCoshExpression : public SGUnaryExpression { +public: + SGCoshExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = cosh(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGExpExpression : public SGUnaryExpression { +public: + SGExpExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = exp(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGFloorExpression : public SGUnaryExpression { +public: + SGFloorExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = floor(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGLogExpression : public SGUnaryExpression { +public: + SGLogExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = log(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGLog10Expression : public SGUnaryExpression { +public: + SGLog10Expression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = log10(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGSinExpression : public SGUnaryExpression { +public: + SGSinExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = sin(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGSinhExpression : public SGUnaryExpression { +public: + SGSinhExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = sinh(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGSqrExpression : public SGUnaryExpression { +public: + SGSqrExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = getOperand()->getValue(); value = value*value; } + + using SGUnaryExpression::getOperand; +}; + +template +class SGSqrtExpression : public SGUnaryExpression { +public: + SGSqrtExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = sqrt(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGTanExpression : public SGUnaryExpression { +public: + SGTanExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = tan(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGTanhExpression : public SGUnaryExpression { +public: + SGTanhExpression(SGExpression* expr = 0) + : SGUnaryExpression(expr) + { } + + virtual void eval(T& value) const + { value = tanh(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; +}; + +template +class SGScaleExpression : public SGUnaryExpression { +public: + SGScaleExpression(SGExpression* expr = 0, const T& scale = T(1)) + : SGUnaryExpression(expr), _scale(scale) + { } + void setScale(const T& scale) + { _scale = scale; } + const T& getScale() const + { return _scale; } + + virtual void eval(T& value) const + { value = _scale * getOperand()->getValue(); } + + virtual SGExpression* simplify() + { + if (_scale == 1) + return getOperand()->simplify(); + return SGUnaryExpression::simplify(); + } + + using SGUnaryExpression::getOperand; +private: + T _scale; +}; + +template +class SGBiasExpression : public SGUnaryExpression { +public: + SGBiasExpression(SGExpression* expr = 0, const T& bias = T(0)) + : SGUnaryExpression(expr), _bias(bias) + { } + + void setBias(const T& bias) + { _bias = bias; } + const T& getBias() const + { return _bias; } + + virtual void eval(T& value) const + { value = _bias + getOperand()->getValue(); } + + virtual SGExpression* simplify() + { + if (_bias == 0) + return getOperand()->simplify(); + return SGUnaryExpression::simplify(); + } + + using SGUnaryExpression::getOperand; +private: + T _bias; +}; + +template +class SGInterpTableExpression : public SGUnaryExpression { +public: + SGInterpTableExpression(SGExpression* expr, + const SGInterpTable* interpTable) : + SGUnaryExpression(expr), + _interpTable(interpTable) + { } + + virtual void eval(T& value) const + { + if (_interpTable) + value = _interpTable->interpolate(getOperand()->getValue()); + } + + using SGUnaryExpression::getOperand; +private: + SGSharedPtr _interpTable; +}; + +template +class SGClipExpression : public SGUnaryExpression { +public: + SGClipExpression(SGExpression* expr) + : SGUnaryExpression(expr), + _clipMin(SGMisc::min(-SGLimits::max(), SGLimits::min())), + _clipMax(SGLimits::max()) + { } + SGClipExpression(SGExpression* expr, + const T& clipMin, const T& clipMax) + : SGUnaryExpression(expr), + _clipMin(clipMin), + _clipMax(clipMax) + { } + + void setClipMin(const T& clipMin) + { _clipMin = clipMin; } + const T& getClipMin() const + { return _clipMin; } + + void setClipMax(const T& clipMax) + { _clipMax = clipMax; } + const T& getClipMax() const + { return _clipMax; } + + virtual void eval(T& value) const + { + value = SGMisc::clip(getOperand()->getValue(), _clipMin, _clipMax); + } + + virtual SGExpression* simplify() + { + if (_clipMin <= SGMisc::min(-SGLimits::max(), SGLimits::min()) && + _clipMax >= SGLimits::max()) + return getOperand()->simplify(); + return SGUnaryExpression::simplify(); + } + + using SGUnaryExpression::getOperand; +private: + T _clipMin; + T _clipMax; +}; + +template +class SGStepExpression : public SGUnaryExpression { +public: + SGStepExpression(SGExpression* expr = 0, + const T& step = T(1), const T& scroll = T(0)) + : SGUnaryExpression(expr), _step(step), _scroll(scroll) + { } + + void setStep(const T& step) + { _step = step; } + const T& getStep() const + { return _step; } + + void setScroll(const T& scroll) + { _scroll = scroll; } + const T& getScroll() const + { return _scroll; } + + virtual void eval(T& value) const + { value = apply_mods(getOperand()->getValue()); } + + using SGUnaryExpression::getOperand; + +private: + T apply_mods(T property) const + { + T modprop; + if (_step > 0) { + T scrollval = 0; + if(_scroll > 0) { + // calculate scroll amount (for odometer like movement) + T remainder = _step - fmod(fabs(property), _step); + if (remainder < _scroll) { + scrollval = (_scroll - remainder) / _scroll * _step; + } + } + // apply stepping of input value + if(property > 0) + modprop = ((floor(property/_step) * _step) + scrollval); + else + modprop = ((ceil(property/_step) * _step) + scrollval); + } else { + modprop = property; + } + return modprop; + } + + T _step; + T _scroll; +}; + +template +class SGEnableExpression : public SGUnaryExpression { +public: + SGEnableExpression(SGExpression* expr = 0, + SGCondition* enable = 0, + const T& disabledValue = T(0)) + : SGUnaryExpression(expr), + _enable(enable), + _disabledValue(disabledValue) + { } + + const T& getDisabledValue() const + { return _disabledValue; } + void setDisabledValue(const T& disabledValue) + { _disabledValue = disabledValue; } + + virtual void eval(T& value) const + { + if (_enable->test()) + value = getOperand()->getValue(); + else + value = _disabledValue; + } + + virtual SGExpression* simplify() + { + if (!_enable) + return getOperand()->simplify(); + return SGUnaryExpression::simplify(); + } + + using SGUnaryExpression::getOperand; +private: + SGSharedPtr _enable; + T _disabledValue; +}; + +template +class SGAtan2Expression : public SGBinaryExpression { +public: + SGAtan2Expression(SGExpression* expr0, SGExpression* expr1) + : SGBinaryExpression(expr0, expr1) + { } + virtual void eval(T& value) const + { value = atan2(getOperand(0)->getValue(), getOperand(1)->getValue()); } + using SGBinaryExpression::getOperand; +}; + +template +class SGDivExpression : public SGBinaryExpression { +public: + SGDivExpression(SGExpression* expr0, SGExpression* expr1) + : SGBinaryExpression(expr0, expr1) + { } + virtual void eval(T& value) const + { value = getOperand(0)->getValue() / getOperand(1)->getValue(); } + using SGBinaryExpression::getOperand; +}; + +template +class SGModExpression : public SGBinaryExpression { +public: + SGModExpression(SGExpression* expr0, SGExpression* expr1) + : SGBinaryExpression(expr0, expr1) + { } + virtual void eval(T& value) const + { value = mod(getOperand(0)->getValue(), getOperand(1)->getValue()); } + using SGBinaryExpression::getOperand; +private: + int mod(const int& v0, const int& v1) const + { return v0 % v1; } + float mod(const float& v0, const float& v1) const + { return fmod(v0, v1); } + double mod(const double& v0, const double& v1) const + { return fmod(v0, v1); } +}; + +template +class SGPowExpression : public SGBinaryExpression { +public: + SGPowExpression(SGExpression* expr0, SGExpression* expr1) + : SGBinaryExpression(expr0, expr1) + { } + virtual void eval(T& value) const + { value = pow(getOperand(0)->getValue(), getOperand(1)->getValue()); } + using SGBinaryExpression::getOperand; +}; + +template +class SGSumExpression : public SGNaryExpression { +public: + SGSumExpression() + { } + SGSumExpression(SGExpression* expr0, SGExpression* expr1) + : SGNaryExpression(expr0, expr1) + { } + virtual void eval(T& value) const + { + value = T(0); + unsigned sz = SGNaryExpression::getNumOperands(); + for (unsigned i = 0; i < sz; ++i) + value += getOperand(i)->getValue(); + } + using SGNaryExpression::getValue; + using SGNaryExpression::getOperand; +}; + +template +class SGProductExpression : public SGNaryExpression { +public: + SGProductExpression() + { } + SGProductExpression(SGExpression* expr0, SGExpression* expr1) + : SGNaryExpression(expr0, expr1) + { } + virtual void eval(T& value) const + { + value = T(1); + unsigned sz = SGNaryExpression::getNumOperands(); + for (unsigned i = 0; i < sz; ++i) + value *= getOperand(i)->getValue(); + } + using SGNaryExpression::getValue; + using SGNaryExpression::getOperand; +}; + +template +class SGMinExpression : public SGNaryExpression { +public: + SGMinExpression() + { } + SGMinExpression(SGExpression* expr0, SGExpression* expr1) + : SGNaryExpression(expr0, expr1) + { } + virtual void eval(T& value) const + { + unsigned sz = SGNaryExpression::getNumOperands(); + if (sz < 1) + return; + + value = getOperand(0)->getValue(); + for (unsigned i = 1; i < sz; ++i) + value = SGMisc::min(value, getOperand(i)->getValue()); + } + using SGNaryExpression::getOperand; +}; + +template +class SGMaxExpression : public SGNaryExpression { +public: + SGMaxExpression() + { } + SGMaxExpression(SGExpression* expr0, SGExpression* expr1) + : SGNaryExpression(expr0, expr1) + { } + virtual void eval(T& value) const + { + unsigned sz = SGNaryExpression::getNumOperands(); + if (sz < 1) + return; + + value = getOperand(0)->getValue(); + for (unsigned i = 1; i < sz; ++i) + value = SGMisc::max(value, getOperand(i)->getValue()); + } + using SGNaryExpression::getOperand; +}; + +typedef SGExpression SGExpressioni; +typedef SGExpression SGExpressionf; +typedef SGExpression SGExpressiond; +typedef SGExpression SGExpressionb; + +/** + * Global function to make an expression out of properties. + + + 0 + 79 + + + + sim/model/whatever-rad + + sim/model/someother-deg + -90 + + + + +will evaluate to an expression: + +SGMisc::clip(abs(deg2rad*sim/model/whatever-rad + sim/model/someother-deg - 90), clipMin, clipMax); + + */ +SGExpression* +SGReadIntExpression(SGPropertyNode *inputRoot, + const SGPropertyNode *configNode); + +SGExpression* +SGReadFloatExpression(SGPropertyNode *inputRoot, + const SGPropertyNode *configNode); + +SGExpression* +SGReadDoubleExpression(SGPropertyNode *inputRoot, + const SGPropertyNode *configNode); + +SGExpression* +SGReadBoolExpression(SGPropertyNode *inputRoot, + const SGPropertyNode *configNode); + +#endif // _SG_EXPRESSION_HXX