Isis 3 Programmer Reference
Calculator.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 
8 #include <cmath>
9 
10 #include <QRegExp>
11 #include <QStack>
12 #include <QVector>
13 
14 #include "Calculator.h"
15 #include "InfixToPostfix.h"
16 #include "IException.h"
17 #include "SpecialPixel.h"
18 
19 using namespace std;
20 
21 namespace Isis {
31  Calculator::Calculator() {
33  p_valStack = NULL;
34 
35  p_valStack = new QStack< QVector<double> >();
36  }
37 
39  Calculator::~Calculator() {
40  if (p_valStack) {
41  delete p_valStack;
42  p_valStack = NULL;
43  }
44  }
45 
53  double NegateOperator(double a) {
54  return -1 * a;
55  }
56 
57 
66  double MultiplyOperator(double a, double b) {
67  return a * b;
68  }
69 
70 
79  double DivideOperator(double a, double b) {
80  return a / b;
81  }
82 
83 
92  double AddOperator(double a, double b) {
93  return a + b;
94  }
95 
96 
105  double SubtractOperator(double a, double b) {
106  return a - b;
107  }
108 
109 
118  double GreaterThanOperator(double a, double b) {
119  return a > b ? 1.0 : 0.0;
120  }
121 
122 
131  double LessThanOperator(double a, double b) {
132  return a < b ? 1.0 : 0.0;
133  }
134 
135 
144  double EqualOperator(double a, double b) {
145  return a == b ? 1.0 : 0.0;
146  }
147 
148 
157  double GreaterThanOrEqualOperator(double a, double b) {
158  return a >= b ? 1.0 : 0.0;
159  }
160 
161 
170  double LessThanOrEqualOperator(double a, double b) {
171  return a <= b ? 1.0 : 0.0;
172  }
173 
174 
183  double NotEqualOperator(double a, double b) {
184  return a != b ? 1.0 : 0.0;
185  }
186 
187 
195  double CosecantOperator(double a) {
196  return 1.0 / sin(a);
197  }
198 
199 
207  double SecantOperator(double a) {
208  return 1.0 / cos(a);
209  }
210 
218  double CotangentOperator(double a) {
219  return 1.0 / tan(a);
220  }
221 
222 
230  int Round(double a) {
231  return (a > 0) ? (int)(a + 0.5) : (int)(a - 0.5);
232  }
233 
234 
243  double BitwiseAndOperator(double a, double b) {
244  return (double)(Round(a)&Round(b));
245  }
246 
247 
256  double BitwiseOrOperator(double a, double b) {
257  return (double)(Round(a) | Round(b));
258  }
259 
260 
269  double ModulusOperator(double a, double b) {
270  return (double)(Round(a) % Round(b));
271  }
272 
281  double MaximumOperator(double a, double b) {
282 
283  if (std::isnan(a)) return (a);
284  if (std::isnan(b)) return (b);
285  return (a > b) ? a : b;
286  }
287 
296  double MinimumOperator(double a, double b) {
297  if (std::isnan(a)) return (a);
298  if (std::isnan(b)) return (b);
299  return (a < b) ? a : b;
300  }
301 
302 
303 
307  void Calculator::Negative() {
308  QVector<double> result = Pop();
309  PerformOperation(result, result.begin(), result.end(), NegateOperator);
310  Push(result);
311  }
312 
313 
317  void Calculator::Multiply() {
318  QVector<double> y = Pop();
319  QVector<double> x = Pop();
320  QVector<double> result;
321 
322  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), MultiplyOperator);
323  Push(result);
324  }
325 
326 
330  void Calculator::Add() {
331  QVector<double> y = Pop();
332  QVector<double> x = Pop();
333  QVector<double> result;
334  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), AddOperator);
335  Push(result);
336  }
337 
338 
342  void Calculator::Subtract() {
343  QVector<double> y = Pop();
344  QVector<double> x = Pop();
345  QVector<double> result;
346  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), SubtractOperator);
347  Push(result);
348  }
349 
350 
354  void Calculator::Divide() {
355  QVector<double> y = Pop();
356  QVector<double> x = Pop();
357  QVector<double> result;
358 
359  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), DivideOperator);
360  Push(result);
361  }
362 
366  void Calculator::Modulus() {
367  QVector<double> y = Pop();
368  QVector<double> x = Pop();
369  QVector<double> result;
370 
371  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), ModulusOperator);
372  Push(result);
373  }
374 
375 
382  void Calculator::Exponent() {
383  QVector<double> exponent = Pop();
384  QVector<double> x = Pop();
385  QVector<double> result;
386 
387  PerformOperation(result, x.begin(), x.end(), exponent.begin(), exponent.end(), pow);
388  Push(result);
389  }
390 
391 
397  void Calculator::SquareRoot() {
398  QVector<double> result = Pop();
399  PerformOperation(result, result.begin(), result.end(), sqrt);
400  Push(result);
401  }
402 
403 
407  void Calculator::AbsoluteValue() {
408  QVector<double> result = Pop();
409  PerformOperation(result, result.begin(), result.end(), fabs);
410  Push(result);
411  }
412 
413 
419  void Calculator::Log() {
420  QVector<double> result = Pop();
421  PerformOperation(result, result.begin(), result.end(), log);
422  Push(result);
423  }
424 
425 
429  void Calculator::Log10() {
430  QVector<double> result = Pop();
431  PerformOperation(result, result.begin(), result.end(), log10);
432  Push(result);
433  }
434 
435 
441  void Calculator::LeftShift() {
442  QVector<double> y = Pop();
443  if (y.size() != 1) {
444  IString msg = "When trying to do a left shift calculation, a non-scalar "
445  "shift value was encountered. Shifting requires scalars.";
446  throw IException(IException::Unknown, msg, _FILEINFO_);
447  }
448  else {
449  QVector<double> x = Pop();
450 
451  if ((int)y[0] > (int)x.size()) {
452  IString msg = "When trying to do a left shift calculation, a shift "
453  "value greater than the data size was encountered. "
454  "Shifting by this value would erase all of the data.";
455  throw IException(IException::Unknown, msg, _FILEINFO_);
456  }
457  else {
458  QVector<double> result;
459  int shift = (int)y[0];
460  result.resize(x.size());
461 
462  for (int i = 0; i < result.size(); i++) {
463  if (i + shift < x.size() && i + shift >= 0)
464  result[i] = x[i+shift];
465  else
466  result[i] = sqrt(-1.0); // create a NaN
467  }
468 
469  Push(result);
470  }
471  }
472  }
473 
474 
480  void Calculator::RightShift() {
481  QVector<double> y = Pop();
482  if (y.size() != 1) {
483  IString msg = "When trying to do a right shift calculation, a non-scalar "
484  "shift value was encountered. Shifting requires scalars.";
485  throw IException(IException::Unknown, msg, _FILEINFO_);
486  }
487  else {
488  QVector<double> x = Pop();
489 
490  if ((int)y[0] > (int)x.size()) {
491  IString msg = "When trying to do a right shift calculation, a shift "
492  "value greater than the data size was encountered. "
493  "Shifting by this value would erase all of the data.";
494  throw IException(IException::Unknown, msg, _FILEINFO_);
495  }
496  else {
497  QVector<double> result;
498  int shift = (int)y[0];
499  result.resize(x.size());
500 
501  for (int i = 0; i < (int)result.size(); i++) {
502  if (i - shift < (int)x.size() && i - shift >= 0) {
503  result[i] = x[i-shift];
504  }
505  else {
506  result[i] = sqrt(-1.0); // create a NaN
507  }
508  }
509 
510  Push(result);
511  }
512  }
513  }
514 
518  void Calculator::MinimumLine() {
519  QVector<double> result = Pop();
520 
521  double minVal = result[0];
522  for (int i = 0; i < result.size(); i++) {
523  if (!IsSpecial(result[i])) {
524  minVal = min(minVal, result[i]);
525  }
526  }
527 
528  result.clear();
529  result.push_back(minVal);
530  Push(result);
531  }
532 
533 
537  void Calculator::MaximumLine() {
538  QVector<double> result = Pop();
539 
540  double maxVal = result[0];
541  for (int i = 0; i < result.size(); i++) {
542  if (!IsSpecial(result[i])) {
543  maxVal = max(maxVal, result[i]);
544  }
545  }
546 
547  result.clear();
548  result.push_back(maxVal);
549  Push(result);
550  }
551 
552 
557  void Calculator::MinimumPixel() {
558  QVector<double> x = Pop();
559  QVector<double> y = Pop();
560  QVector<double> result;
561 
562  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(),
564  Push(result);
565  }
566 
567 
572  void Calculator::MaximumPixel() {
573  QVector<double> x = Pop();
574  QVector<double> y = Pop();
575  QVector<double> result;
576 
577  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(),
579  Push(result);
580  }
581 
582 
587  void Calculator::GreaterThan() {
588  QVector<double> y = Pop();
589  QVector<double> x = Pop();
590  QVector<double> result;
591 
592  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(),
594  Push(result);
595  }
596 
597 
602  void Calculator::LessThan() {
603  QVector<double> y = Pop();
604  QVector<double> x = Pop();
605  QVector<double> result;
606 
607  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(),
609  Push(result);
610  }
611 
612 
617  void Calculator::Equal() {
618  QVector<double> y = Pop();
619  QVector<double> x = Pop();
620  QVector<double> result;
621 
622  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(),
623  EqualOperator);
624  Push(result);
625  }
626 
627 
632  void Calculator::GreaterThanOrEqual() {
633  QVector<double> y = Pop();
634  QVector<double> x = Pop();
635  QVector<double> result;
636 
637  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(),
639  Push(result);
640  }
641 
642 
647  void Calculator::LessThanOrEqual() {
648  QVector<double> y = Pop();
649  QVector<double> x = Pop();
650  QVector<double> result;
651 
652  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(),
654  Push(result);
655  }
656 
657 
662  void Calculator::NotEqual() {
663  QVector<double> y = Pop();
664  QVector<double> x = Pop();
665  QVector<double> result;
666 
667  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(),
669  Push(result);
670  }
671 
672 
673  // Commented out because bitwise ops only work with integers instead of
674  // doubles
675 
679  void Calculator::And() {
680  QVector<double> y = Pop();
681  QVector<double> x = Pop();
682  QVector<double> result;
683 
684  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(),
686  Push(result);
687  }
688 
689 
693  void Calculator::Or() {
694  QVector<double> y = Pop();
695  QVector<double> x = Pop();
696  QVector<double> result;
697 
698  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(),
700  Push(result);
701  }
702 
703 
707  void Calculator::Sine() {
708  QVector<double> result = Pop();
709  PerformOperation(result, result.begin(), result.end(), sin);
710  Push(result);
711  }
712 
713 
717  void Calculator::Cosine() {
718  QVector<double> result = Pop();
719  PerformOperation(result, result.begin(), result.end(), cos);
720  Push(result);
721  }
722 
723 
727  void Calculator::Tangent() {
728  QVector<double> result = Pop();
729  PerformOperation(result, result.begin(), result.end(), tan);
730  Push(result);
731  }
732 
733 
737  void Calculator::Cosecant() {
738  QVector<double> result = Pop();
739  PerformOperation(result, result.begin(), result.end(), CosecantOperator);
740  Push(result);
741  }
742 
743 
747  void Calculator::Secant() {
748  QVector<double> result = Pop();
749  PerformOperation(result, result.begin(), result.end(), SecantOperator);
750  Push(result);
751  }
752 
753 
757  void Calculator::Cotangent() {
758  QVector<double> result = Pop();
759  PerformOperation(result, result.begin(), result.end(), CotangentOperator);
760  Push(result);
761  }
762 
763 
767  void Calculator::Arcsine() {
768  QVector<double> result = Pop();
769  PerformOperation(result, result.begin(), result.end(), asin);
770  Push(result);
771  }
772 
773 
777  void Calculator::Arccosine() {
778  QVector<double> result = Pop();
779  PerformOperation(result, result.begin(), result.end(), acos);
780  Push(result);
781  }
782 
783 
787  void Calculator::Arctangent() {
788  QVector<double> result = Pop();
789  PerformOperation(result, result.begin(), result.end(), atan);
790  Push(result);
791  }
792 
793 
797  void Calculator::ArcsineH() {
798  QVector<double> result = Pop();
799  PerformOperation(result, result.begin(), result.end(), asinh);
800  Push(result);
801  }
802 
803 
807  void Calculator::ArccosineH() {
808  QVector<double> result = Pop();
809  PerformOperation(result, result.begin(), result.end(), acosh);
810  Push(result);
811  }
812 
813 
817  void Calculator::ArctangentH() {
818  QVector<double> result = Pop();
819  PerformOperation(result, result.begin(), result.end(), atanh);
820  Push(result);
821  }
822 
823 
827  void Calculator::Arctangent2() {
828  QVector<double> y = Pop();
829  QVector<double> x = Pop();
830  QVector<double> result;
831 
832  PerformOperation(result, x.begin(), x.end(), y.begin(), y.end(), atan2);
833  Push(result);
834  }
835 
836 
840  void Calculator::SineH() {
841  QVector<double> result = Pop();
842  PerformOperation(result, result.begin(), result.end(), sinh);
843  Push(result);
844  }
845 
846 
850  void Calculator::CosineH() {
851  QVector<double> result = Pop();
852  PerformOperation(result, result.begin(), result.end(), cosh);
853  Push(result);
854  }
855 
856 
860  void Calculator::TangentH() {
861  QVector<double> result = Pop();
862  PerformOperation(result, result.begin(), result.end(), tanh);
863  Push(result);
864  }
865 
866 
867  // Stack methods
868 
874  int Calculator::StackSize() {
875  return p_valStack->size();
876  }
877 
883  void Calculator::Push(QVector<double> &vect) {
884  p_valStack->push(vect);
885  }
886 
887 
893  void Calculator::Push(double scalar) {
894  QVector<double> s;
895  s.push_back(scalar);
896  Push(s);
897  }
898 
899 
905  void Calculator::Push(Buffer &buff) {
906  QVector<double> b(buff.size());
907 
908  for (int i = 0; i < buff.size(); i++) {
909  // Test for special pixels and map them to valid values
910  if (IsSpecial(buff[i])) {
911  if (Isis::IsNullPixel(buff[i])) {
912  //b[i] = NAN;
913  b[i] = sqrt(-1.0);
914  }
915  else if (Isis::IsHrsPixel(buff[i])) {
916  //b[i] = INFINITY;
917  b[i] = DBL_MAX * 2;
918  }
919  else if (Isis::IsHisPixel(buff[i])) {
920  //b[i] = INFINITY;
921  b[i] = DBL_MAX * 2;
922  }
923  else if (Isis::IsLrsPixel(buff[i])) {
924  //b[i] = -INFINITY;
925  b[i] = -DBL_MAX * 2;
926  }
927  else if (Isis::IsLisPixel(buff[i])) {
928  //b[i] = -INFINITY;
929  b[i] = -DBL_MAX * 2;
930  }
931  }
932  else
933  b[i] = buff[i];
934  }
935 
936  Push(b);
937  }
938 
939 
949  QVector<double> Calculator::Pop(bool keepSpecials) {
950  QVector<double> top;
951 
952  if (p_valStack->empty()) {
953  IString msg = "Math calculator stack is empty, cannot perform any "
954  "more operations.";
955  throw IException(IException::Unknown, msg, _FILEINFO_);
956  }
957 
958  top = p_valStack->top();
959 
960  if (keepSpecials) {
961  for (int i = 0; i < (int)top.size(); i++) {
962  if (std::isnan(top[i])) {
963  top[i] = Isis::Null;
964  }
965  // Test for +INFINITY
966  else if (top[i] > DBL_MAX) {
967  top[i] = Isis::Hrs;
968  }
969  // Test for -INFINITY)
970  else if (top[i] < -DBL_MAX) {
971  top[i] = Isis::Lrs;
972  }
973  else {
974  // Do nothing
975  }
976  }
977  }
978 
979  p_valStack->pop();
980 
981 
982  return top;
983  }
984 
985 
989  void Calculator::PrintTop() {
990  if (p_valStack->empty()) return;
991 
992  QString temp;
993  temp += "[ ";
994  QVector<double> top = p_valStack->top();
995  for (int i = 0; i < (int)top.size(); i++) {
996  temp += QString::number(top[i]);
997  temp += " ";
998  }
999  temp += "]";
1000  // On some operating systems, -nan was being outputted.
1001  // Because this method is only used as a cout in our tests, we do not
1002  // care about the difference between nan and -nan; they are the same in this case.
1003  temp.replace(QRegExp("-nan"), "nan");
1004  std::cout<<temp<<std::endl;
1005  }
1006 
1007 
1013  bool Calculator::Empty() {
1014  return p_valStack->empty();
1015  }
1016 
1017 
1021  void Calculator::Clear() {
1022  while (!p_valStack->empty()) {
1023  p_valStack->pop();
1024  }
1025  }
1026 
1027 
1037  void Calculator::PerformOperation(QVector<double> &results,
1038  QVector<double>::iterator arg1Start,
1039  QVector<double>::iterator arg1End,
1040  double operation(double)) {
1041  results.resize(arg1End - arg1Start);
1042 
1043  for (int pos = 0; pos < results.size(); pos++) {
1044  results[pos] = operation(*arg1Start);
1045 
1046  arg1Start++;
1047  }
1048  }
1049 
1050 
1066  void Calculator::PerformOperation(QVector<double> &results,
1067  QVector<double>::iterator arg1Start,
1068  QVector<double>::iterator arg1End,
1069  QVector<double>::iterator arg2Start,
1070  QVector<double>::iterator arg2End,
1071  double operation(double, double)) {
1072  if (arg1End - arg1Start != 1 && arg2End - arg2Start != 1 &&
1073  arg1End - arg1Start != arg2End - arg2Start) {
1074  IString msg = "The stack based calculator cannot operate on vectors "
1075  "of differing sizes.";
1076  throw IException(IException::Programmer, msg, _FILEINFO_);
1077  }
1078 
1079  int iSize = max(arg1End - arg1Start, arg2End - arg2Start);
1080  results.resize(iSize);
1081 
1082  for (int pos = 0; pos < results.size(); pos++) {
1083  results[pos] = operation(*arg1Start, *arg2Start);
1084 
1085  if (arg1Start + 1 != arg1End) arg1Start++;
1086  if (arg2Start + 1 != arg2End) arg2Start++;
1087  }
1088  }
1089 } // End of namespace Isis
Isis::CosecantOperator
double CosecantOperator(double a)
Returns the cosecant of the input a.
Definition: Calculator.cpp:195
QStack
This is free and unencumbered software released into the public domain.
Definition: Calculator.h:17
Isis::ModulusOperator
double ModulusOperator(double a, double b)
Returns the modulus of a by b.
Definition: Calculator.cpp:269
Isis::CotangentOperator
double CotangentOperator(double a)
Returns the cotangent of the input a.
Definition: Calculator.cpp:218
Isis::IsNullPixel
bool IsNullPixel(const double d)
Returns if the input pixel is null.
Definition: SpecialPixel.h:235
Isis::IsHrsPixel
bool IsHrsPixel(const double d)
Returns if the input pixel is high representation saturation.
Definition: SpecialPixel.h:271
Isis::LessThanOperator
double LessThanOperator(double a, double b)
Returns 1.0 if a is less than b.
Definition: Calculator.cpp:131
Isis::NegateOperator
double NegateOperator(double a)
Returns the nagative of the input parameter.
Definition: Calculator.cpp:53
Isis::GreaterThanOperator
double GreaterThanOperator(double a, double b)
Returns 1.0 if a is greater than b.
Definition: Calculator.cpp:118
Isis::IsSpecial
bool IsSpecial(const double d)
Returns if the input pixel is special.
Definition: SpecialPixel.h:197
Isis::BitwiseAndOperator
double BitwiseAndOperator(double a, double b)
Returns the result of a bitwise AND accross a and b.
Definition: Calculator.cpp:243
Isis::GreaterThanOrEqualOperator
double GreaterThanOrEqualOperator(double a, double b)
Returns 1.0 if a is greater than or equal to b.
Definition: Calculator.cpp:157
Isis::Hrs
const double Hrs
Value for an Isis High Representation Saturation pixel.
Definition: SpecialPixel.h:117
Isis::MaximumOperator
double MaximumOperator(double a, double b)
Returns the max of a and b.
Definition: Calculator.cpp:281
Isis::MinimumOperator
double MinimumOperator(double a, double b)
Returns the min of a and b.
Definition: Calculator.cpp:296
Isis::Buffer
Buffer for reading and writing cube data.
Definition: Buffer.h:53
Isis::Lrs
const double Lrs
Value for an Isis Low Representation Saturation pixel.
Definition: SpecialPixel.h:99
Isis::DivideOperator
double DivideOperator(double a, double b)
Returns the result of dividing a by b.
Definition: Calculator.cpp:79
Isis::BitwiseOrOperator
double BitwiseOrOperator(double a, double b)
Returns the result of a bitwise OR across a and b.
Definition: Calculator.cpp:256
Isis::Round
int Round(double a)
Returns the result of rounding the input a to the closest integer.
Definition: Calculator.cpp:230
Isis::SecantOperator
double SecantOperator(double a)
Returns the secant of the input a.
Definition: Calculator.cpp:207
Isis::MultiplyOperator
double MultiplyOperator(double a, double b)
Returns the result of a multiplied by b.
Definition: Calculator.cpp:66
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::IsLisPixel
bool IsLisPixel(const double d)
Returns if the input pixel is low instrument saturation.
Definition: SpecialPixel.h:295
Isis::IsLrsPixel
bool IsLrsPixel(const double d)
Returns if the input pixel is low representation saturation.
Definition: SpecialPixel.h:307
Isis::SubtractOperator
double SubtractOperator(double a, double b)
Returns the result of subtracting b from a.
Definition: Calculator.cpp:105
Isis::Null
const double Null
Value for an Isis Null pixel.
Definition: SpecialPixel.h:95
Isis::IsHisPixel
bool IsHisPixel(const double d)
Returns if the input pixel is high instrument saturation.
Definition: SpecialPixel.h:283
std
Namespace for the standard library.
Isis::AddOperator
double AddOperator(double a, double b)
Returns the result of additing a with b.
Definition: Calculator.cpp:92
Isis::Buffer::size
int size() const
Returns the total number of pixels in the shape buffer.
Definition: Buffer.h:97
Isis::IString
Adds specific functionality to C++ strings.
Definition: IString.h:165
QVector< double >
Isis::NotEqualOperator
double NotEqualOperator(double a, double b)
Returns 1.0 is a is not equal to b.
Definition: Calculator.cpp:183
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::EqualOperator
double EqualOperator(double a, double b)
Returns 1.0 if a is equal ot b.
Definition: Calculator.cpp:144
Isis::LessThanOrEqualOperator
double LessThanOrEqualOperator(double a, double b)
Returns 1.0 if a is less than or eqaul to b.
Definition: Calculator.cpp:170