ParseExp.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00011 /*  This program is free software; you can redistribute it and/or
00012  *  modify it under the terms of the GNU General Public
00013  *  License as published by the Free Software Foundation; either
00014  *  version 2 of the License, or (at your option) any later version.
00015  *
00016  *  This software is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *  General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public
00022  *  License along with this software. If not, see
00023  *  <http://www.gnu.org/licenses/>.
00024  *
00025  */
00026 
00027 // parser using shunting yard algorithm using C++11 features
00028 #include <exception>
00029 #include <stack>
00030 #include <queue>
00031 #include <map>
00032 #include <functional>
00033 #define _USE_MATH_DEFINES
00034 #include <cmath>
00035 #include "ParseExp.h"
00036 #include "hugin_utils/utils.h"
00037 
00038 #include <panodata/ImageVariableTranslate.h>
00039 
00040 namespace Parser
00041 {
00042 
00043 typedef std::map<std::string, double> ConstantMap;
00044 
00045 namespace ShuntingYard
00046 {
00048 class ParseException : public std::runtime_error
00049 {
00050 public:
00051     explicit ParseException(const char *message) : std::runtime_error(message) {};
00052 };
00053 
00055 namespace RPNTokens
00056 {
00058 class TokenBase
00059 {
00060 public:
00061     virtual void evaluate(std::stack<double>&) = 0;
00062     virtual ~TokenBase() {};
00063 };
00064 
00066 class NumericToken :public TokenBase
00067 {
00068 public:
00069     explicit NumericToken(double val) : m_value(val) {};
00070     void evaluate(std::stack<double>& rpnStack) { rpnStack.push(m_value); };
00071 private:
00072     double m_value;
00073 };
00074 
00076 class FunctionToken : public TokenBase
00077 {
00078 public:
00079     explicit FunctionToken(std::function<double(double)> func) : TokenBase(), m_function(func) {};
00080     void evaluate(std::stack<double>& rpnStack)
00081     {
00082         if (rpnStack.empty())
00083         {
00084             throw ParseException("Unary operator expects one item on stack.");
00085         }
00086         const double val = rpnStack.top();
00087         rpnStack.pop();
00088         const double newVal = m_function(val);
00089         if (!std::isinf(newVal) && !std::isnan(newVal))
00090         {
00091             rpnStack.push(newVal);
00092         }
00093         else
00094         {
00095             throw ParseException("Invalid operation");
00096         };
00097     };
00098 private:
00099     std::function<double(double)> m_function;
00100 };
00101 
00103 class BinaryToken : public TokenBase
00104 {
00105 public:
00106     explicit BinaryToken(std::function<double(double, double)> func) : TokenBase(), m_function(func) {};
00107     void evaluate(std::stack<double>& rpnStack)
00108     {
00109         if (rpnStack.size() < 2)
00110         {
00111             throw ParseException("BinaryOperator expects 2 items on stack.");
00112         };
00113         const double right = rpnStack.top();
00114         rpnStack.pop();
00115         const double left = rpnStack.top();
00116         rpnStack.pop();
00117         const double newVal = m_function(left, right);
00118         if (!std::isinf(newVal) && !std::isnan(newVal))
00119         {
00120             rpnStack.push(newVal);
00121         }
00122         else
00123         {
00124             throw ParseException("Invalid operation");
00125         };
00126     };
00127 private:
00128     std::function<double(double, double)> m_function;
00129 };
00130 
00132 class IfToken : public TokenBase
00133 {
00134 public:
00135     void evaluate(std::stack<double>& rpnStack)
00136     {
00137         if (rpnStack.size() < 3)
00138         {
00139             throw ParseException("IfOperator expects 3 items on stack.");
00140         };
00141         const double elseVal = rpnStack.top();
00142         rpnStack.pop();
00143         const double ifVal = rpnStack.top();
00144         rpnStack.pop();
00145         const double compareVal = rpnStack.top();
00146         rpnStack.pop();
00147         if (fabs(compareVal) > 1e-8)
00148         {
00149             rpnStack.push(ifVal);
00150         }
00151         else
00152         {
00153             rpnStack.push(elseVal);
00154         };
00155     };
00156 };
00157 } // namespace RPNTokens
00158 
00160 namespace Operators
00161 {
00163 class OperatorBase
00164 {
00165 public:
00166     OperatorBase(int prec, bool rightAssoc = false) : m_precedence(prec), m_rightAssoc(rightAssoc) {};
00167     virtual ~OperatorBase() {};
00168     const int GetPrecedence() const { return m_precedence; };
00169     const bool IsRightAssociative() const { return m_rightAssoc; };
00170     bool ComparePrecedence(const OperatorBase* other)
00171     {
00172         if (IsRightAssociative())
00173         {
00174             return GetPrecedence() < other->GetPrecedence();
00175         }
00176         else
00177         {
00178             return GetPrecedence() <= other->GetPrecedence();
00179         };
00180     };
00181     virtual RPNTokens::TokenBase* GetTokenBase() { return nullptr; };
00182 private:
00183     int m_precedence;
00184     bool m_rightAssoc;
00185 };
00186 
00188 class FunctionOperator : public OperatorBase
00189 {
00190 public:
00191     FunctionOperator(std::function<double(double)> func, int prec = -2, bool rightAssoc = false) : OperatorBase(prec, rightAssoc), m_function(func) {};
00192     RPNTokens::TokenBase* GetTokenBase() { return new RPNTokens::FunctionToken(m_function); };
00193 private:
00194     std::function<double(double)> m_function;
00195 };
00196 
00198 class BinaryOperator : public OperatorBase
00199 {
00200 public:
00201     BinaryOperator(std::function<double(double, double)> func, int prec, bool rightAssoc = false) : OperatorBase(prec, rightAssoc), m_function(func) {};
00202     RPNTokens::TokenBase* GetTokenBase() { return new RPNTokens::BinaryToken(m_function); };
00203 private:
00204     std::function<double(double, double)> m_function;
00205 };
00206 
00208 class IfOperator : public OperatorBase
00209 {
00210 public:
00211     IfOperator() : OperatorBase(0, true) {};
00212     RPNTokens::TokenBase* GetTokenBase() { return new RPNTokens::IfToken(); }
00213 };
00214 }; // namespace Operators
00215 
00217 void ClearQueue(std::queue<RPNTokens::TokenBase*>& input)
00218 {
00219     while (!input.empty())
00220     {
00221         delete input.front();
00222         input.pop();
00223     }
00224 }
00225 
00227 std::string RemoveWhiteSpaces(const std::string& text)
00228 {
00229     std::string output;
00230     output.reserve(text.size());
00231     for (auto c : text)
00232     {
00233         if (!isspace(c))
00234         {
00235             output.push_back(tolower(c));
00236         };
00237     };
00238     return output;
00239 };
00240 
00241 static std::map<std::string, Operators::OperatorBase*> supportedBinaryOperations;
00242 static Operators::OperatorBase* parenthesesOperator = nullptr;
00243 static Operators::OperatorBase* ifOperator = nullptr;
00244 static Operators::OperatorBase* ifOperatorClose = nullptr;
00245 static std::map<std::string, Operators::FunctionOperator*> supportedFunctions;
00246 
00248 void InitParser()
00249 {
00250     if (supportedBinaryOperations.empty())
00251     {
00252         supportedBinaryOperations["||"] = new Operators::BinaryOperator(std::logical_or<double>(), 2);
00253         supportedBinaryOperations["&&"] = new Operators::BinaryOperator(std::logical_and<double>(), 3);
00254         supportedBinaryOperations["=="] = new Operators::BinaryOperator(std::equal_to<double>(), 4);
00255         supportedBinaryOperations["!="] = new Operators::BinaryOperator(std::not_equal_to<double>(), 4);
00256         supportedBinaryOperations["<"] = new Operators::BinaryOperator(std::less<double>(), 5);
00257         supportedBinaryOperations["<="] = new Operators::BinaryOperator(std::less_equal<double>(), 5);
00258         supportedBinaryOperations[">"] = new Operators::BinaryOperator(std::greater<double>(), 5);
00259         supportedBinaryOperations[">="] = new Operators::BinaryOperator(std::greater_equal<double>(), 5);
00260         supportedBinaryOperations["+"] = new Operators::BinaryOperator(std::plus<double>(), 6);
00261         supportedBinaryOperations["-"] = new Operators::BinaryOperator(std::minus<double>(), 6);
00262         supportedBinaryOperations["*"] = new Operators::BinaryOperator(std::multiplies<double>(), 7);
00263         supportedBinaryOperations["/"] = new Operators::BinaryOperator(std::divides<double>(), 7);
00264         supportedBinaryOperations["%"] = new Operators::BinaryOperator((double(*)(double, double))fmod, 7);
00265         supportedBinaryOperations["^"] = new Operators::BinaryOperator((double(*)(double, double))pow, 8, true);
00266         supportedBinaryOperations["UNARY_MINUS"] = new Operators::FunctionOperator([](double val)->double {return -1 * val; }, 9, true);
00267     }
00268     if (!parenthesesOperator)
00269     {
00270         parenthesesOperator = new Operators::OperatorBase(-1);
00271     };
00272     if (!ifOperator)
00273     {
00274         ifOperator = new Operators::OperatorBase(1);
00275     }
00276     if (!ifOperatorClose)
00277     {
00278         ifOperatorClose = new Operators::IfOperator();
00279     }
00280     if (supportedFunctions.empty())
00281     {
00282         supportedFunctions["abs"] = new Operators::FunctionOperator((double(*)(double))abs);
00283         supportedFunctions["sin"] = new Operators::FunctionOperator((double(*)(double))sin);
00284         supportedFunctions["cos"] = new Operators::FunctionOperator((double(*)(double))cos);
00285         supportedFunctions["tan"] = new Operators::FunctionOperator((double(*)(double))tan);
00286         supportedFunctions["asin"] = new Operators::FunctionOperator((double(*)(double))asin);
00287         supportedFunctions["acos"] = new Operators::FunctionOperator((double(*)(double))acos);
00288         supportedFunctions["atan"] = new Operators::FunctionOperator((double(*)(double))atan);
00289         supportedFunctions["exp"] = new Operators::FunctionOperator((double(*)(double))exp);
00290         supportedFunctions["log"] = new Operators::FunctionOperator((double(*)(double))log);
00291         supportedFunctions["ceil"] = new Operators::FunctionOperator((double(*)(double))ceil);
00292         supportedFunctions["floor"] = new Operators::FunctionOperator((double(*)(double))floor);
00293         supportedFunctions["sqrt"] = new Operators::FunctionOperator((double(*)(double))sqrt);
00294         supportedFunctions["deg"] = new Operators::FunctionOperator([](double val)->double { return val * 180.0f / M_PI; });
00295         supportedFunctions["rad"] = new Operators::FunctionOperator([](double val)->double { return val * M_PI / 180.0f; });
00296     }
00297 };
00298 
00300 void CleanUpParser()
00301 {
00302     for (auto it : supportedBinaryOperations)
00303     {
00304         delete it.second;
00305     };
00306     supportedBinaryOperations.clear();
00307     for (auto it : supportedFunctions)
00308     {
00309         delete it.second;
00310     };
00311     supportedFunctions.clear();
00312     if (parenthesesOperator)
00313     {
00314         delete parenthesesOperator;
00315         parenthesesOperator = nullptr;
00316     };
00317     if (ifOperator)
00318     {
00319         delete ifOperator;
00320         ifOperator = nullptr;
00321     };
00322     if (ifOperatorClose)
00323     {
00324         delete ifOperatorClose;
00325         ifOperatorClose = nullptr;
00326     };
00327 };
00328 
00330 std::string FindOperator(const std::string& searchString)
00331 {
00332     std::string foundOperator;
00333     for (auto it : supportedBinaryOperations)
00334     {
00335         const std::string op(it.first);
00336         if (searchString.compare(0, op.length(), op) == 0)
00337         {
00338             if (op.length() > foundOperator.length())
00339             {
00340                 foundOperator = op;
00341             }
00342         };
00343     };
00344     return foundOperator;
00345 };
00346 
00349 bool ConvertToRPN(const std::string& expression, const ConstantMap& constants, std::queue<RPNTokens::TokenBase*>& rpn)
00350 {
00351     // initialize some internal variables, don't forget to call CleanUpParser() at the end
00352     InitParser();
00353     size_t pos = 0;
00354     std::stack<Operators::OperatorBase*> operatorStack;
00355     bool lastTokenWasOperator = true;
00356     const size_t expressionLength = expression.length();
00357     while (pos < expressionLength)
00358     {
00359         const char currentChar = expression[pos];
00360         if (lastTokenWasOperator && (currentChar == '+' || currentChar == '-'))
00361         {
00362             // special handling of +/- prefix
00363             if (currentChar == '-')
00364             {
00365                 operatorStack.push(supportedBinaryOperations["UNARY_MINUS"]);
00366             };
00367             pos++;
00368             lastTokenWasOperator = false;
00369             continue;
00370         }
00371         if (isdigit(currentChar) || currentChar == '.')
00372         {
00373             // parse numbers
00374             size_t index;
00375             double val;
00376             try
00377             {
00378                 val = std::stod(expression.substr(pos), &index);
00379             }
00380             catch (std::invalid_argument)
00381             {
00382                 throw ParseException("Invalid number");
00383             }
00384             catch (std::out_of_range)
00385             {
00386                 throw ParseException("Out of range");
00387             }
00388             index += pos;
00389             rpn.push(new RPNTokens::NumericToken(val));
00390             pos = index;
00391             lastTokenWasOperator = false;
00392             continue;
00393         }
00394         if (isalpha(currentChar))
00395         {
00396             // parse variable or function names
00397             const size_t found = expression.find_first_not_of("abcdefghijklmnopqrstuvwxyz0123456789_", pos);
00398             std::string subString;
00399             if (found != std::string::npos)
00400             {
00401                 subString = expression.substr(pos, found - pos);
00402                 // if next character is '(' we found a function name, otherwise we treat it as variable name
00403                 // all white space have been filtered out before
00404                 if (expression[found] == '(')
00405                 {
00406                     const auto foundFunction = supportedFunctions.find(subString);
00407                     if (foundFunction == supportedFunctions.end())
00408                     {
00409                         throw ParseException("Unknown function");
00410                     };
00411                     operatorStack.push(foundFunction->second);
00412                     operatorStack.push(parenthesesOperator);
00413                     pos = found + 1;
00414                     lastTokenWasOperator = true;
00415                     continue;
00416                 };
00417             }
00418             else
00419             {
00420                 // no further character in string, it can only be a variable name
00421                 subString = expression.substr(pos);
00422             };
00423             const auto foundVar = constants.find(subString);
00424             if (foundVar == constants.end())
00425             {
00426                 const std::string s = "Unknown variable: " + subString;
00427                 throw ParseException(s.c_str());
00428             };
00429             rpn.push(new RPNTokens::NumericToken(foundVar->second));
00430             pos = found;
00431             lastTokenWasOperator = false;
00432             continue;
00433         };
00434         if (currentChar == '(')
00435         {
00436             // parse left parenthesis
00437             operatorStack.push(parenthesesOperator);
00438             pos++;
00439             lastTokenWasOperator = true;
00440             continue;
00441         };
00442         if (currentChar == ')')
00443         {
00444             // closing parenthesis
00445             bool matchingParenthesis = false;
00446             while (!operatorStack.empty())
00447             {
00448                 const int topPrecedenece = operatorStack.top()->GetPrecedence();
00449                 if (topPrecedenece == -2)
00450                 {
00451                     throw ParseException("Function without matching parenthesis");
00452                 }
00453                 if (topPrecedenece == -1)
00454                 {
00455                     // we found a matching parenthesis
00456                     matchingParenthesis = true;
00457                     operatorStack.pop();
00458                     break;
00459                 }
00460                 rpn.push(operatorStack.top()->GetTokenBase());
00461                 operatorStack.pop();
00462             }
00463             if (!matchingParenthesis)
00464             {
00465                 throw ParseException("Mismatched parentheses");
00466             };
00467             if (!operatorStack.empty() && operatorStack.top()->GetPrecedence() == -2)
00468             {
00469                 // we found a function on the operator stack
00470                 rpn.push(operatorStack.top()->GetTokenBase());
00471                 operatorStack.pop();
00472             };
00473             pos++;
00474             lastTokenWasOperator = false;
00475             continue;
00476         };
00477         if (currentChar == '?')
00478         {
00479             // we found an start of an ?: expression
00480             while (!operatorStack.empty() && operatorStack.top()->GetPrecedence() > 1)
00481             {
00482                 rpn.push(operatorStack.top()->GetTokenBase());
00483                 operatorStack.pop();
00484             };
00485             operatorStack.push(ifOperator);
00486             pos++;
00487             lastTokenWasOperator = true;
00488             continue;
00489         }
00490         if (currentChar == ':')
00491         {
00492             bool matchingIf = false;
00493             while (!operatorStack.empty())
00494             {
00495                 if (operatorStack.top()->GetPrecedence() == 1)
00496                 {
00497                     matchingIf = true;
00498                     operatorStack.pop();
00499                     break;
00500                 };
00501                 rpn.push(operatorStack.top()->GetTokenBase());
00502                 operatorStack.pop();
00503             }
00504             if (!matchingIf)
00505             {
00506                 throw ParseException("Mismatched ternary operator ?:");
00507             };
00508             operatorStack.push(ifOperatorClose);
00509             pos++;
00510             lastTokenWasOperator = true;
00511             continue;
00512         };
00513         // and finally the operators
00514         const std::string foundOperatorString = FindOperator(expression.substr(pos));
00515         if (foundOperatorString.empty())
00516         {
00517             throw ParseException("Invalid operator or unknown character");
00518         }
00519         Operators::OperatorBase* foundOperator = supportedBinaryOperations[foundOperatorString];
00520         while (!operatorStack.empty() && foundOperator->ComparePrecedence(operatorStack.top()))
00521         {
00522             rpn.push(operatorStack.top()->GetTokenBase());
00523             operatorStack.pop();
00524         };
00525         operatorStack.push(foundOperator);
00526         pos += foundOperatorString.length();
00527         lastTokenWasOperator = true;
00528     };
00529     while (!operatorStack.empty())
00530     {
00531         switch (operatorStack.top()->GetPrecedence())
00532         {
00533             case -2:
00534                 throw ParseException("Function with unbalanced parenthenses");
00535                 break;
00536             case -1:
00537                 throw ParseException("Unbalanced left and right parenthenses");
00538                 break;
00539             case 1:
00540                 throw ParseException("If without else");
00541                 break;
00542         }
00543         rpn.push(operatorStack.top()->GetTokenBase());
00544         operatorStack.pop();
00545     };
00546     return true;
00547 };
00548 
00551 bool EvaluateRPN(std::queue<RPNTokens::TokenBase*>& input, double& result)
00552 {
00553     std::stack<double> stack;
00554     try
00555     {
00556         while (!input.empty())
00557         {
00558             RPNTokens::TokenBase* token = input.front();
00559             token->evaluate(stack);
00560             delete token;
00561             input.pop();
00562         }
00563     }
00564     catch (ParseException)
00565     {
00566         ClearQueue(input);
00567         return false;
00568     };
00569     ClearQueue(input);
00570     if (stack.size() == 1)
00571     {
00572         result = stack.top();
00573         return true;
00574     }
00575     return false;
00576 };
00577 }
00578 
00580 bool ParseExpression(const std::string& expression, double& result, const ConstantMap& constants, std::string& error)
00581 {
00582     std::queue<ShuntingYard::RPNTokens::TokenBase*> rpn;
00583     try
00584     {
00585         // remove all white spaces
00586         const std::string inputExpression = ShuntingYard::RemoveWhiteSpaces(expression);
00587         if (inputExpression.empty())
00588         {
00589             // if expression is now empty, return false
00590             return false;
00591         };
00592         ConstantMap inputConstants;
00593         // convert constant names to lower case
00594         for (auto& c : constants)
00595         {
00596             inputConstants[hugin_utils::tolower(c.first)] = c.second;
00597         }
00598         // add pi
00599         inputConstants["pi"] = M_PI;
00600         // convert expression to reverse polish notation rpn
00601         if (ShuntingYard::ConvertToRPN(inputExpression, inputConstants, rpn))
00602         {
00603             // if successful, evaluate queue
00604             return ShuntingYard::EvaluateRPN(rpn, result);
00605         }
00606         else
00607         {
00608             // could not convert to RPN
00609             ShuntingYard::ClearQueue(rpn);
00610             return false;
00611         };
00612     }
00613     catch (ShuntingYard::ParseException& exception)
00614     {
00615         //something went wrong, delete queue and return false
00616         ShuntingYard::ClearQueue(rpn);
00617         error = std::string(exception.what());
00618         return false;
00619     };
00620 };
00621 
00622 ParseVar::ParseVar() : varname(""), imgNr(-1), expression(""), flag(false)
00623 {
00624 };
00625 
00626 bool ParseVarNumber(const std::string&s, Parser::ParseVar& var)
00627 {
00628     std::size_t pos = s.find_first_of("0123456789");
00629     if (pos == std::string::npos)
00630     {
00631         var.varname = s;
00632         var.imgNr = -1;
00633     }
00634     else
00635     {
00636         if (pos == 0)
00637         {
00638             return false;
00639         };
00640         var.varname = s.substr(0, pos);
00641         if (!hugin_utils::stringToInt(s.substr(pos, s.length() - pos), var.imgNr))
00642         {
00643             return false;
00644         };
00645     }
00646 #define image_variable( name, type, default_value ) \
00647     if (HuginBase::PTOVariableConverterFor##name::checkApplicability(var.varname))\
00648     {\
00649         return true;\
00650     };
00651 #include "panodata/image_variables.h"
00652 #undef image_variable
00653     return false;
00654 };
00655 
00656 // parse the given input if it matches a valid expression
00657 void ParseSingleVar(ParseVarVec& varVec, const std::string& s, std::ostream& errorStream)
00658 {
00659     // parse following regex ([a-zA-Z]{1,3})(\\d*?)=(.*)
00660     const std::size_t pos = s.find_first_of("=", 0);
00661     if (pos != std::string::npos && pos > 0 && pos < s.length() - 1)
00662     {
00663         ParseVar var;
00664         var.expression = hugin_utils::StrTrim(s.substr(pos + 1, s.length() - pos - 1));
00665         if (var.expression.empty())
00666         {
00667             errorStream << "The expression \"" << s << "\" does not contain a result." << std::endl;
00668         }
00669         else
00670         {
00671             const std::string tempString(s.substr(0, pos));
00672             if (ParseVarNumber(tempString, var))
00673             {
00674                 varVec.push_back(var);
00675             }
00676             else
00677             {
00678                 // no image variable from pto syntax
00679                 if (tempString.find_first_of("0123456789") == std::string::npos)
00680                 {
00681                     // constants should not contain digits
00682                     var.flag = true;
00683                     varVec.push_back(var);
00684                 }
00685                 else
00686                 {
00687                     errorStream << "The expression \"" << tempString << "\" is not a valid image variable or constant." << std::endl;
00688                 };
00689             };
00690         };
00691     }
00692     else
00693     {
00694         errorStream << "The expression \"" << s << "\" is incomplete." << std::endl;
00695     };
00696 };
00697 
00698 //parse complete variables string
00699 void ParseVariableString(ParseVarVec& parseVec, const std::string& input, std::ostream& errorStream, void(*func)(ParseVarVec&, const std::string&, std::ostream&))
00700 {
00701     // split at ","
00702     std::vector<std::string> splitResult = hugin_utils::SplitString(input, ",");
00703     for (auto& s : splitResult)
00704     {
00705         (*func)(parseVec, s, errorStream);
00706     };
00707 };
00708 
00709 bool UpdateSingleVar(HuginBase::Panorama& pano, const Parser::ParseVar& parseVar, const Parser::ConstantMap& constants, size_t imgNr, std::ostream& statusStream, std::ostream& errorStream)
00710 {
00711     const HuginBase::SrcPanoImage& srcImg = pano.getImage(imgNr);
00712     double val = srcImg.getVar(parseVar.varname);
00713     Parser::ConstantMap constMap(constants);
00714     constMap["i"] = 1.0*imgNr;
00715     constMap["val"] = val;
00716     constMap["hfov"] = srcImg.getHFOV();
00717     constMap["width"] = srcImg.getWidth();
00718     constMap["height"] = srcImg.getHeight();
00719     statusStream << "Updating variable " << parseVar.varname << imgNr << ": " << val;
00720     std::string error;
00721     if (Parser::ParseExpression(parseVar.expression, val, constMap, error))
00722     {
00723         statusStream << " -> " << val << std::endl;
00724         HuginBase::Variable var(parseVar.varname, val);
00725         pano.updateVariable(imgNr, var);
00726         return true;
00727     }
00728     else
00729     {
00730         statusStream << std::endl;
00731         errorStream << "Could not parse given expression \"" << parseVar.expression << "\" for variable " << parseVar.varname << " on image " << imgNr << "." << std::endl;
00732         if (!error.empty())
00733         {
00734             errorStream << "(Error: " << error << ")" << std::endl;
00735         };
00736         return false;
00737     };
00738 };
00739 
00740 bool CalculateConstant(HuginBase::Panorama& pano, const Parser::ParseVar& parseVar, Parser::ConstantMap& constants, std::ostream& statusStream, std::ostream& errorStream)
00741 {
00742     const HuginBase::SrcPanoImage& srcImg = pano.getImage(0);
00743     double val = 0;
00744     Parser::ConstantMap constMap(constants);
00745     constMap["hfov"] = srcImg.getHFOV();
00746     constMap["width"] = srcImg.getWidth();
00747     constMap["height"] = srcImg.getHeight();
00748     statusStream << "Calculating constant " << parseVar.varname << " = ";
00749     std::string error;
00750     if (Parser::ParseExpression(parseVar.expression, val, constMap, error))
00751     {
00752         statusStream << val << std::endl;
00753         constants[parseVar.varname] = val;
00754         return true;
00755     }
00756     else
00757     {
00758         statusStream << std::endl;
00759         errorStream << "Could not parse given expression \"" << parseVar.expression << "\" for constant " << parseVar.varname << "." << std::endl;
00760         if (!error.empty())
00761         {
00762             errorStream << "(Error: " << error << ")" << std::endl;
00763         };
00764         return false;
00765     };
00766 };
00767 
00768 void PanoParseExpression(HuginBase::Panorama& pano, const std::string& expression, std::ostream& statusStream, std::ostream& errorStream)
00769 {
00770     ParseVarVec setVars;
00771     // set locale to C to correctly parse decimal numbers
00772     char * old_locale = strdup(setlocale(LC_NUMERIC, NULL));
00773     setlocale(LC_NUMERIC, "C");
00774     // filter out comments
00775     std::vector<std::string> lines = hugin_utils::SplitString(expression, "\n");
00776     std::string filteredExpression;
00777     filteredExpression.reserve(expression.length());
00778     for(auto& l:lines)
00779     { 
00780         const std::string l0 = hugin_utils::StrTrim(l);
00781         if (!l0.empty() && l0[0] != '#')
00782         {
00783             filteredExpression.append(l).append(",");
00784         };
00785     };
00786     ParseVariableString(setVars, filteredExpression, errorStream, ParseSingleVar);
00787     if (!setVars.empty())
00788     {
00789         Parser::ConstantMap constants;
00790         constants["imax"] = pano.getNrOfImages() - 1;
00791         for (auto& var:setVars)
00792         {
00793             if (!var.flag)
00794             {
00795                 // update image variable
00796                 //skip invalid image numbers
00797                 if (var.imgNr >= (int)pano.getNrOfImages())
00798                 {
00799                     continue;
00800                 };
00801                 if (var.imgNr < 0)
00802                 {
00803                     // no img number given, apply to all images
00804                     HuginBase::UIntSet updatedImgs;
00805                     for (size_t j = 0; j < pano.getNrOfImages(); j++)
00806                     {
00807                         //if we already update the variable in this image via links, skip it
00808                         if (set_contains(updatedImgs, j))
00809                         {
00810                             continue;
00811                         };
00812                         // skip following images, if expression could not parsed
00813                         if (!UpdateSingleVar(pano, var, constants, j, statusStream, errorStream))
00814                         {
00815                             break;
00816                         };
00817                         updatedImgs.insert(j);
00818                         if (j == pano.getNrOfImages() - 1)
00819                         {
00820                             break;
00821                         };
00822                         // now remember linked variables
00823                         const HuginBase::SrcPanoImage& img1 = pano.getImage(j);
00824 #define image_variable( name, type, default_value ) \
00825     if (HuginBase::PTOVariableConverterFor##name::checkApplicability(var.varname))\
00826     {\
00827         if(img1.name##isLinked())\
00828         {\
00829             for(size_t k=j+1; k<pano.getNrOfImages(); k++)\
00830             {\
00831                 if(img1.name##isLinkedWith(pano.getImage(k)))\
00832                 {\
00833                     updatedImgs.insert(k);\
00834                 }\
00835             };\
00836         };\
00837     };
00838 #include "panodata/image_variables.h"
00839 #undef image_variable
00840                     };
00841                 }
00842                 else
00843                 {
00844                     UpdateSingleVar(pano, var, constants, var.imgNr, statusStream, errorStream);
00845                 };
00846             }
00847             else
00848             {
00849                 // handle constants
00850                 CalculateConstant(pano, var, constants, statusStream, errorStream);
00851             }
00852         };
00853     }
00854     else
00855     {
00856         errorStream << "Expression is empty." << std::endl;
00857     };
00858     ShuntingYard::CleanUpParser();
00859     //reset locale
00860     setlocale(LC_NUMERIC, old_locale);
00861     free(old_locale);
00862 };
00863 
00864 } //namespace Parser

Generated on 21 Feb 2018 for Hugintrunk by  doxygen 1.4.7