Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ParseExp.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
11 /* This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This software is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public
22  * License along with this software. If not, see
23  * <http://www.gnu.org/licenses/>.
24  *
25  */
26 
27 // parser using shunting yard algorithm using C++11 features
28 #include <exception>
29 #include <stack>
30 #include <queue>
31 #include <map>
32 #include <functional>
33 #define _USE_MATH_DEFINES
34 #include <cmath>
35 #include "ParseExp.h"
36 #include "hugin_utils/utils.h"
37 
39 
40 namespace Parser
41 {
42 
43 typedef std::map<std::string, double> ConstantMap;
44 
45 namespace ShuntingYard
46 {
48 class ParseException : public std::runtime_error
49 {
50 public:
51  explicit ParseException(const char *message) : std::runtime_error(message) {};
52 };
53 
55 namespace RPNTokens
56 {
58 class TokenBase
59 {
60 public:
61  virtual void evaluate(std::stack<double>&) = 0;
62  virtual ~TokenBase() {};
63 };
64 
66 class NumericToken :public TokenBase
67 {
68 public:
69  explicit NumericToken(double val) : m_value(val) {};
70  void evaluate(std::stack<double>& rpnStack) { rpnStack.push(m_value); };
71 private:
72  double m_value;
73 };
74 
76 class FunctionToken : public TokenBase
77 {
78 public:
79  explicit FunctionToken(std::function<double(double)> func) : TokenBase(), m_function(func) {};
80  void evaluate(std::stack<double>& rpnStack)
81  {
82  if (rpnStack.empty())
83  {
84  throw ParseException("Unary operator expects one item on stack.");
85  }
86  const double val = rpnStack.top();
87  rpnStack.pop();
88  const double newVal = m_function(val);
89  if (!std::isinf(newVal) && !std::isnan(newVal))
90  {
91  rpnStack.push(newVal);
92  }
93  else
94  {
95  throw ParseException("Invalid operation");
96  };
97  };
98 private:
99  std::function<double(double)> m_function;
100 };
101 
103 class BinaryToken : public TokenBase
104 {
105 public:
106  explicit BinaryToken(std::function<double(double, double)> func) : TokenBase(), m_function(func) {};
107  void evaluate(std::stack<double>& rpnStack)
108  {
109  if (rpnStack.size() < 2)
110  {
111  throw ParseException("BinaryOperator expects 2 items on stack.");
112  };
113  const double right = rpnStack.top();
114  rpnStack.pop();
115  const double left = rpnStack.top();
116  rpnStack.pop();
117  const double newVal = m_function(left, right);
118  if (!std::isinf(newVal) && !std::isnan(newVal))
119  {
120  rpnStack.push(newVal);
121  }
122  else
123  {
124  throw ParseException("Invalid operation");
125  };
126  };
127 private:
128  std::function<double(double, double)> m_function;
129 };
130 
132 class IfToken : public TokenBase
133 {
134 public:
135  void evaluate(std::stack<double>& rpnStack)
136  {
137  if (rpnStack.size() < 3)
138  {
139  throw ParseException("IfOperator expects 3 items on stack.");
140  };
141  const double elseVal = rpnStack.top();
142  rpnStack.pop();
143  const double ifVal = rpnStack.top();
144  rpnStack.pop();
145  const double compareVal = rpnStack.top();
146  rpnStack.pop();
147  if (fabs(compareVal) > 1e-8)
148  {
149  rpnStack.push(ifVal);
150  }
151  else
152  {
153  rpnStack.push(elseVal);
154  };
155  };
156 };
157 } // namespace RPNTokens
158 
160 namespace Operators
161 {
164 {
165 public:
166  OperatorBase(int prec, bool rightAssoc = false) : m_precedence(prec), m_rightAssoc(rightAssoc) {};
167  virtual ~OperatorBase() {};
168  const int GetPrecedence() const { return m_precedence; };
169  const bool IsRightAssociative() const { return m_rightAssoc; };
170  bool ComparePrecedence(const OperatorBase* other)
171  {
172  if (IsRightAssociative())
173  {
174  return GetPrecedence() < other->GetPrecedence();
175  }
176  else
177  {
178  return GetPrecedence() <= other->GetPrecedence();
179  };
180  };
181  virtual RPNTokens::TokenBase* GetTokenBase() { return nullptr; };
182 private:
183  int m_precedence;
185 };
186 
189 {
190 public:
191  FunctionOperator(std::function<double(double)> func, int prec = -2, bool rightAssoc = false) : OperatorBase(prec, rightAssoc), m_function(func) {};
193 private:
194  std::function<double(double)> m_function;
195 };
196 
199 {
200 public:
201  BinaryOperator(std::function<double(double, double)> func, int prec, bool rightAssoc = false) : OperatorBase(prec, rightAssoc), m_function(func) {};
203 private:
204  std::function<double(double, double)> m_function;
205 };
206 
208 class IfOperator : public OperatorBase
209 {
210 public:
211  IfOperator() : OperatorBase(0, true) {};
213 };
214 }; // namespace Operators
215 
217 void ClearQueue(std::queue<RPNTokens::TokenBase*>& input)
218 {
219  while (!input.empty())
220  {
221  delete input.front();
222  input.pop();
223  }
224 }
225 
227 std::string RemoveWhiteSpaces(const std::string& text)
228 {
229  std::string output;
230  output.reserve(text.size());
231  for (auto c : text)
232  {
233  if (!isspace(c))
234  {
235  output.push_back(tolower(c));
236  };
237  };
238  return output;
239 };
240 
241 static std::map<std::string, Operators::OperatorBase*> supportedBinaryOperations;
245 static std::map<std::string, Operators::FunctionOperator*> supportedFunctions;
246 
249 {
250  if (supportedBinaryOperations.empty())
251  {
252  supportedBinaryOperations["||"] = new Operators::BinaryOperator(std::logical_or<double>(), 2);
253  supportedBinaryOperations["&&"] = new Operators::BinaryOperator(std::logical_and<double>(), 3);
254  supportedBinaryOperations["=="] = new Operators::BinaryOperator(std::equal_to<double>(), 4);
255  supportedBinaryOperations["!="] = new Operators::BinaryOperator(std::not_equal_to<double>(), 4);
256  supportedBinaryOperations["<"] = new Operators::BinaryOperator(std::less<double>(), 5);
257  supportedBinaryOperations["<="] = new Operators::BinaryOperator(std::less_equal<double>(), 5);
258  supportedBinaryOperations[">"] = new Operators::BinaryOperator(std::greater<double>(), 5);
259  supportedBinaryOperations[">="] = new Operators::BinaryOperator(std::greater_equal<double>(), 5);
260  supportedBinaryOperations["+"] = new Operators::BinaryOperator(std::plus<double>(), 6);
261  supportedBinaryOperations["-"] = new Operators::BinaryOperator(std::minus<double>(), 6);
262  supportedBinaryOperations["*"] = new Operators::BinaryOperator(std::multiplies<double>(), 7);
263  supportedBinaryOperations["/"] = new Operators::BinaryOperator(std::divides<double>(), 7);
264  supportedBinaryOperations["%"] = new Operators::BinaryOperator((double(*)(double, double))fmod, 7);
265  supportedBinaryOperations["^"] = new Operators::BinaryOperator((double(*)(double, double))pow, 8, true);
266  supportedBinaryOperations["UNARY_MINUS"] = new Operators::FunctionOperator([](double val)->double {return -1 * val; }, 9, true);
267  }
268  if (!parenthesesOperator)
269  {
271  };
272  if (!ifOperator)
273  {
275  }
276  if (!ifOperatorClose)
277  {
279  }
280  if (supportedFunctions.empty())
281  {
282  supportedFunctions["abs"] = new Operators::FunctionOperator((double(*)(double))abs);
283  supportedFunctions["sin"] = new Operators::FunctionOperator((double(*)(double))sin);
284  supportedFunctions["cos"] = new Operators::FunctionOperator((double(*)(double))cos);
285  supportedFunctions["tan"] = new Operators::FunctionOperator((double(*)(double))tan);
286  supportedFunctions["asin"] = new Operators::FunctionOperator((double(*)(double))asin);
287  supportedFunctions["acos"] = new Operators::FunctionOperator((double(*)(double))acos);
288  supportedFunctions["atan"] = new Operators::FunctionOperator((double(*)(double))atan);
289  supportedFunctions["exp"] = new Operators::FunctionOperator((double(*)(double))exp);
290  supportedFunctions["log"] = new Operators::FunctionOperator((double(*)(double))log);
291  supportedFunctions["ceil"] = new Operators::FunctionOperator((double(*)(double))ceil);
292  supportedFunctions["floor"] = new Operators::FunctionOperator((double(*)(double))floor);
293  supportedFunctions["sqrt"] = new Operators::FunctionOperator((double(*)(double))sqrt);
294  supportedFunctions["deg"] = new Operators::FunctionOperator([](double val)->double { return val * 180.0f / M_PI; });
295  supportedFunctions["rad"] = new Operators::FunctionOperator([](double val)->double { return val * M_PI / 180.0f; });
296  }
297 };
298 
301 {
302  for (auto it : supportedBinaryOperations)
303  {
304  delete it.second;
305  };
306  supportedBinaryOperations.clear();
307  for (auto it : supportedFunctions)
308  {
309  delete it.second;
310  };
311  supportedFunctions.clear();
313  {
314  delete parenthesesOperator;
315  parenthesesOperator = nullptr;
316  };
317  if (ifOperator)
318  {
319  delete ifOperator;
320  ifOperator = nullptr;
321  };
322  if (ifOperatorClose)
323  {
324  delete ifOperatorClose;
325  ifOperatorClose = nullptr;
326  };
327 };
328 
330 std::string FindOperator(const std::string& searchString)
331 {
332  std::string foundOperator;
333  for (auto it : supportedBinaryOperations)
334  {
335  const std::string op(it.first);
336  if (searchString.compare(0, op.length(), op) == 0)
337  {
338  if (op.length() > foundOperator.length())
339  {
340  foundOperator = op;
341  }
342  };
343  };
344  return foundOperator;
345 };
346 
349 bool ConvertToRPN(const std::string& expression, const ConstantMap& constants, std::queue<RPNTokens::TokenBase*>& rpn)
350 {
351  // initialize some internal variables, don't forget to call CleanUpParser() at the end
352  InitParser();
353  size_t pos = 0;
354  std::stack<Operators::OperatorBase*> operatorStack;
355  bool lastTokenWasOperator = true;
356  const size_t expressionLength = expression.length();
357  while (pos < expressionLength)
358  {
359  const char currentChar = expression[pos];
360  if (lastTokenWasOperator && (currentChar == '+' || currentChar == '-'))
361  {
362  // special handling of +/- prefix
363  if (currentChar == '-')
364  {
365  operatorStack.push(supportedBinaryOperations["UNARY_MINUS"]);
366  };
367  pos++;
368  lastTokenWasOperator = false;
369  continue;
370  }
371  if (isdigit(currentChar) || currentChar == '.')
372  {
373  // parse numbers
374  size_t index;
375  double val;
376  try
377  {
378  val = std::stod(expression.substr(pos), &index);
379  }
380  catch (std::invalid_argument)
381  {
382  throw ParseException("Invalid number");
383  }
384  catch (std::out_of_range)
385  {
386  throw ParseException("Out of range");
387  }
388  index += pos;
389  rpn.push(new RPNTokens::NumericToken(val));
390  pos = index;
391  lastTokenWasOperator = false;
392  continue;
393  }
394  if (isalpha(currentChar))
395  {
396  // parse variable or function names
397  const size_t found = expression.find_first_not_of("abcdefghijklmnopqrstuvwxyz0123456789_", pos);
398  std::string subString;
399  if (found != std::string::npos)
400  {
401  subString = expression.substr(pos, found - pos);
402  // if next character is '(' we found a function name, otherwise we treat it as variable name
403  // all white space have been filtered out before
404  if (expression[found] == '(')
405  {
406  const auto foundFunction = supportedFunctions.find(subString);
407  if (foundFunction == supportedFunctions.end())
408  {
409  throw ParseException("Unknown function");
410  };
411  operatorStack.push(foundFunction->second);
412  operatorStack.push(parenthesesOperator);
413  pos = found + 1;
414  lastTokenWasOperator = true;
415  continue;
416  };
417  }
418  else
419  {
420  // no further character in string, it can only be a variable name
421  subString = expression.substr(pos);
422  };
423  const auto foundVar = constants.find(subString);
424  if (foundVar == constants.end())
425  {
426  const std::string s = "Unknown variable: " + subString;
427  throw ParseException(s.c_str());
428  };
429  rpn.push(new RPNTokens::NumericToken(foundVar->second));
430  pos = found;
431  lastTokenWasOperator = false;
432  continue;
433  };
434  if (currentChar == '(')
435  {
436  // parse left parenthesis
437  operatorStack.push(parenthesesOperator);
438  pos++;
439  lastTokenWasOperator = true;
440  continue;
441  };
442  if (currentChar == ')')
443  {
444  // closing parenthesis
445  bool matchingParenthesis = false;
446  while (!operatorStack.empty())
447  {
448  const int topPrecedenece = operatorStack.top()->GetPrecedence();
449  if (topPrecedenece == -2)
450  {
451  throw ParseException("Function without matching parenthesis");
452  }
453  if (topPrecedenece == -1)
454  {
455  // we found a matching parenthesis
456  matchingParenthesis = true;
457  operatorStack.pop();
458  break;
459  }
460  rpn.push(operatorStack.top()->GetTokenBase());
461  operatorStack.pop();
462  }
463  if (!matchingParenthesis)
464  {
465  throw ParseException("Mismatched parentheses");
466  };
467  if (!operatorStack.empty() && operatorStack.top()->GetPrecedence() == -2)
468  {
469  // we found a function on the operator stack
470  rpn.push(operatorStack.top()->GetTokenBase());
471  operatorStack.pop();
472  };
473  pos++;
474  lastTokenWasOperator = false;
475  continue;
476  };
477  if (currentChar == '?')
478  {
479  // we found an start of an ?: expression
480  while (!operatorStack.empty() && operatorStack.top()->GetPrecedence() > 1)
481  {
482  rpn.push(operatorStack.top()->GetTokenBase());
483  operatorStack.pop();
484  };
485  operatorStack.push(ifOperator);
486  pos++;
487  lastTokenWasOperator = true;
488  continue;
489  }
490  if (currentChar == ':')
491  {
492  bool matchingIf = false;
493  while (!operatorStack.empty())
494  {
495  if (operatorStack.top()->GetPrecedence() == 1)
496  {
497  matchingIf = true;
498  operatorStack.pop();
499  break;
500  };
501  rpn.push(operatorStack.top()->GetTokenBase());
502  operatorStack.pop();
503  }
504  if (!matchingIf)
505  {
506  throw ParseException("Mismatched ternary operator ?:");
507  };
508  operatorStack.push(ifOperatorClose);
509  pos++;
510  lastTokenWasOperator = true;
511  continue;
512  };
513  // and finally the operators
514  const std::string foundOperatorString = FindOperator(expression.substr(pos));
515  if (foundOperatorString.empty())
516  {
517  throw ParseException("Invalid operator or unknown character");
518  }
519  Operators::OperatorBase* foundOperator = supportedBinaryOperations[foundOperatorString];
520  while (!operatorStack.empty() && foundOperator->ComparePrecedence(operatorStack.top()))
521  {
522  rpn.push(operatorStack.top()->GetTokenBase());
523  operatorStack.pop();
524  };
525  operatorStack.push(foundOperator);
526  pos += foundOperatorString.length();
527  lastTokenWasOperator = true;
528  };
529  while (!operatorStack.empty())
530  {
531  switch (operatorStack.top()->GetPrecedence())
532  {
533  case -2:
534  throw ParseException("Function with unbalanced parenthenses");
535  break;
536  case -1:
537  throw ParseException("Unbalanced left and right parenthenses");
538  break;
539  case 1:
540  throw ParseException("If without else");
541  break;
542  }
543  rpn.push(operatorStack.top()->GetTokenBase());
544  operatorStack.pop();
545  };
546  return true;
547 };
548 
551 bool EvaluateRPN(std::queue<RPNTokens::TokenBase*>& input, double& result)
552 {
553  std::stack<double> stack;
554  try
555  {
556  while (!input.empty())
557  {
558  RPNTokens::TokenBase* token = input.front();
559  token->evaluate(stack);
560  delete token;
561  input.pop();
562  }
563  }
564  catch (ParseException)
565  {
566  ClearQueue(input);
567  return false;
568  };
569  ClearQueue(input);
570  if (stack.size() == 1)
571  {
572  result = stack.top();
573  return true;
574  }
575  return false;
576 };
577 }
578 
580 bool ParseExpression(const std::string& expression, double& result, const ConstantMap& constants, std::string& error)
581 {
582  std::queue<ShuntingYard::RPNTokens::TokenBase*> rpn;
583  try
584  {
585  // remove all white spaces
586  const std::string inputExpression = ShuntingYard::RemoveWhiteSpaces(expression);
587  if (inputExpression.empty())
588  {
589  // if expression is now empty, return false
590  return false;
591  };
592  ConstantMap inputConstants;
593  // convert constant names to lower case
594  for (auto& c : constants)
595  {
596  inputConstants[hugin_utils::tolower(c.first)] = c.second;
597  }
598  // add pi
599  inputConstants["pi"] = M_PI;
600  // convert expression to reverse polish notation rpn
601  if (ShuntingYard::ConvertToRPN(inputExpression, inputConstants, rpn))
602  {
603  // if successful, evaluate queue
604  return ShuntingYard::EvaluateRPN(rpn, result);
605  }
606  else
607  {
608  // could not convert to RPN
610  return false;
611  };
612  }
613  catch (ShuntingYard::ParseException& exception)
614  {
615  //something went wrong, delete queue and return false
617  error = std::string(exception.what());
618  return false;
619  };
620 };
621 
622 ParseVar::ParseVar() : varname(""), imgNr(-1), expression(""), flag(false)
623 {
624 };
625 
626 bool ParseVarNumber(const std::string&s, Parser::ParseVar& var)
627 {
628  std::size_t pos = s.find_first_of("0123456789");
629  if (pos == std::string::npos)
630  {
631  var.varname = s;
632  var.imgNr = -1;
633  }
634  else
635  {
636  if (pos == 0)
637  {
638  return false;
639  };
640  var.varname = s.substr(0, pos);
641  if (!hugin_utils::stringToInt(s.substr(pos, s.length() - pos), var.imgNr))
642  {
643  return false;
644  };
645  }
646 #define image_variable( name, type, default_value ) \
647  if (HuginBase::PTOVariableConverterFor##name::checkApplicability(var.varname))\
648  {\
649  return true;\
650  };
652 #undef image_variable
653  return false;
654 };
655 
656 // parse the given input if it matches a valid expression
657 void ParseSingleVar(ParseVarVec& varVec, const std::string& s, std::ostream& errorStream)
658 {
659  // parse following regex ([a-zA-Z]{1,3})(\\d*?)=(.*)
660  const std::size_t pos = s.find_first_of("=", 0);
661  if (pos != std::string::npos && pos > 0 && pos < s.length() - 1)
662  {
663  ParseVar var;
664  var.expression = hugin_utils::StrTrim(s.substr(pos + 1, s.length() - pos - 1));
665  if (var.expression.empty())
666  {
667  errorStream << "The expression \"" << s << "\" does not contain a result." << std::endl;
668  }
669  else
670  {
671  const std::string tempString(s.substr(0, pos));
672  if (ParseVarNumber(tempString, var))
673  {
674  varVec.push_back(var);
675  }
676  else
677  {
678  // no image variable from pto syntax
679  if (tempString.find_first_of("0123456789") == std::string::npos)
680  {
681  // constants should not contain digits
682  var.flag = true;
683  varVec.push_back(var);
684  }
685  else
686  {
687  errorStream << "The expression \"" << tempString << "\" is not a valid image variable or constant." << std::endl;
688  };
689  };
690  };
691  }
692  else
693  {
694  errorStream << "The expression \"" << s << "\" is incomplete." << std::endl;
695  };
696 };
697 
698 //parse complete variables string
699 void ParseVariableString(ParseVarVec& parseVec, const std::string& input, std::ostream& errorStream, void(*func)(ParseVarVec&, const std::string&, std::ostream&))
700 {
701  // split at ","
702  std::vector<std::string> splitResult = hugin_utils::SplitString(input, ",");
703  for (auto& s : splitResult)
704  {
705  (*func)(parseVec, s, errorStream);
706  };
707 };
708 
709 bool UpdateSingleVar(HuginBase::Panorama& pano, const Parser::ParseVar& parseVar, const Parser::ConstantMap& constants, size_t imgNr, std::ostream& statusStream, std::ostream& errorStream)
710 {
711  const HuginBase::SrcPanoImage& srcImg = pano.getImage(imgNr);
712  double val = srcImg.getVar(parseVar.varname);
713  Parser::ConstantMap constMap(constants);
714  constMap["i"] = 1.0*imgNr;
715  constMap["val"] = val;
716  constMap["hfov"] = srcImg.getHFOV();
717  constMap["width"] = srcImg.getWidth();
718  constMap["height"] = srcImg.getHeight();
719  statusStream << "Updating variable " << parseVar.varname << imgNr << ": " << val;
720  std::string error;
721  if (Parser::ParseExpression(parseVar.expression, val, constMap, error))
722  {
723  statusStream << " -> " << val << std::endl;
724  HuginBase::Variable var(parseVar.varname, val);
725  pano.updateVariable(imgNr, var);
726  return true;
727  }
728  else
729  {
730  statusStream << std::endl;
731  errorStream << "Could not parse given expression \"" << parseVar.expression << "\" for variable " << parseVar.varname << " on image " << imgNr << "." << std::endl;
732  if (!error.empty())
733  {
734  errorStream << "(Error: " << error << ")" << std::endl;
735  };
736  return false;
737  };
738 };
739 
740 bool CalculateConstant(HuginBase::Panorama& pano, const Parser::ParseVar& parseVar, Parser::ConstantMap& constants, std::ostream& statusStream, std::ostream& errorStream)
741 {
742  const HuginBase::SrcPanoImage& srcImg = pano.getImage(0);
743  double val = 0;
744  Parser::ConstantMap constMap(constants);
745  constMap["hfov"] = srcImg.getHFOV();
746  constMap["width"] = srcImg.getWidth();
747  constMap["height"] = srcImg.getHeight();
748  statusStream << "Calculating constant " << parseVar.varname << " = ";
749  std::string error;
750  if (Parser::ParseExpression(parseVar.expression, val, constMap, error))
751  {
752  statusStream << val << std::endl;
753  constants[parseVar.varname] = val;
754  return true;
755  }
756  else
757  {
758  statusStream << std::endl;
759  errorStream << "Could not parse given expression \"" << parseVar.expression << "\" for constant " << parseVar.varname << "." << std::endl;
760  if (!error.empty())
761  {
762  errorStream << "(Error: " << error << ")" << std::endl;
763  };
764  return false;
765  };
766 };
767 
768 void PanoParseExpression(HuginBase::Panorama& pano, const std::string& expression, std::ostream& statusStream, std::ostream& errorStream)
769 {
770  ParseVarVec setVars;
771  // set locale to C to correctly parse decimal numbers
772  char * old_locale = strdup(setlocale(LC_NUMERIC, NULL));
773  setlocale(LC_NUMERIC, "C");
774  // filter out comments
775  std::vector<std::string> lines = hugin_utils::SplitString(expression, "\n");
776  std::string filteredExpression;
777  filteredExpression.reserve(expression.length());
778  for(auto& l:lines)
779  {
780  const std::string l0 = hugin_utils::StrTrim(l);
781  if (!l0.empty() && l0[0] != '#')
782  {
783  filteredExpression.append(l).append(",");
784  };
785  };
786  ParseVariableString(setVars, filteredExpression, errorStream, ParseSingleVar);
787  if (!setVars.empty())
788  {
789  Parser::ConstantMap constants;
790  constants["imax"] = pano.getNrOfImages() - 1;
791  for (size_t i = 0; i < pano.getNrOfImages(); ++i)
792  {
793  const HuginBase::SrcPanoImage& img = pano.getImage(i);
794  const std::string imgNr = std::to_string(i);
796 #define image_variable( name, type, default_value ) \
797  HuginBase::PTOVariableConverterFor##name::addToVariableMap(img.get##name##IV(), vars);
799 #undef image_variable
800  for (auto& var : vars)
801  {
802  constants[var.first + imgNr] = var.second.getValue();
803  }
804  }
805  for (auto& var:setVars)
806  {
807  if (!var.flag)
808  {
809  // update image variable
810  //skip invalid image numbers
811  if (var.imgNr >= (int)pano.getNrOfImages())
812  {
813  continue;
814  };
815  if (var.imgNr < 0)
816  {
817  // no img number given, apply to all images
818  HuginBase::UIntSet updatedImgs;
819  for (size_t j = 0; j < pano.getNrOfImages(); j++)
820  {
821  //if we already update the variable in this image via links, skip it
822  if (set_contains(updatedImgs, j))
823  {
824  continue;
825  };
826  // skip following images, if expression could not parsed
827  if (!UpdateSingleVar(pano, var, constants, j, statusStream, errorStream))
828  {
829  break;
830  };
831  updatedImgs.insert(j);
832  if (j == pano.getNrOfImages() - 1)
833  {
834  break;
835  };
836  // now remember linked variables
837  const HuginBase::SrcPanoImage& img1 = pano.getImage(j);
838 #define image_variable( name, type, default_value ) \
839  if (HuginBase::PTOVariableConverterFor##name::checkApplicability(var.varname))\
840  {\
841  if(img1.name##isLinked())\
842  {\
843  for(size_t k=j+1; k<pano.getNrOfImages(); k++)\
844  {\
845  if(img1.name##isLinkedWith(pano.getImage(k)))\
846  {\
847  updatedImgs.insert(k);\
848  }\
849  };\
850  };\
851  };
853 #undef image_variable
854  };
855  }
856  else
857  {
858  UpdateSingleVar(pano, var, constants, var.imgNr, statusStream, errorStream);
859  };
860  }
861  else
862  {
863  // handle constants
864  CalculateConstant(pano, var, constants, statusStream, errorStream);
865  }
866  };
867  }
868  else
869  {
870  errorStream << "Expression is empty." << std::endl;
871  };
873  //reset locale
874  setlocale(LC_NUMERIC, old_locale);
875  free(old_locale);
876 };
877 
878 } //namespace Parser
void ParseVariableString(ParseVarVec &parseVec, const std::string &input, std::ostream &errorStream, void(*func)(ParseVarVec &, const std::string &, std::ostream &))
parse complete variables string
Definition: ParseExp.cpp:699
bool ParseExpression(const std::string &expression, double &result, const ConstantMap &constants, std::string &error)
parse complete expression in 2 steps
Definition: ParseExp.cpp:580
void evaluate(std::stack< double > &rpnStack)
Definition: ParseExp.cpp:70
bool EvaluateRPN(std::queue< RPNTokens::TokenBase * > &input, double &result)
evaluate RPN in input
Definition: ParseExp.cpp:551
std::string RemoveWhiteSpaces(const std::string &text)
remove all whitespaces and convert to lowercase
Definition: ParseExp.cpp:227
void InitParser()
initialize some internal variables
Definition: ParseExp.cpp:248
std::string StrTrim(const std::string &str)
remove trailing and leading white spaces and tabs
Definition: utils.cpp:208
OperatorBase(int prec, bool rightAssoc=false)
Definition: ParseExp.cpp:166
IMPEX bool ParseVarNumber(const std::string &s, Parser::ParseVar &var)
parse string s and store result in ParseVar var
std::map< std::string, double > ConstantMap
Definition: ParseExp.cpp:43
binary operator on rpn stack
Definition: ParseExp.cpp:103
void ClearQueue(std::queue< RPNTokens::TokenBase * > &input)
clear the queue
Definition: ParseExp.cpp:217
a variable has a value and a name.
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition: stl_utils.h:74
struct to save parsed variables and optional image numbers
Definition: ParseExp.h:39
int getHeight() const
Get the height of the image in pixels.
Definition: SrcPanoImage.h:276
void evaluate(std::stack< double > &rpnStack)
Definition: ParseExp.cpp:107
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
function or unary operator on shunting yards operator stack
Definition: ParseExp.cpp:188
IMPEX void PanoParseExpression(HuginBase::Panorama &pano, const std::string &expression, std::ostream &statusStream=std::cout, std::ostream &errorStream=std::cerr)
parses the given expression and apply the changes to the Panorama
std::string expression
Definition: ParseExp.h:44
Model for a panorama.
Definition: Panorama.h:152
void CleanUpParser()
clean up some internal static variables
Definition: ParseExp.cpp:300
BinaryOperator(std::function< double(double, double)> func, int prec, bool rightAssoc=false)
Definition: ParseExp.cpp:201
base class for operator on shunting yards operator stack
Definition: ParseExp.cpp:163
std::vector< ParseVar > ParseVarVec
Definition: ParseExp.h:48
if operator on operator stack, used only for &#39;:&#39; token
Definition: ParseExp.cpp:208
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
void evaluate(std::stack< double > &rpnStack)
Definition: ParseExp.cpp:135
bool ConvertToRPN(const std::string &expression, const ConstantMap &constants, std::queue< RPNTokens::TokenBase * > &rpn)
convert expression to RPN *
Definition: ParseExp.cpp:349
bool ComparePrecedence(const OperatorBase *other)
Definition: ParseExp.cpp:170
float pow(float a, double b)
Definition: utils.h:181
int getWidth() const
Get the width of the image in pixels.
Definition: SrcPanoImage.h:266
ParseException(const char *message)
Definition: ParseExp.cpp:51
std::string varname
Definition: ParseExp.h:41
FunctionToken(std::function< double(double)> func)
Definition: ParseExp.cpp:79
static Operators::OperatorBase * ifOperator
Definition: ParseExp.cpp:243
std::function< double(double, double)> m_function
Definition: ParseExp.cpp:126
double getVar(const std::string &name) const
BinaryToken(std::function< double(double, double)> func)
Definition: ParseExp.cpp:106
binary operator on stack on shunting yards operator stack
Definition: ParseExp.cpp:198
bool stringToInt(const std::string &s, int &val)
convert string to integer value, returns true, if sucessful
Definition: utils.cpp:264
std::string FindOperator(const std::string &searchString)
compare the first characters in string with supportedBinaryOperations, return longest match ...
Definition: ParseExp.cpp:330
internal exception class for all errors
Definition: ParseExp.cpp:48
unary operator or function on rpn queue
Definition: ParseExp.cpp:76
static std::map< std::string, Operators::OperatorBase * > supportedBinaryOperations
Definition: ParseExp.cpp:239
std::function< double(double, double)> m_function
Definition: ParseExp.cpp:202
std::map< std::string, Variable > VariableMap
void ParseSingleVar(ParseVarVec &varVec, const std::string &s, std::ostream &errorStream)
Definition: ParseExp.cpp:657
vigra::RGBValue< T, RIDX, GIDX, BIDX > log(vigra::RGBValue< T, RIDX, GIDX, BIDX > const &v)
component-wise logarithm
Definition: utils.h:209
static Operators::OperatorBase * ifOperatorClose
Definition: ParseExp.cpp:244
Convenience functions for SrcPanoImage to use on the image variables.
bool CalculateConstant(HuginBase::Panorama &pano, const Parser::ParseVar &parseVar, Parser::ConstantMap &constants, std::ostream &statusStream, std::ostream &errorStream)
Definition: ParseExp.cpp:740
RPNTokens::TokenBase * GetTokenBase()
Definition: ParseExp.cpp:212
single numeric token on rpn queue
Definition: ParseExp.cpp:66
static std::map< std::string, Operators::FunctionOperator * > supportedFunctions
Definition: ParseExp.cpp:245
static Operators::OperatorBase * parenthesesOperator
Definition: ParseExp.cpp:242
FunctionOperator(std::function< double(double)> func, int prec=-2, bool rightAssoc=false)
Definition: ParseExp.cpp:191
virtual RPNTokens::TokenBase * GetTokenBase()
Definition: ParseExp.cpp:181
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
bool UpdateSingleVar(HuginBase::Panorama &pano, const Parser::ParseVar &parseVar, const Parser::ConstantMap &constants, size_t imgNr, std::ostream &statusStream, std::ostream &errorStream)
Definition: ParseExp.cpp:709
std::vector< std::string > SplitString(const std::string &s, const std::string &sep)
split string s at given sep, returns vector of strings
Definition: utils.cpp:294
virtual void evaluate(std::stack< double > &)=0
All variables of a source image.
Definition: SrcPanoImage.h:194
#define M_PI
Definition: GaborFilter.cpp:34
virtual void updateVariable(unsigned int imgNr, const Variable &var)
update a single variable
This file specifies what image variables SrcPanoImg should have.
function to parse expressions from strings
std::string tolower(const std::string &s)
convert a string to lowercase
Definition: stl_utils.h:49
std::function< double(double)> m_function
Definition: ParseExp.cpp:192
void evaluate(std::stack< double > &rpnStack)
Definition: ParseExp.cpp:80
std::function< double(double)> m_function
Definition: ParseExp.cpp:97