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

Generated on 21 Nov 2017 for Hugintrunk by  doxygen 1.4.7