Medical Imaging Interaction Toolkit  2018.4.99-b7f3afaa
Medical Imaging Interaction Toolkit
mitkFormulaParser.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include <boost/math/constants/constants.hpp>
14 #include <boost/spirit/include/qi.hpp>
15 #include <boost/spirit/include/phoenix.hpp>
16 #include <boost/version.hpp>
17 
18 #include "mitkFormulaParser.h"
19 #include "mitkFresnel.h"
20 
21 namespace qi = boost::spirit::qi;
22 namespace ascii = boost::spirit::ascii;
23 namespace phx = boost::phoenix;
24 
25 typedef std::string::const_iterator Iter;
26 typedef ascii::space_type Skipper;
27 
28 namespace qi = boost::spirit::qi;
29 
30 namespace mitk
31 {
38  template<typename T>
39  inline T deg2rad(const T deg)
40  {
41  return deg * boost::math::constants::pi<T>() / static_cast<T>(180);
42  }
43 
50  template<typename T>
51  inline T cosd(const T t)
52  {
53  return std::cos(deg2rad(t));
54  }
55 
62  template<typename T>
63  inline T sind(const T t)
64  {
65  return std::sin(deg2rad(t));
66  }
67 
74  template<typename T>
75  inline T tand(const T t)
76  {
77  return std::tan(deg2rad(t));
78  }
79 
89  template<typename T>
90  T fresnelS(const T t)
91  {
92  T x = t / boost::math::constants::root_half_pi<T>();
93  return static_cast<T>(fresnel_s(x) / boost::math::constants::root_two_div_pi<T>());
94  }
95 
105  template<typename T>
106  T fresnelC(const T t)
107  {
108  T x = t / boost::math::constants::root_half_pi<T>();
109  return static_cast<T>(fresnel_c(x) / boost::math::constants::root_two_div_pi<T>());
110  }
111 
115  class Grammar : public qi::grammar<Iter, FormulaParser::ValueType(), Skipper>
116  {
121  struct func1_
122  {
123  // Required for Phoenix 3+
124  template<typename Sig>
125  struct result;
126 
135  template<typename Functor, typename Function, typename Arg1>
136  struct result<Functor(Function, Arg1&)>
137  {
139  typedef Arg1 type;
140  };
141 
152  template<typename Function, typename Arg1>
153  Arg1 operator()(const Function f, const Arg1 a1) const
154  {
155  return f(a1);
156  }
157  };
158 
164  class unaryFunction_ :
165  public qi::symbols<typename std::iterator_traits<Iter>::value_type, FormulaParser::ValueType(*)(FormulaParser::ValueType)>
166  {
167  public:
171  unaryFunction_()
172  {
173  this->add
174  ("abs", static_cast<FormulaParser::ValueType(*)(FormulaParser::ValueType)>(&std::abs))
175  ("exp", static_cast<FormulaParser::ValueType(*)(FormulaParser::ValueType)>(&std::exp)) // @TODO: exp ignores division by zero
176  ("sin", static_cast<FormulaParser::ValueType(*)(FormulaParser::ValueType)>(&std::sin))
177  ("cos", static_cast<FormulaParser::ValueType(*)(FormulaParser::ValueType)>(&std::cos))
178  ("tan", static_cast<FormulaParser::ValueType(*)(FormulaParser::ValueType)>(&std::tan))
179  ("sind", &sind)
180  ("cosd", &cosd)
181  ("tand", &tand)
182  ("fresnelS", &fresnelS)
183  ("fresnelC", &fresnelC);
184  }
185  } unaryFunction;
186 
187  public:
193  Grammar(FormulaParser& formulaParser) : Grammar::base_type(start)
194  {
195  using qi::_val;
196  using qi::_1;
197  using qi::_2;
198  using qi::char_;
199  using qi::alpha;
200  using qi::alnum;
201  using qi::double_;
202  using qi::as_string;
203 
204  phx::function<func1_> func1;
205 
206  start = expression > qi::eoi;
207 
208  expression = term[_val = _1]
209  >> *(('+' >> term[_val += _1])
210  | ('-' >> term[_val -= _1]));
211 
212  term = factor[_val = _1]
213  >> *(('*' >> factor[_val *= _1])
214  | ('/' >> factor[_val /= _1]));
215 
216  factor = primary[_val = _1];
218  //>> *('^' >> factor[phx::bind<FormulaParser::ValueType, FormulaParser::ValueType, FormulaParser::ValueType>(std::pow, _val, _1)]);
219 
220  variable = as_string[alpha >> *(alnum | char_('_'))]
221  [_val = phx::bind(&FormulaParser::lookupVariable, &formulaParser, _1)];
222 
223  primary = double_[_val = _1]
224  | '(' >> expression[_val = _1] >> ')'
225  | ('-' >> primary[_val = -_1])
226  | ('+' >> primary[_val = _1])
227  | (unaryFunction >> '(' >> expression >> ')')[_val = func1(_1, _2)]
228  | variable[_val = _1];
229  }
230 
232  qi::rule<Iter, FormulaParser::ValueType(), Skipper> start;
233  qi::rule<Iter, FormulaParser::ValueType(), Skipper> expression;
234  qi::rule<Iter, FormulaParser::ValueType(), Skipper> term;
235  qi::rule<Iter, FormulaParser::ValueType(), Skipper> factor;
236  qi::rule<Iter, FormulaParser::ValueType(), Skipper> variable;
237  qi::rule<Iter, FormulaParser::ValueType(), Skipper> primary;
238  };
239 
240 
241  FormulaParser::FormulaParser(const VariableMapType* variables) : m_Variables(variables)
242  {}
243 
245  {
246  std::string::const_iterator iter = input.begin();
247  std::string::const_iterator end = input.end();
248  FormulaParser::ValueType result = static_cast<FormulaParser::ValueType>(0);
249 
250  try
251  {
252  if (!qi::phrase_parse(iter, end, Grammar(*this), ascii::space, result))
253  {
254  mitkThrowException(FormulaParserException) << "Could not parse '" << input <<
255  "': Grammar could not be applied to the input " << "at all.";
256  }
257  }
258  catch (qi::expectation_failure<Iter>& e)
259  {
260  std::string parsed = "";
261 
262  for (Iter i = input.begin(); i != e.first; i++)
263  {
264  parsed += *i;
265  }
266  mitkThrowException(FormulaParserException) << "Error while parsing '" << input <<
267  "': Unexpected character '" << *e.first << "' after '" << parsed << "'";
268  }
269 
270  return result;
271  };
272 
274  {
275  if (m_Variables == nullptr)
276  {
277  mitkThrowException(FormulaParserException) << "Map of variables is empty";
278  }
279 
280  try
281  {
282  return m_Variables->at(var);
283  }
284  catch (std::out_of_range&)
285  {
286  mitkThrowException(FormulaParserException) << "No variable '" << var << "' defined in lookup";
287  }
288  };
289 
290 }
T cosd(const T t)
Returns the cosine of the given degree scalar.
T fresnelS(const T t)
Returns the fresnel integral sine at the given x-coordinate.
This class offers the functionality to evaluate simple mathematical formula strings (e...
T sind(const T t)
Returns the sine of the given degree scalar.
DataCollection - Class to facilitate loading/accessing structured data.
ValueType lookupVariable(const std::string var)
Looks up the associated value of the given string var in the variables map.
Exception class for all exceptions that are generated in the FormulaParser module.
double fresnel_c(double x)
T fresnelC(const T t)
Returns the fresnel integral cosine at the given x-coordinate.
T tand(const T t)
Returns the tangent of the given degree scalar.
ValueType parse(const std::string &input)
Evaluates the input string and returns the resulting value.
T deg2rad(const T deg)
Transforms the given number from degrees to radians and returns it.
FormulaParser(const VariableMapType *variables)
Construct the FormulaParser and initialized the variables with variables.
std::string::const_iterator Iter
std::map< std::string, ValueType > VariableMapType
double fresnel_s(double x)
#define mitkThrowException(classname)
ascii::space_type Skipper