osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthSymbology/Expression.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003 * Copyright 2008-2010 Pelican Mapping
00004 * http://osgearth.org
00005 *
00006 * osgEarth is free software; you can redistribute it and/or modify
00007 * it under the terms of the GNU Lesser General Public License as published by
00008 * the Free Software Foundation; either version 2 of the License, or
00009 * (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU Lesser General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU Lesser General Public License
00017 * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018 */
00019 #include <osgEarthSymbology/Expression>
00020 #include <osgEarth/StringUtils>
00021 #include <algorithm>
00022 
00023 using namespace osgEarth;
00024 using namespace osgEarth::Symbology;
00025 
00026 NumericExpression::NumericExpression( const std::string& expr ) : 
00027 _src  ( expr ),
00028 _value( 0.0 ),
00029 _dirty( true )
00030 {
00031     init();
00032 }
00033 
00034 NumericExpression::NumericExpression( const NumericExpression& rhs ) :
00035 _src  ( rhs._src ),
00036 _rpn  ( rhs._rpn ),
00037 _vars ( rhs._vars ),
00038 _value( rhs._value ),
00039 _dirty( rhs._dirty )
00040 {
00041     //nop
00042 }
00043 
00044 NumericExpression::NumericExpression( double staticValue ) :
00045 _value( staticValue ),
00046 _dirty( false )
00047 {
00048     _src = Stringify() << staticValue;
00049     init();
00050 }
00051 
00052 NumericExpression::NumericExpression( const Config& conf )
00053 {
00054     mergeConfig( conf );
00055     init();
00056 }
00057 
00058 void
00059 NumericExpression::mergeConfig( const Config& conf )
00060 {
00061     _src = conf.value();
00062     init();
00063     _dirty = true;
00064 }
00065 
00066 Config
00067 NumericExpression::getConfig() const
00068 {
00069     return Config( "numeric_expression", _src );
00070 }
00071 
00072 #define IS_OPERATOR(a) ( a .first == ADD || a .first == SUB || a .first == MULT || a .first == DIV || a .first == MOD )
00073 
00074 void
00075 NumericExpression::init()
00076 {
00077     _vars.clear();
00078     _rpn.clear();
00079 
00080     StringTokenizer tokenizer( "", "'\"" );
00081     tokenizer.addDelims( "[],()%*/+-", true );
00082     tokenizer.keepEmpties() = false;
00083 
00084     StringVector t;
00085     tokenizer.tokenize( _src, t );
00086     //tokenize(_src, t, "[],()%*/+-", "'\"", false, true);
00087 
00088     // identify tokens:
00089     AtomVector infix;
00090     bool invar = false;
00091     for( unsigned i=0; i<t.size(); ++i ) {
00092         if ( t[i] == "[" && !invar ) {
00093             invar = true;
00094         }
00095         else if ( t[i] == "]" && invar ) {
00096             invar = false;
00097             infix.push_back( Atom(VARIABLE,0.0) );
00098             _vars.push_back( Variable(t[i-1],0) );
00099         }
00100         else if ( t[i] == "(" ) infix.push_back( Atom(LPAREN,0.0) );
00101         else if ( t[i] == ")" ) infix.push_back( Atom(RPAREN,0.0) );
00102         else if ( t[i] == "," ) infix.push_back( Atom(COMMA,0.0) );
00103         else if ( t[i] == "%" ) infix.push_back( Atom(MOD,0.0) );
00104         else if ( t[i] == "*" ) infix.push_back( Atom(MULT,0.0) );
00105         else if ( t[i] == "/" ) infix.push_back( Atom(DIV,0.0) );
00106         else if ( t[i] == "+" ) infix.push_back( Atom(ADD,0.0) );
00107         else if ( t[i] == "-" ) infix.push_back( Atom(SUB,0.0) );
00108         else if ( t[i] == "min" ) infix.push_back( Atom(MIN,0.0) );
00109         else if ( t[i] == "max" ) infix.push_back( Atom(MAX,0.0) );
00110         else if ( (t[i][0] >= '0' && t[i][0] <= '9') || t[i][0] == '.' )
00111             infix.push_back( Atom(OPERAND,as<double>(t[i],0.0)) );
00112 
00113         // note: do nothing for a comma
00114     }
00115 
00116     // convert to RPN:
00117     // http://en.wikipedia.org/wiki/Shunting-yard_algorithm
00118     AtomStack s;
00119     unsigned var_i = 0;
00120 
00121     for( unsigned i=0; i<infix.size(); ++i )
00122     {
00123         Atom& a = infix[i];
00124 
00125         if ( a.first == LPAREN )
00126         {
00127             s.push( a );
00128         }
00129         else if ( a.first == RPAREN )
00130         {
00131             while( s.size() > 0 )
00132             {
00133                 Atom top = s.top();
00134                 s.pop();
00135                 if ( top.first == LPAREN )
00136                     break;
00137                 else
00138                     _rpn.push_back( top );
00139             }
00140         }
00141         else if ( a.first == COMMA )
00142         {
00143             while( s.size() > 0 && s.top().first != LPAREN )
00144             {
00145                 _rpn.push_back( s.top() );
00146                 s.pop();
00147             }
00148         }
00149         else if ( IS_OPERATOR(a) )
00150         {
00151             if ( s.empty() || a.first > s.top().first )
00152             {
00153                 s.push( a );
00154             }
00155             else 
00156             {
00157                 while( s.size() > 0 && a.first < s.top().first && IS_OPERATOR(s.top()) )
00158                 {
00159                     _rpn.push_back( s.top() );
00160                     s.pop();
00161                 }
00162                 s.push( a );
00163             }
00164         }
00165         else if ( a.first == MIN || a.first == MAX )
00166         {
00167             s.push( a );
00168         }
00169         else if ( a.first == OPERAND )
00170         {
00171             _rpn.push_back( a );
00172         }
00173         else if ( a.first == VARIABLE )
00174         {
00175             _rpn.push_back( a );
00176             _vars[var_i++].second = _rpn.size()-1; // store the index
00177         }
00178     }
00179 
00180     while( s.size() > 0 )
00181     {
00182         _rpn.push_back( s.top() );
00183         s.pop();
00184     }
00185 }
00186 
00187 void 
00188 NumericExpression::set( const Variable& var, double value )
00189 {
00190     Atom& a = _rpn[var.second];
00191     if ( a.second != value )
00192     {
00193         a.second = value;
00194         _dirty = true;
00195     }
00196 }
00197 
00198 double
00199 NumericExpression::eval() const
00200 {
00201     if ( _dirty )
00202     {
00203         std::stack<double> s;
00204 
00205         for( unsigned i=0; i<_rpn.size(); ++i )
00206         {
00207             const Atom& a = _rpn[i];
00208 
00209             if ( a.first == ADD )
00210             {
00211                 if ( s.size() >= 2 )
00212                 {
00213                     double op2 = s.top(); s.pop();
00214                     double op1 = s.top(); s.pop();
00215                     s.push( op1 + op2 );
00216                 }
00217             }
00218             else if ( a.first == SUB )
00219             {
00220                 if ( s.size() >= 2 )
00221                 {
00222                     double op2 = s.top(); s.pop();
00223                     double op1 = s.top(); s.pop();
00224                     s.push( op1 - op2 );
00225                 }
00226             }
00227             else if ( a.first == MULT )
00228             {
00229                 if ( s.size() >= 2 )
00230                 {
00231                     double op2 = s.top(); s.pop();
00232                     double op1 = s.top(); s.pop();
00233                     s.push( op1 * op2 );
00234                 }
00235             }
00236             else if ( a.first == DIV )
00237             {
00238                 if ( s.size() >= 2 )
00239                 {
00240                     double op2 = s.top(); s.pop();
00241                     double op1 = s.top(); s.pop();
00242                     s.push( op1 / op2 );
00243                 }
00244             }
00245             else if ( a.first == MOD )
00246             {
00247                 if ( s.size() >= 2 )
00248                 {
00249                     double op2 = s.top(); s.pop();
00250                     double op1 = s.top(); s.pop();
00251                     s.push( fmod(op1, op2) );
00252                 }
00253             }
00254             else if ( a.first == MIN )
00255             {
00256                 if ( s.size() >= 2 )
00257                 {
00258                     double op2 = s.top(); s.pop();
00259                     double op1 = s.top(); s.pop();
00260                     s.push( std::min(op1, op2) );
00261                 }
00262             }
00263             else if ( a.first == MAX )
00264             {
00265                 if ( s.size() >= 2 )
00266                 {
00267                     double op2 = s.top(); s.pop();
00268                     double op1 = s.top(); s.pop();
00269                     s.push( std::max(op1, op2) );
00270                 }
00271             }
00272             else // OPERAND or VARIABLE
00273             {
00274                 s.push( a.second );
00275             }
00276         }
00277 
00278         const_cast<NumericExpression*>(this)->_value = s.size() > 0 ? s.top() : 0.0;
00279         const_cast<NumericExpression*>(this)->_dirty = false;
00280     }
00281 
00282     return !osg::isNaN( _value ) ? _value : 0.0;
00283 }
00284 
00285 //------------------------------------------------------------------------
00286 
00287 StringExpression::StringExpression( const std::string& expr ) : 
00288 _src( expr ),
00289 _dirty( true )
00290 {
00291     init();
00292 }
00293 
00294 StringExpression::StringExpression( const StringExpression& rhs ) :
00295 _src( rhs._src ),
00296 _vars( rhs._vars ),
00297 _value( rhs._value ),
00298 _infix( rhs._infix ),
00299 _dirty( rhs._dirty ),
00300 _uriContext( rhs._uriContext )
00301 {
00302     //nop
00303 }
00304 
00305 StringExpression::StringExpression( const Config& conf )
00306 {
00307     mergeConfig( conf );
00308     init();
00309 }
00310 
00311 void
00312 StringExpression::mergeConfig( const Config& conf )
00313 {
00314     _src = conf.value();
00315     _dirty = true;
00316 }
00317 
00318 Config
00319 StringExpression::getConfig() const
00320 {
00321     return Config( "string_expression", _src );
00322 }
00323 
00324 void
00325 StringExpression::init()
00326 {
00327     StringTokenizer izer("", "");
00328     izer.addDelims( "[]", true );
00329     izer.addQuotes( "'\"", false );
00330     izer.keepEmpties() = false;
00331     izer.trimTokens() = false;
00332 
00333     StringVector t;
00334     izer.tokenize( _src, t );
00335     //tokenize(_src, t, "[]", "'\"", false, true, false);
00336 
00337     // identify tokens:
00338     bool invar = false;
00339     for( unsigned i=0; i<t.size(); ++i )
00340     {
00341         if ( t[i] == "[" && !invar )
00342         {
00343             invar = true;
00344         }
00345         else if ( t[i] == "]" && invar )
00346         {
00347             invar = false;
00348             _infix.push_back( Atom(VARIABLE,"") );
00349             _vars.push_back( Variable(t[i-1],0) );
00350         }
00351         else
00352             _infix.push_back( Atom(OPERAND,t[i]) );
00353     }
00354 }
00355 
00356 void 
00357 StringExpression::set( const Variable& var, const std::string& value )
00358 {
00359     Atom& a = _infix[var.second];
00360     if ( a.second != value )
00361     {
00362         a.second = value;
00363         _dirty = true;
00364     }
00365 }
00366 
00367 const std::string&
00368 StringExpression::eval() const
00369 {
00370     if ( _dirty )
00371     {
00372         std::stringstream buf;
00373         for( AtomVector::const_iterator i = _infix.begin(); i != _infix.end(); ++i )
00374             buf << i->second;
00375 
00376         const_cast<StringExpression*>(this)->_value = buf.str();
00377         const_cast<StringExpression*>(this)->_dirty = false;
00378     }
00379 
00380     return _value;
00381 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines