osgEarth 2.1.1
Public Types | Public Member Functions | Private Types | Private Member Functions | Private Attributes

osgEarth::Symbology::NumericExpression Class Reference

List of all members.

Public Types

typedef std::pair< std::string,
unsigned > 
Variable
typedef std::vector< VariableVariables

Public Member Functions

 NumericExpression ()
 NumericExpression (const Config &conf)
 NumericExpression (const std::string &expr)
 NumericExpression (double staticValue)
 NumericExpression (const NumericExpression &rhs)
const Variablesvariables () const
void set (const Variable &var, double value)
double eval () const
const std::string & expr () const
bool empty () const
Config getConfig () const
void mergeConfig (const Config &conf)

Private Types

enum  Op {
  OPERAND, VARIABLE, ADD, SUB,
  MULT, DIV, MOD, MIN,
  MAX, LPAREN, RPAREN, COMMA
}
typedef std::pair< Op, double > Atom
typedef std::vector< AtomAtomVector
typedef std::stack< AtomAtomStack

Private Member Functions

void init ()

Private Attributes

std::string _src
AtomVector _rpn
Variables _vars
double _value
bool _dirty

Detailed Description

Simple numeric expression evaluator with variables.

Definition at line 33 of file Expression.


Member Typedef Documentation

typedef std::pair<Op,double> osgEarth::Symbology::NumericExpression::Atom [private]

Definition at line 74 of file Expression.

Definition at line 76 of file Expression.

Definition at line 75 of file Expression.

typedef std::pair<std::string,unsigned> osgEarth::Symbology::NumericExpression::Variable

Definition at line 36 of file Expression.

Definition at line 37 of file Expression.


Member Enumeration Documentation

Enumerator:
OPERAND 
VARIABLE 
ADD 
SUB 
MULT 
DIV 
MOD 
MIN 
MAX 
LPAREN 
RPAREN 
COMMA 

Definition at line 73 of file Expression.

{ OPERAND, VARIABLE, ADD, SUB, MULT, DIV, MOD, MIN, MAX, LPAREN, RPAREN, COMMA }; // in low-high precedence order

Constructor & Destructor Documentation

osgEarth::Symbology::NumericExpression::NumericExpression ( ) [inline]

Definition at line 40 of file Expression.

{ }
NumericExpression::NumericExpression ( const Config conf)

Definition at line 52 of file Expression.cpp.

{
    mergeConfig( conf );
    init();
}

Here is the call graph for this function:

NumericExpression::NumericExpression ( const std::string &  expr)

Construct a new expression from the infix string.

Definition at line 26 of file Expression.cpp.

                                                            : 
_src  ( expr ),
_value( 0.0 ),
_dirty( true )
{
    init();
}

Here is the call graph for this function:

NumericExpression::NumericExpression ( double  staticValue)

Construct a new static expression from a value

Definition at line 44 of file Expression.cpp.

                                                         :
_value( staticValue ),
_dirty( false )
{
    _src = Stringify() << staticValue;
    init();
}

Here is the call graph for this function:

NumericExpression::NumericExpression ( const NumericExpression rhs)

Copy ctor.

Definition at line 34 of file Expression.cpp.

                                                                   :
_src  ( rhs._src ),
_rpn  ( rhs._rpn ),
_vars ( rhs._vars ),
_value( rhs._value ),
_dirty( rhs._dirty )
{
    //nop
}

Member Function Documentation

bool osgEarth::Symbology::NumericExpression::empty ( ) const [inline]

Whether the expression is empty

Definition at line 66 of file Expression.

{ return _src.empty(); }
double NumericExpression::eval ( ) const

Evaluate the expression.

Definition at line 199 of file Expression.cpp.

{
    if ( _dirty )
    {
        std::stack<double> s;

        for( unsigned i=0; i<_rpn.size(); ++i )
        {
            const Atom& a = _rpn[i];

            if ( a.first == ADD )
            {
                if ( s.size() >= 2 )
                {
                    double op2 = s.top(); s.pop();
                    double op1 = s.top(); s.pop();
                    s.push( op1 + op2 );
                }
            }
            else if ( a.first == SUB )
            {
                if ( s.size() >= 2 )
                {
                    double op2 = s.top(); s.pop();
                    double op1 = s.top(); s.pop();
                    s.push( op1 - op2 );
                }
            }
            else if ( a.first == MULT )
            {
                if ( s.size() >= 2 )
                {
                    double op2 = s.top(); s.pop();
                    double op1 = s.top(); s.pop();
                    s.push( op1 * op2 );
                }
            }
            else if ( a.first == DIV )
            {
                if ( s.size() >= 2 )
                {
                    double op2 = s.top(); s.pop();
                    double op1 = s.top(); s.pop();
                    s.push( op1 / op2 );
                }
            }
            else if ( a.first == MOD )
            {
                if ( s.size() >= 2 )
                {
                    double op2 = s.top(); s.pop();
                    double op1 = s.top(); s.pop();
                    s.push( fmod(op1, op2) );
                }
            }
            else if ( a.first == MIN )
            {
                if ( s.size() >= 2 )
                {
                    double op2 = s.top(); s.pop();
                    double op1 = s.top(); s.pop();
                    s.push( std::min(op1, op2) );
                }
            }
            else if ( a.first == MAX )
            {
                if ( s.size() >= 2 )
                {
                    double op2 = s.top(); s.pop();
                    double op1 = s.top(); s.pop();
                    s.push( std::max(op1, op2) );
                }
            }
            else // OPERAND or VARIABLE
            {
                s.push( a.second );
            }
        }

        const_cast<NumericExpression*>(this)->_value = s.size() > 0 ? s.top() : 0.0;
        const_cast<NumericExpression*>(this)->_dirty = false;
    }

    return !osg::isNaN( _value ) ? _value : 0.0;
}

Here is the caller graph for this function:

const std::string& osgEarth::Symbology::NumericExpression::expr ( ) const [inline]

Gets the expression string.

Definition at line 63 of file Expression.

{ return _src; }
Config NumericExpression::getConfig ( ) const

Definition at line 67 of file Expression.cpp.

{
    return Config( "numeric_expression", _src );
}
void NumericExpression::init ( ) [private]

Definition at line 75 of file Expression.cpp.

{
    _vars.clear();
    _rpn.clear();

    StringTokenizer tokenizer( "", "'\"" );
    tokenizer.addDelims( "[],()%*/+-", true );
    tokenizer.keepEmpties() = false;

    StringVector t;
    tokenizer.tokenize( _src, t );
    //tokenize(_src, t, "[],()%*/+-", "'\"", false, true);

    // identify tokens:
    AtomVector infix;
    bool invar = false;
    for( unsigned i=0; i<t.size(); ++i ) {
        if ( t[i] == "[" && !invar ) {
            invar = true;
        }
        else if ( t[i] == "]" && invar ) {
            invar = false;
            infix.push_back( Atom(VARIABLE,0.0) );
            _vars.push_back( Variable(t[i-1],0) );
        }
        else if ( t[i] == "(" ) infix.push_back( Atom(LPAREN,0.0) );
        else if ( t[i] == ")" ) infix.push_back( Atom(RPAREN,0.0) );
        else if ( t[i] == "," ) infix.push_back( Atom(COMMA,0.0) );
        else if ( t[i] == "%" ) infix.push_back( Atom(MOD,0.0) );
        else if ( t[i] == "*" ) infix.push_back( Atom(MULT,0.0) );
        else if ( t[i] == "/" ) infix.push_back( Atom(DIV,0.0) );
        else if ( t[i] == "+" ) infix.push_back( Atom(ADD,0.0) );
        else if ( t[i] == "-" ) infix.push_back( Atom(SUB,0.0) );
        else if ( t[i] == "min" ) infix.push_back( Atom(MIN,0.0) );
        else if ( t[i] == "max" ) infix.push_back( Atom(MAX,0.0) );
        else if ( (t[i][0] >= '0' && t[i][0] <= '9') || t[i][0] == '.' )
            infix.push_back( Atom(OPERAND,as<double>(t[i],0.0)) );

        // note: do nothing for a comma
    }

    // convert to RPN:
    // http://en.wikipedia.org/wiki/Shunting-yard_algorithm
    AtomStack s;
    unsigned var_i = 0;

    for( unsigned i=0; i<infix.size(); ++i )
    {
        Atom& a = infix[i];

        if ( a.first == LPAREN )
        {
            s.push( a );
        }
        else if ( a.first == RPAREN )
        {
            while( s.size() > 0 )
            {
                Atom top = s.top();
                s.pop();
                if ( top.first == LPAREN )
                    break;
                else
                    _rpn.push_back( top );
            }
        }
        else if ( a.first == COMMA )
        {
            while( s.size() > 0 && s.top().first != LPAREN )
            {
                _rpn.push_back( s.top() );
                s.pop();
            }
        }
        else if ( IS_OPERATOR(a) )
        {
            if ( s.empty() || a.first > s.top().first )
            {
                s.push( a );
            }
            else 
            {
                while( s.size() > 0 && a.first < s.top().first && IS_OPERATOR(s.top()) )
                {
                    _rpn.push_back( s.top() );
                    s.pop();
                }
                s.push( a );
            }
        }
        else if ( a.first == MIN || a.first == MAX )
        {
            s.push( a );
        }
        else if ( a.first == OPERAND )
        {
            _rpn.push_back( a );
        }
        else if ( a.first == VARIABLE )
        {
            _rpn.push_back( a );
            _vars[var_i++].second = _rpn.size()-1; // store the index
        }
    }

    while( s.size() > 0 )
    {
        _rpn.push_back( s.top() );
        s.pop();
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void NumericExpression::mergeConfig ( const Config conf)

Definition at line 59 of file Expression.cpp.

{
    _src = conf.value();
    init();
    _dirty = true;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void NumericExpression::set ( const Variable var,
double  value 
)

Set the value of a variable.

Definition at line 188 of file Expression.cpp.

{
    Atom& a = _rpn[var.second];
    if ( a.second != value )
    {
        a.second = value;
        _dirty = true;
    }
}

Here is the caller graph for this function:

const Variables& osgEarth::Symbology::NumericExpression::variables ( ) const [inline]

Access the expression variables.

Definition at line 54 of file Expression.

{ return _vars; }

Here is the caller graph for this function:


Member Data Documentation

Definition at line 82 of file Expression.

Definition at line 79 of file Expression.

Definition at line 78 of file Expression.

Definition at line 81 of file Expression.

Definition at line 80 of file Expression.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines