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
19using namespace std;
20
21namespace Isis {
33 p_valStack = NULL;
34
35 p_valStack = new QStack< QVector<double> >();
36 }
37
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
308 QVector<double> result = Pop();
309 PerformOperation(result, result.begin(), result.end(), NegateOperator);
310 Push(result);
311 }
312
313
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
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
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
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
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
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
398 QVector<double> result = Pop();
399 PerformOperation(result, result.begin(), result.end(), sqrt);
400 Push(result);
401 }
402
403
408 QVector<double> result = Pop();
409 PerformOperation(result, result.begin(), result.end(), fabs);
410 Push(result);
411 }
412
413
420 QVector<double> result = Pop();
421 PerformOperation(result, result.begin(), result.end(), log);
422 Push(result);
423 }
424
425
430 QVector<double> result = Pop();
431 PerformOperation(result, result.begin(), result.end(), log10);
432 Push(result);
433 }
434
435
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
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
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
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
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
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
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
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
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(),
624 Push(result);
625 }
626
627
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
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
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
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
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
708 QVector<double> result = Pop();
709 PerformOperation(result, result.begin(), result.end(), sin);
710 Push(result);
711 }
712
713
718 QVector<double> result = Pop();
719 PerformOperation(result, result.begin(), result.end(), cos);
720 Push(result);
721 }
722
723
728 QVector<double> result = Pop();
729 PerformOperation(result, result.begin(), result.end(), tan);
730 Push(result);
731 }
732
733
738 QVector<double> result = Pop();
739 PerformOperation(result, result.begin(), result.end(), CosecantOperator);
740 Push(result);
741 }
742
743
748 QVector<double> result = Pop();
749 PerformOperation(result, result.begin(), result.end(), SecantOperator);
750 Push(result);
751 }
752
753
758 QVector<double> result = Pop();
759 PerformOperation(result, result.begin(), result.end(), CotangentOperator);
760 Push(result);
761 }
762
763
768 QVector<double> result = Pop();
769 PerformOperation(result, result.begin(), result.end(), asin);
770 Push(result);
771 }
772
773
778 QVector<double> result = Pop();
779 PerformOperation(result, result.begin(), result.end(), acos);
780 Push(result);
781 }
782
783
788 QVector<double> result = Pop();
789 PerformOperation(result, result.begin(), result.end(), atan);
790 Push(result);
791 }
792
793
798 QVector<double> result = Pop();
799 PerformOperation(result, result.begin(), result.end(), asinh);
800 Push(result);
801 }
802
803
808 QVector<double> result = Pop();
809 PerformOperation(result, result.begin(), result.end(), acosh);
810 Push(result);
811 }
812
813
818 QVector<double> result = Pop();
819 PerformOperation(result, result.begin(), result.end(), atanh);
820 Push(result);
821 }
822
823
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
841 QVector<double> result = Pop();
842 PerformOperation(result, result.begin(), result.end(), sinh);
843 Push(result);
844 }
845
846
851 QVector<double> result = Pop();
852 PerformOperation(result, result.begin(), result.end(), cosh);
853 Push(result);
854 }
855
856
861 QVector<double> result = Pop();
862 PerformOperation(result, result.begin(), result.end(), tanh);
863 Push(result);
864 }
865
866
867 // Stack methods
868
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
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
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
1014 return p_valStack->empty();
1015 }
1016
1017
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,
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,
1069 QVector<double>::iterator arg2Start,
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
Buffer for reading and writing cube data.
Definition Buffer.h:53
void LessThan()
Pop two elements off the stack and compare them to see where one is less than the other,...
void PrintTop()
Print the vector at the top of the stack.
void Cosecant()
Pops one element and push the cosecant.
void Arctangent2()
Pops two elements and push the arctangent.
void Modulus()
Pops two elements, mods them, then pushes the result on the stack.
void Tangent()
Pops one element and push the tangent.
int StackSize()
Returns the current stack size.
void Arctangent()
Pops one element and push the arctangent.
void SineH()
Pops one element and push the hyperbolic sine.
void Divide()
Pops two, divides them, then pushes the quotient on the stack.
void GreaterThanOrEqual()
Pop two elements off the stack and compare them to see where one is greater than or equal to the othe...
void TangentH()
Pops one element and push the hyperbolic tangent.
void Push(double scalar)
Push a scalar onto the stack.
void Cotangent()
Pops one element and push the cotangent.
void ArctangentH()
Pops one element and push the inverse hyperbolic tangent.
Calculator()
The code that performs math operations is designed to call a function and use the result.
void Add()
Pops two elements, adds them, then pushes the sum on the stack.
void Multiply()
Pops two elements, multiplies them, then pushes the product on the stack.
void ArcsineH()
Pops one element and push the inverse hyperbolic sine.
QStack< QVector< double > > * p_valStack
The current stack of arguments.
Definition Calculator.h:135
void Negative()
Pops an element, negates it, then pushes the result.
virtual ~Calculator()
Virtual Constructor.
void RightShift()
Pop the top element, then perform a right shift with zero fill.
void Or()
Pop two elements, OR them, then push the result on the stack.
void Sine()
Pops one element and push the sine.
virtual void Clear()
Clear out the stack.
void PerformOperation(QVector< double > &results, QVector< double >::iterator arg1Start, QVector< double >::iterator arg1End, double operation(double))
Performs the mathematical operations on each argument.
void Arcsine()
Pops one element and push the arcsine.
void LeftShift()
Pop the top element, then perform a left shift with zero fill.
void LessThanOrEqual()
Pop two elements off the stack and compare them to see where one is less than or equal to the other,...
void NotEqual()
Pop two elements off the stack and compare them to see where one is not equal to the other,...
void GreaterThan()
Pop two elements off the stack and compare them to see where one is greater than the other,...
void Arccosine()
Pops one element and push the arccosine.
void Log10()
Pop an element, compute its base 10 log, then push the result on the stack.
void MaximumLine()
Pop one element, then push the maximum on the stack.
void MaximumPixel()
Pop two elements, then push the maximum on a pixel by pixel basis back on the stack.
void Secant()
Pops one element and push the secant.
void MinimumLine()
Pop one element, then push the minimum on the stack.
void Log()
Pop an element, compute its log, then push the result on the stack.
void Subtract()
Pops two elements, subtracts them, then pushes the difference on the stack.
void Equal()
Pop two elements off the stack and compare them to see where one is equal to the other,...
QVector< double > Pop(bool keepSpecials=false)
Pop an element off the stack.
void AbsoluteValue()
Pop an element, compute its absolute value, then push the result on the stack.
void MinimumPixel()
Pop two elements, then push the minimum on a pixel by pixel basis back on the stack.
void Exponent()
Pops two elements, computes the power then pushes the result on the stack The exponent has to be a sc...
void ArccosineH()
Pops one element and push the inverse hyperbolic cosine.
void And()
Pop two elements, AND them, then push the result on the stack.
void SquareRoot()
Pop an element, compute its square root, then push the root on the stack.
void Cosine()
Pops one element and push the cosine.
bool Empty()
Check if the stack is empty.
void CosineH()
Pops one element and push the hyperbolic cosine.
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
Adds specific functionality to C++ strings.
Definition IString.h:165
This is free and unencumbered software released into the public domain.
Definition Calculator.h:18
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
double SecantOperator(double a)
Returns the secant of the input a.
const double Hrs
Value for an Isis High Representation Saturation pixel.
double AddOperator(double a, double b)
Returns the result of additing a with b.
double CosecantOperator(double a)
Returns the cosecant of the input a.
double ModulusOperator(double a, double b)
Returns the modulus of a by b.
bool IsLrsPixel(const double d)
Returns if the input pixel is low representation saturation.
double MultiplyOperator(double a, double b)
Returns the result of a multiplied by b.
bool IsNullPixel(const double d)
Returns if the input pixel is null.
bool IsHrsPixel(const double d)
Returns if the input pixel is high representation saturation.
double GreaterThanOrEqualOperator(double a, double b)
Returns 1.0 if a is greater than or equal to b.
double DivideOperator(double a, double b)
Returns the result of dividing a by b.
double NotEqualOperator(double a, double b)
Returns 1.0 is a is not equal to b.
double EqualOperator(double a, double b)
Returns 1.0 if a is equal ot b.
double SubtractOperator(double a, double b)
Returns the result of subtracting b from a.
double CotangentOperator(double a)
Returns the cotangent of the input a.
double BitwiseOrOperator(double a, double b)
Returns the result of a bitwise OR across a and b.
const double Null
Value for an Isis Null pixel.
bool IsHisPixel(const double d)
Returns if the input pixel is high instrument saturation.
const double Lrs
Value for an Isis Low Representation Saturation pixel.
double BitwiseAndOperator(double a, double b)
Returns the result of a bitwise AND accross a and b.
double NegateOperator(double a)
Returns the nagative of the input parameter.
double LessThanOperator(double a, double b)
Returns 1.0 if a is less than b.
double LessThanOrEqualOperator(double a, double b)
Returns 1.0 if a is less than or eqaul to b.
bool IsSpecial(const double d)
Returns if the input pixel is special.
double MinimumOperator(double a, double b)
Returns the min of a and b.
double GreaterThanOperator(double a, double b)
Returns 1.0 if a is greater than b.
bool IsLisPixel(const double d)
Returns if the input pixel is low instrument saturation.
double MaximumOperator(double a, double b)
Returns the max of a and b.
int Round(double a)
Returns the result of rounding the input a to the closest integer.
Namespace for the standard library.