Isis 3 Programmer Reference
InlineCalculator.cpp
Go to the documentation of this file.
1 
24 #include "InlineCalculator.h"
25 
26 // std library
27 #include <cmath>
28 
29 // Qt library
30 #include <QMap>
31 #include <QString>
32 #include <QStringList>
33 #include <QVariant>
34 #include <QVector>
35 
36 // boost library
37 #include <boost/foreach.hpp>
38 
39 // naif library
40 #include <SpiceUsr.h>
41 #include <SpiceZfc.h>
42 #include <SpiceZmc.h>
43 
44 // other ISIS
45 #include "IException.h"
46 #include "InlineInfixToPostfix.h"
47 #include "IString.h"
48 #include "NaifStatus.h"
49 
50 using namespace std;
51 
52 namespace Isis {
53 
58  InlineCalculator::InlineCalculator() : Calculator() {
59  initialize();
60  }
61 
62 
69  InlineCalculator::InlineCalculator(const QString &equation) : Calculator() {
70  initialize();
72  }
73 
74 
79  destruct();
80  }
81 
82 
90  int InlineCalculator::size() const {
91  return (m_functions.size());
92  }
93 
94 
102  QString InlineCalculator::equation() const {
103  return (m_equation);
104  }
105 
106 
123  bool InlineCalculator::compile(const QString &equation) {
124  // Transform equation to postfix order
125 
126  QString tokenOps = toPostfix(equation);
127  tokenOps = tokenOps.simplified();
128 
129  int nerrors = 0;
130  QString error = "Errors parsing inline equation[" + equation + "].";
131  IException errList(IException::User, error, _FILEINFO_);
132 
133  Clear(); // Clear the stack
135  m_functions.clear(); // Clear function list
136 
137  QStringList tokenList = tokenOps.split(" ");
138  while ( !tokenList.isEmpty() ) {
139  QString token = tokenList.takeFirst();
140  if ( !token.isEmpty() ) {
141 
142  // See if the function already exists. Note that scalars and variables
143  // that are already present can safely be reused. New occuring ones are
144  // created fresh!
145  FxTypePtr fx = find(token);
146  if ( 0 != fx ) {
147  m_functions.push_back(fx);
148  }
149  // New scalars and variables will create new unique function objects if
150  // they do not already exist (they would be found above then)
151  else if ( isScalar(token) ) {
152  fx = addFunction(new ParameterFx(token, &InlineCalculator::scalar, this));
153  m_functions.push_back(fx);
154  }
155  else if ( isVariable(token) ) {
156  // Will also get line, sample, band, etc...
157  fx = addFunction(new ParameterFx(token, &InlineCalculator::variable, this));
158  m_functions.push_back(fx);
159  }
160  else {
161  // Parameter not recognized during compile. All unknown tokens are
162  // assumed to be variables until run time when they are searched for
163  // in the current state of the resource pool.
164  try {
165  if ( !orphanTokenHandler(token) ) {
166  error = "Equation element (" + token + ") invalid - token not recognized.";
167  errList.append(IException(IException::User, error, _FILEINFO_));
168  nerrors++;
169  }
170  }
171  // Catch all failures from orphaned tokens
172  catch (IException &e) {
173  errList.append(e);
174  nerrors++;
175  }
176  }
177  }
178  }
179 
180  // Might want to make this optional here
181  if (nerrors > 0) {
182  throw errList;
183  }
184  return (nerrors == 0);
185  }
186 
187 
205  QVector<double> value;
206  try {
207  pushVariables(variablePool);
208  value = evaluate();
209  popVariables();
210  }
211  catch (IException &ie) {
212  popVariables();
214  "Calculation with variable pool failed.",
215  _FILEINFO_);
216  }
217  return (value);
218  }
219 
220 
236 
237  BOOST_FOREACH (FxTypePtr function, m_functions) {
238  function->execute();
239  }
240 
241  if (StackSize() != 1) {
242  QString msg = "Too many operands in the equation [" + m_equation + "].";
244  }
245 
246  return (Pop(true));
247  }
248 
249 
258  QString InlineCalculator::toPostfix(const QString &equation) const {
259  InlineInfixToPostfix parser;
260  return (parser.convert(equation));
261  }
262 
263 
272  bool InlineCalculator::isScalar(const QString &scalar) {
273  if (scalar.isEmpty()) return (false);
274  try {
275  toDouble(scalar);
276  return (true);
277  }
278  catch (IException &e) {
279  return (false);
280  }
281  }
282 
283 
292  bool InlineCalculator::isVariable(const QString &str) {
293  if (str.isEmpty()) {
294  return (false);
295  }
296  if (!isScalar(str)) {
297  return (true);
298  }
299  return (false);
300  }
301 
302 
311  void InlineCalculator::scalar(const QVariant &scalar) {
312  Push(toDouble(scalar.toString()));
313  }
314 
315 
326  void InlineCalculator::variable(const QVariant &variable) {
327  CalculatorVariablePool *variablePool = variables();
328  QString key = variable.toString();
329  if (variablePool->exists(key)) {
330  QVector<double> values = variablePool->value(key);
331  Push(values);
332  return;
333  }
334 
335  // Error!
336  QString error = "Could not find variable [" + key + "] in variable pool.";
337  throw IException(IException::User, error, _FILEINFO_);
338  }
339 
340 
352  double floatModulusOperator(double a, double b) {
353  return (fmod(a, b));
354  }
355 
356 
363  QVector<double> y = Pop();
364  QVector<double> x = Pop();
365  QVector<double> result;
366  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(),
368  Push(result);
369  return;
370  }
371 
372 
378  QVector<double> degree = Pop();
379  QVector<double> result;
380  BOOST_FOREACH(double d, degree) {
381  result.push_back(d * rpd_c());
382  }
383  Push(result);
384  return;
385  }
386 
387 
394  QVector<double> result;
395  BOOST_FOREACH(double r, radians) {
396  result.push_back(r * dpr_c());
397  }
398  Push(result);
399  return;
400  }
401 
402 
411  QVector<double> inputA = Pop();
412  QVector<double> inputB = Pop();
413  QVector<double> results;
414  if ( inputA.size() != inputB.size() ) {
415  QString msg = "Failed performing logical or operation, "
416  "input vectors are of differnet lengths.";
418  }
419  for (int i = 0; i < inputA.size(); i++) {
420  results.push_back( inputA[i] || inputB[i] );
421  }
422  Push(results);
423  return;
424  }
425 
426 
435  QVector<double> inputA = Pop();
436  QVector<double> inputB = Pop();
437  QVector<double> results;
438  if ( inputA.size() != inputB.size() ) {
439  QString msg = "Failed performing logical and operation, "
440  "input vectors are of differnet lengths.";
442  }
443  for (int i = 0; i < inputA.size(); i++) {
444  results.push_back( inputA[i] && inputB[i] );
445  }
446  Push(results);
447  return;
448  }
449 
450 
455  Push(pi_c());
456  return;
457  }
458 
459 
464  Push(E);
465  return;
466  }
467 
468 
478  bool InlineCalculator::fxExists(const QString &fxname) const {
479  return (m_fxPool.contains(fxname));
480  }
481 
482 
496  FxTypePtr func = find(function->name());
497  if (!func) {
498  m_fxPool.insert(function->name(), function);
499  }
500  else {
501  QString msg = "Function operator [" + function->name() +
502  "] exists! Cannot replace existing functions in the pool :-(";
504  }
505  return (function);
506  }
507 
508 
529  bool InlineCalculator::orphanTokenHandler(const QString &token) {
530  return (false);
531  }
532 
533 
541  m_variablePoolList.push_back(variablePool);
542  return;
543  }
544 
545 
554  if ( !m_variablePoolList.isEmpty() ) {
555  return (m_variablePoolList.back());
556  }
558  "Request for nonexistent variable pool.",
559  _FILEINFO_);
560  }
561 
562 
567  Clear();
568  if ( !m_variablePoolList.isEmpty() ) {
569  m_variablePoolList.pop_back();
570  }
571  return;
572  }
573 
574 
586  FxPoolType::iterator fx = m_fxPool.find(fxname);
587  if ( m_fxPool.end() == fx ) return NULL;
588  return (*fx);
589  }
590 
591 
596  // Set up calculator function lookup list
597  addFunction(new VoidFx("^", &Calculator::Exponent, this));
598  addFunction(new VoidFx("/", &Calculator::Divide, this));
599  addFunction(new VoidFx("*", &Calculator::Multiply, this));
600  addFunction(new VoidFx("<<", &Calculator::LeftShift, this));
601  addFunction(new VoidFx(">>", &Calculator::RightShift, this));
602  addFunction(new VoidFx("+", &Calculator::Add, this));
603  addFunction(new VoidFx("-", &Calculator::Subtract, this));
604  addFunction(new VoidFx(">", &Calculator::GreaterThan, this));
605  addFunction(new VoidFx("<", &Calculator::LessThan, this));
608  addFunction(new VoidFx("==", &Calculator::Equal, this));
609  addFunction(new VoidFx("!=", &Calculator::NotEqual, this));
610 
611  // These are not part of the Calculator class because InfixToPostfix didn't
612  // add/recognize them in the tokenizer. See InlineInfixToPostfix class which
613  // is part of this calculator.
614  addFunction(new VoidFx("&", &Calculator::And, this));
615  addFunction(new VoidFx("and", &Calculator::And, this));
616  addFunction(new VoidFx("|", &Calculator::Or, this));
617  addFunction(new VoidFx("or", &Calculator::Or, this));
619  addFunction(new VoidFx("mod", &Calculator::Modulus, this));
621 
622  addFunction(new VoidFx("--", &Calculator::Negative, this));
623  addFunction(new VoidFx("neg", &Calculator::Negative, this));
624 
625  addFunction(new VoidFx("min", &Calculator::MinimumPixel, this));
626  addFunction(new VoidFx("max", &Calculator::MaximumPixel, this));
627  addFunction(new VoidFx("abs", &Calculator::AbsoluteValue, this));
628  addFunction(new VoidFx("sqrt", &Calculator::SquareRoot, this));
629  addFunction(new VoidFx("log", &Calculator::Log, this));
630  addFunction(new VoidFx("ln", &Calculator::Log, this));
631  addFunction(new VoidFx("log10", &Calculator::Log10, this));
632  addFunction(new InlineVoidFx("pi", &InlineCalculator::pi, this));
633 
634  addFunction(new VoidFx("sin", &Calculator::Sine, this));
635  addFunction(new VoidFx("cos", &Calculator::Cosine, this));
636  addFunction(new VoidFx("tan", &Calculator::Tangent, this));
637  addFunction(new VoidFx("sec", &Calculator::Secant, this));
638  addFunction(new VoidFx("csc", &Calculator::Cosecant, this));
639  addFunction(new VoidFx("cot", &Calculator::Cotangent, this));
640  addFunction(new VoidFx("asin", &Calculator::Arcsine, this));
641  addFunction(new VoidFx("acos", &Calculator::Arccosine, this));
642  addFunction(new VoidFx("atan", &Calculator::Arctangent, this));
643  addFunction(new VoidFx("atan2", &Calculator::Arctangent2, this));
644 
650 
651  // Add new functions available for inlining
652  // m_variablePoolList = defaultVariables();
653 
654  return;
655  }
656 
657 
663  BOOST_FOREACH (FxTypePtr function, m_fxPool) {
664  delete function;
665  }
666 
667  m_fxPool.clear();
668  m_functions.clear();
669  return;
670  }
671 
672 
677  }
678 
679 
684  }
685 
686 
693  bool CalculatorVariablePool::exists(const QString &variable) const {
694  return (true);
695  }
696 
697 
709  const int &index) const {
710  QString mess = "No implementation in Calculator variable pool to provide "
711  " value for variable [" + variable + "].";
713  }
714 
715 
728  void CalculatorVariablePool::add(const QString &key, QVector<double> &values) {
729  QString mess = "No implementation in Calculator variable pool to add "
730  " value for variable [" + key + "].";
732  }
733 
734 
740  FxBinder::FxBinder(const QString &name) : m_name(name) {
741  }
742 
743 
748  }
749 
750 
756  QString FxBinder::name() const {
757  return (m_name);
758  }
759 
760 
766  dispatch();
767  }
768 
769 
775  dispatch();
776  }
777 
778 
785  QVariant FxBinder::args() {
786  return (QVariant(m_name));
787  }
788 
789 
798  InlineVoidFx::InlineVoidFx(const QString &name, calcOp function,
799  InlineCalculator *calculator) : FxBinder(name),
800  m_func(function),
801  m_calc(calculator) {
802  }
803 
804 
809  }
810 
811 
818  }
819 
820 
832  ParameterFx::ParameterFx(const QString &name, calcOp function,
833  InlineCalculator *calculator) : FxBinder(name),
834  m_func(function),
835  m_calc(calculator){
836  }
837 
838 
843  }
844 
845 
853  }
854 
855 
864  VoidFx::VoidFx(const QString &name, calcOp function,
865  InlineCalculator *calculator) : FxBinder(name),
866  m_func(function),
867  m_calc(calculator) {
868  }
869 
870 
875  }
876 
877 
884  }
885 } // namespace Isis
void LessThanOrEqual()
Pop two elements off the stack and compare them to see where one is less than or equal to the other...
Definition: Calculator.cpp:662
void And()
Pop two elements, AND them, then push the result on the stack.
Definition: Calculator.cpp:694
void Divide()
Pops two, divides them, then pushes the quotient on the stack.
Definition: Calculator.cpp:369
QList< CalculatorVariablePool * > m_variablePoolList
The list of variable pool pointers.
bool fxExists(const QString &fxname) const
Determines whether the given function name exists in the current function pool.
void Multiply()
Pops two elements, multiplies them, then pushes the product on the stack.
Definition: Calculator.cpp:332
void floatModulus()
Pops the top two vectors off the current stack and performs the floatModulusOperator() on the corresp...
void NotEqual()
Pop two elements off the stack and compare them to see where one is not equal to the other...
Definition: Calculator.cpp:677
void GreaterThan()
Pop two elements off the stack and compare them to see where one is greater than the other...
Definition: Calculator.cpp:602
virtual QVector< double > value(const QString &variable, const int &index=0) const
Return vector of doubles for Calculator functions.
void LeftShift()
Pop the top element, then perform a left shift with zero fill.
Definition: Calculator.cpp:456
CalculatorVariablePool()
Constructs a CalculatorVariablePool object.
void Arctangent()
Pops one element and push the arctangent.
Definition: Calculator.cpp:802
void variable(const QVariant &variable)
Pushes the given value onto the stack as a variable.
void Arctangent2()
Pops two elements and push the arctangent.
Definition: Calculator.cpp:842
virtual void add(const QString &key, QVector< double > &values)
Add a parameter to the variable pool.
void logicalOr()
Pops the top two vectors off the current stack and performs a logical or on each pair.
QString m_name
Name of function.
void dispatch()
Calls the function corresponding to this object using its stored InlineCalculator, InlineCalculator operator, and arguments.
This is a simple class to model a Calculator Variable Pool.
virtual ~FxBinder()
Destroys the FxBinder object.
void MinimumPixel()
Pop two elements, then push the minimum on a pixel by pixel basis back on the stack.
Definition: Calculator.cpp:572
FxBinder(const QString &name)
Constructs a function binder given a name.
A parser for converting equation strings to postfix.
void degrees()
Pops the top vector off the current stack and converts from radians to degrees.
int size() const
Accesses the number of functions, operators, variables, and scalars to be executed.
void Or()
Pop two elements, OR them, then push the result on the stack.
Definition: Calculator.cpp:708
QString convert(const QString &infix)
This method converts infix to postfix.
void Arccosine()
Pops one element and push the arccosine.
Definition: Calculator.cpp:792
void LessThan()
Pop two elements off the stack and compare them to see where one is less than the other...
Definition: Calculator.cpp:617
void logicalAnd()
Pops the top two vectors off the current stack and performs a logical and on each pair...
InlineCalculator * m_calc
The Calculator used to evaluate this function.
void Modulus()
Pops two elements, mods them, then pushes the result on the stack.
Definition: Calculator.cpp:381
virtual ~InlineCalculator()
Destroys the InlineCalculator object.
void GreaterThanOrEqual()
Pop two elements off the stack and compare them to see where one is greater than or equal to the othe...
Definition: Calculator.cpp:647
void append(const IException &exceptionSource)
Appends the given exception (and its list of previous exceptions) to this exception&#39;s causational exc...
Definition: IException.cpp:425
Namespace for the standard library.
void Cotangent()
Pops one element and push the cotangent.
Definition: Calculator.cpp:772
QVector< double > Pop(bool keepSpecials=false)
Pop an element off the stack.
Definition: Calculator.cpp:964
Provides a calculator for inline equations.
virtual bool exists(const QString &variable) const
Returns true so the real error can be reported.
virtual bool orphanTokenHandler(const QString &token)
Default token handler if it is undefined during parsing/compilation.
FxPoolType m_fxPool
The map between function names and equation lists.
bool isScalar(const QString &scalar)
Determines whether the given string contains a scalar value (i.e.
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition: IString.cpp:164
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:162
void Negative()
Pops an element, negates it, then pushes the result.
Definition: Calculator.cpp:322
void Log()
Pop an element, compute its log, then push the result on the stack.
Definition: Calculator.cpp:434
InlineVoidFx(const QString &name, calcOp function, InlineCalculator *calculator)
Constructs an InlineVoid function from the given name, InlineCalculator operator, and InlineCalculato...
InlineCalculator * m_calc
The InlineCalculator used to evaluate this function.
virtual ~InlineVoidFx()
Destroys the InlineVoidFx object.
void Arcsine()
Pops one element and push the arcsine.
Definition: Calculator.cpp:782
QVector< double > evaluate()
Evaluate compiled equation with existing variable pool.
bool compile(const QString &equation)
Compiles the given equation for evaluation.
void PerformOperation(QVector< double > &results, QVector< double >::iterator arg1Start, QVector< double >::iterator arg1End, double operation(double))
Performs the mathematical operations on each argument.
double floatModulusOperator(double a, double b)
Determines the remainder of the quotient a/b whose sign is the same as that of a. ...
QString equation() const
Accesses the string representation of the current equation, in postfix format.
void SquareRoot()
Pop an element, compute its square root, then push the root on the stack.
Definition: Calculator.cpp:412
QString name() const
The name assigned to this function binder.
virtual QString toPostfix(const QString &equation) const
Converts the given string from infix to postfix format.
InlineCalculator * m_calc
The InlineCalculator used to evaluate this function.
void Add()
Pops two elements, adds them, then pushes the sum on the stack.
Definition: Calculator.cpp:345
bool isVariable(const QString &str)
Determines whether the given string is a variable.
void popVariables()
Removes the last variable pool in the current variable pool list.
int StackSize()
Returns the current stack size.
Definition: Calculator.cpp:889
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
This is the parent class to the various function classes.
void Subtract()
Pops two elements, subtracts them, then pushes the difference on the stack.
Definition: Calculator.cpp:357
A type of error that could only have occurred due to a mistake on the user&#39;s part (e...
Definition: IException.h:142
void Equal()
Pop two elements off the stack and compare them to see where one is equal to the other, then push the results on the stack.
Definition: Calculator.cpp:632
FxEqList m_functions
The list of pointers to function equations for the calculator.
A type of error that cannot be classified as any of the other error types.
Definition: IException.h:134
virtual ~ParameterFx()
Destroys the ParameterFx object.
This class is used to bind function names with corresponding Calculator functions that do not take pa...
calcOp m_func
The InlineCalculator operator that takes parameters.
void destruct()
Discard of all the function pool and class resources.
void operator()()
Executes the function.
void initialize()
Adds the recognized functions to the function pool.
#define CALL_MEMBER_FN(object, ptrToMember)
Macro for calling member functions.
void Push(double scalar)
Push a scalar onto the stack.
Definition: Calculator.cpp:908
calcOp m_func
The Calculator operator that takes no parameters.
void pushVariables(CalculatorVariablePool *variablePool)
Push the given variable pool onto the current variable pool list.
void pi()
Pushes the PI constant onto the current stack.
const double E
Sets some basic constants for use in ISIS programming.
Definition: Constants.h:55
void radians()
Pops the top vector off the current stack and converts from degrees to radians.
virtual void Clear()
Clear out the stack.
void AbsoluteValue()
Pop an element, compute its absolute value, then push the result on the stack.
Definition: Calculator.cpp:422
FxTypePtr find(const QString &fxname)
Gets a pointer to the function from the current pool that corresponds to the given function name...
ParameterFx(const QString &name, calcOp function, InlineCalculator *calculator)
Constructs a Parameter function from the given name (containing the appropriate parameters), InlineCalculator operator, and InlineCalculator.
calcOp m_func
The InlineCalculator operator that takes no parameters.
void MaximumPixel()
Pop two elements, then push the maximum on a pixel by pixel basis back on the stack.
Definition: Calculator.cpp:587
void Secant()
Pops one element and push the secant.
Definition: Calculator.cpp:762
This class is used to bind function names with corresponding InlineCalculator functions that do not t...
void Sine()
Pops one element and push the sine.
Definition: Calculator.cpp:722
void RightShift()
Pop the top element, then perform a right shift with zero fill.
Definition: Calculator.cpp:495
virtual QVariant args()
Accesses the arguments for this function.
void Tangent()
Pops one element and push the tangent.
Definition: Calculator.cpp:742
virtual ~VoidFx()
Destroys the VoidFx object.
void execute()
Executes the function.
void dispatch()
Calls the function corresponding to this object using its stored Calculator and Calculator operator...
Isis exception class.
Definition: IException.h:107
VoidFx(const QString &name, calcOp function, InlineCalculator *calculator)
Constructs a Void function from the given name, Calculator operator, and Calculator.
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
InlineCalculator()
Constructs an InlineCalculator object by initializing the operator lookup list.
QString m_equation
The equation to be evaluated.
void Cosecant()
Pops one element and push the cosecant.
Definition: Calculator.cpp:752
void eConstant()
Pushes the Euler constant (e) onto the current stack.
virtual void dispatch()=0
This method defines how to execute this function.
FxTypePtr addFunction(FxTypePtr function)
Adds a function to the function pool.
void Log10()
Pop an element, compute its base 10 log, then push the result on the stack.
Definition: Calculator.cpp:444
void Exponent()
Pops two elements, computes the power then pushes the result on the stack The exponent has to be a sc...
Definition: Calculator.cpp:397
~CalculatorVariablePool()
Destroys the CalculatorVariablePool object.
void Cosine()
Pops one element and push the cosine.
Definition: Calculator.cpp:732
void scalar(const QVariant &scalar)
Pushes the given value onto the stack as a scalar.
void dispatch()
Calls the function corresponding to this object using its stored InlineCalculator and InlineCalculato...
This class is used to bind function names with corresponding Calculator functions that take a paramet...
Calculator for arrays.
Definition: Calculator.h:70
CalculatorVariablePool * variables()
Accesses the last variable pool in the current pool list.