Commit 1f890b9b authored by T.J. Corona's avatar T.J. Corona
Browse files

Added unary plus and fixed scientific notation bug in vtkFunctionParser

This fix is in reference to bug report 0015557. Originally, the expression
'3.0e+01' was being evaluated as '3.0e1 + 1 = 31'. It now behaves correctly.
Additionally, a unary plus operator has been added to the general case
(previously, the inclusion of a unary plus resulted in an error). The test
program for vtkFunctionParser has been updated to include unary plus tests
and a scientific notation test.
parent a1fdb774
......@@ -97,6 +97,8 @@ SCALAR_FUNC(TestSqrt,sqrt,std::sqrt);
SCALAR_FUNC(TestTan,tan,std::tan);
SCALAR_FUNC(TestTanh,tanh,std::tanh);
static int TestScalars();
static int TestUnaryOperations();
static int TestScientificNotation();
static int TestVectors();
static int TestMinMax();
static int TestScalarLogic();
......@@ -127,6 +129,8 @@ int UnitTestFunctionParser(int,char *[])
status += TestTanh(-1.0, 1.0);
status += TestScalars();
status += TestUnaryOperations();
status += TestScientificNotation();
status += TestVectors();
status += TestMinMax();
status += TestScalarLogic();
......@@ -148,6 +152,56 @@ int UnitTestFunctionParser(int,char *[])
return EXIT_SUCCESS;
}
int TestUnaryOperations()
{
std::cout << "Testing Scalar Unary" << "...";
std::string formula[4] = {
"-x * +y",
"+x + +y",
"+x - -y",
"-x - +y"};
double expected[4] = {-2.,3.,3.,-3.};
vtkSmartPointer<vtkFunctionParser> parser =
vtkSmartPointer<vtkFunctionParser>::New();
parser->SetScalarVariableValue("x", 1.0);
parser->SetScalarVariableValue("y", 2.0);
for (unsigned i=0;i<4;i++)
{
parser->SetFunction(&formula[i][0]);
double result = parser->GetScalarResult();
if (!vtkMathUtilities::FuzzyCompare(
result, expected[i],
std::numeric_limits<double>::epsilon() * 1.0))
{
std::cout << "FAILED\n";
return 1;
}
}
parser->SetScalarVariableValue("x", 3);
parser->SetScalarVariableValue("y", 2);
parser->SetFunction("-x ^ +y");
int result = parser->GetScalarResult();
std::cout<<"result: "<<result<<std::endl;
if (result != 9)
{
std::cout << "FAILED\n";
return 1;
}
parser->SetFunction("(-x)");
result = parser->GetScalarResult();
if (result != -3)
{
std::cout << "FAILED\n";
return 1;
}
std::cout << "PASSED\n";
return 0;
}
int TestScalars()
{
std::cout << "Testing Scalar Add / Subtract / Multiply / Divide" << "...";
......@@ -155,7 +209,7 @@ int TestScalars()
vtkSmartPointer<vtkFunctionParser>::New();
parser->SetScalarVariableValue("x", 1.0);
parser->SetScalarVariableValue("y", 2.0);
parser->SetFunction( "(x-y)/(x-y) * -(x-y)/(x-y) + (x - x)");
parser->SetFunction( "+(x-y)/(x-y) * -(x-y)/(x-y) + (x - x)");
double result = parser->GetScalarResult();
if (result != -1.0)
{
......@@ -169,6 +223,32 @@ int TestScalars()
}
}
int TestScientificNotation()
{
std::cout << "Testing Scientific notation" << "...";
vtkSmartPointer<vtkFunctionParser> parser =
vtkSmartPointer<vtkFunctionParser>::New();
parser->SetFunction( "3.0e+01");
double expected = 3.0e+01;
double result = parser->GetScalarResult();
if (!vtkMathUtilities::FuzzyCompare(
result, expected,
std::numeric_limits<double>::epsilon() * 1.0))
{
std::cout << " Scientific notation expected " << expected
<< " but got " << result;
std::cout << "eps ratio is: " << (result - expected)
/ std::numeric_limits<double>::epsilon() << std::endl;
std::cout << "FAILED\n";
return 1;
}
else
{
std::cout << "PASSED\n";
return 0;
}
}
int TestVectors()
{
std::cout << "Testing Cross" << "...";
......
......@@ -171,6 +171,7 @@ int vtkFunctionParser::Parse()
// - scalar/vector +
// - scalar/vector -
// - scalar/vector unary minus
// - scalar/vector unary plus
// - * (2 scalars) or scalar multiple (scalar, vector)
result = this->DisambiguateOperators();
if (!result)
......@@ -229,6 +230,12 @@ int vtkFunctionParser::DisambiguateOperators()
this->ByteCode[i] = VTK_PARSER_VECTOR_UNARY_MINUS;
}
break;
case VTK_PARSER_UNARY_PLUS:
if (tempStack[tempStackPtr] != 0)
{
this->ByteCode[i] = VTK_PARSER_VECTOR_UNARY_PLUS;
}
break;
case VTK_PARSER_ADD:
if (tempStack[tempStackPtr] != 0 && tempStack[tempStackPtr-1] != 0)
{
......@@ -487,6 +494,8 @@ bool vtkFunctionParser::Evaluate()
case VTK_PARSER_UNARY_MINUS:
this->Stack[stackPosition] = -(this->Stack[stackPosition]);
break;
case VTK_PARSER_UNARY_PLUS:
break;
case VTK_PARSER_ADD:
this->Stack[stackPosition-1] += this->Stack[stackPosition];
stackPosition--;
......@@ -724,6 +733,8 @@ bool vtkFunctionParser::Evaluate()
this->Stack[stackPosition-1] = -this->Stack[stackPosition-1];
this->Stack[stackPosition-2] = -this->Stack[stackPosition-2];
break;
case VTK_PARSER_VECTOR_UNARY_PLUS:
break;
case VTK_PARSER_DOT_PRODUCT:
this->Stack[stackPosition-3] *= this->Stack[stackPosition];
this->Stack[stackPosition-4] *= this->Stack[stackPosition-1];
......@@ -1427,11 +1438,21 @@ void vtkFunctionParser::BuildInternalSubstringStructure(int beginIndex,
this->AddInternalByte(VTK_PARSER_UNARY_MINUS);
return;
}
if (this->GetMathConstantNumber(beginIndex+1) > 0 &&
this->FindEndOfMathConstant(beginIndex+1) == endIndex)
}
if (this->Function[beginIndex] == '+')
{
if (this->IsSubstringCompletelyEnclosed(beginIndex+1, endIndex))
{
this->BuildInternalSubstringStructure(beginIndex+2, endIndex-1);
this->AddInternalByte(VTK_PARSER_UNARY_PLUS);
return;
}
if (this->GetMathFunctionNumber(beginIndex+1) > 0 &&
this->FindEndOfMathFunction(beginIndex+1) == endIndex)
{
this->BuildInternalSubstringStructure(beginIndex+1, endIndex);
this->AddInternalByte(VTK_PARSER_UNARY_MINUS);
this->AddInternalByte(VTK_PARSER_UNARY_PLUS);
return;
}
}
......@@ -1539,7 +1560,7 @@ void vtkFunctionParser::BuildInternalSubstringStructure(int beginIndex,
if (parenthesisCount == 0 &&
// arithmetic or boolean
this->Function[i] == elementaryMathOps[opNum] &&
!(this->Function[i] == '-' &&
!((this->Function[i] == '-' || this->Function[i] == '+') &&
(this->IsElementaryOperator(this->Function[i-1]) ||
this->Function[i-1] == '(' ||
(this->Function[i-1] == 'e' && i > 1 &&
......@@ -1560,8 +1581,12 @@ void vtkFunctionParser::BuildInternalSubstringStructure(int beginIndex,
} // end of for (opNum = 0; opNum < numMathOps; opNum++)
beginIndex2 = beginIndex;
if (this->Function[beginIndex] == '-')
bool unaryMinus = false;
if (this->Function[beginIndex] == '-' ||
this->Function[beginIndex] == '+')
{
if (this->Function[beginIndex] == '-')
unaryMinus = true;
beginIndex2++;
}
......@@ -1574,7 +1599,10 @@ void vtkFunctionParser::BuildInternalSubstringStructure(int beginIndex,
}
if (beginIndex2 > beginIndex)
{
this->AddInternalByte(VTK_PARSER_UNARY_MINUS);
if (unaryMinus)
this->AddInternalByte(VTK_PARSER_UNARY_MINUS);
else
this->AddInternalByte(VTK_PARSER_UNARY_PLUS);
}
}
......@@ -2172,6 +2200,21 @@ void vtkFunctionParser::CheckExpression(int &pos, char **error)
}
}
// Check for leading +
if (currentChar == '+')
{
currentChar = this->Function[++index];
if(index == this->FunctionLength)
{
this->ParseErrorPositon = this->FindPositionInOriginalFunction(index);
this->SetParseError("Syntax error: unary plus with no operand");
this->CopyParseError(pos, error);
delete [] expectCommaOnParenthesisCount;
delete [] expectTwoCommasOnParenthesisCount;
return;
}
}
// Check for math function
if ((functionNumber = this->GetMathFunctionNumberByCheckingParenthesis(index)))
{
......
......@@ -46,76 +46,78 @@
#define VTK_PARSER_IMMEDIATE 1
#define VTK_PARSER_UNARY_MINUS 2
#define VTK_PARSER_UNARY_PLUS 3
// supported math functions
#define VTK_PARSER_ADD 3
#define VTK_PARSER_SUBTRACT 4
#define VTK_PARSER_MULTIPLY 5
#define VTK_PARSER_DIVIDE 6
#define VTK_PARSER_POWER 7
#define VTK_PARSER_ABSOLUTE_VALUE 8
#define VTK_PARSER_EXPONENT 9
#define VTK_PARSER_CEILING 10
#define VTK_PARSER_FLOOR 11
#define VTK_PARSER_LOGARITHM 12
#define VTK_PARSER_LOGARITHME 13
#define VTK_PARSER_LOGARITHM10 14
#define VTK_PARSER_SQUARE_ROOT 15
#define VTK_PARSER_SINE 16
#define VTK_PARSER_COSINE 17
#define VTK_PARSER_TANGENT 18
#define VTK_PARSER_ARCSINE 19
#define VTK_PARSER_ARCCOSINE 20
#define VTK_PARSER_ARCTANGENT 21
#define VTK_PARSER_HYPERBOLIC_SINE 22
#define VTK_PARSER_HYPERBOLIC_COSINE 23
#define VTK_PARSER_HYPERBOLIC_TANGENT 24
#define VTK_PARSER_MIN 25
#define VTK_PARSER_MAX 26
#define VTK_PARSER_SIGN 28
#define VTK_PARSER_ADD 4
#define VTK_PARSER_SUBTRACT 5
#define VTK_PARSER_MULTIPLY 6
#define VTK_PARSER_DIVIDE 7
#define VTK_PARSER_POWER 8
#define VTK_PARSER_ABSOLUTE_VALUE 9
#define VTK_PARSER_EXPONENT 10
#define VTK_PARSER_CEILING 11
#define VTK_PARSER_FLOOR 12
#define VTK_PARSER_LOGARITHM 13
#define VTK_PARSER_LOGARITHME 14
#define VTK_PARSER_LOGARITHM10 15
#define VTK_PARSER_SQUARE_ROOT 16
#define VTK_PARSER_SINE 17
#define VTK_PARSER_COSINE 18
#define VTK_PARSER_TANGENT 19
#define VTK_PARSER_ARCSINE 20
#define VTK_PARSER_ARCCOSINE 21
#define VTK_PARSER_ARCTANGENT 22
#define VTK_PARSER_HYPERBOLIC_SINE 23
#define VTK_PARSER_HYPERBOLIC_COSINE 24
#define VTK_PARSER_HYPERBOLIC_TANGENT 25
#define VTK_PARSER_MIN 26
#define VTK_PARSER_MAX 27
#define VTK_PARSER_SIGN 29
// functions involving vectors
#define VTK_PARSER_CROSS 27
#define VTK_PARSER_VECTOR_UNARY_MINUS 29
#define VTK_PARSER_DOT_PRODUCT 30
#define VTK_PARSER_VECTOR_ADD 31
#define VTK_PARSER_VECTOR_SUBTRACT 32
#define VTK_PARSER_SCALAR_TIMES_VECTOR 33
#define VTK_PARSER_VECTOR_TIMES_SCALAR 34
#define VTK_PARSER_VECTOR_OVER_SCALAR 35
#define VTK_PARSER_MAGNITUDE 36
#define VTK_PARSER_NORMALIZE 37
#define VTK_PARSER_CROSS 28
#define VTK_PARSER_VECTOR_UNARY_MINUS 30
#define VTK_PARSER_VECTOR_UNARY_PLUS 31
#define VTK_PARSER_DOT_PRODUCT 32
#define VTK_PARSER_VECTOR_ADD 33
#define VTK_PARSER_VECTOR_SUBTRACT 34
#define VTK_PARSER_SCALAR_TIMES_VECTOR 35
#define VTK_PARSER_VECTOR_TIMES_SCALAR 36
#define VTK_PARSER_VECTOR_OVER_SCALAR 37
#define VTK_PARSER_MAGNITUDE 38
#define VTK_PARSER_NORMALIZE 39
// constants involving vectors
#define VTK_PARSER_IHAT 38
#define VTK_PARSER_JHAT 39
#define VTK_PARSER_KHAT 40
#define VTK_PARSER_IHAT 40
#define VTK_PARSER_JHAT 41
#define VTK_PARSER_KHAT 42
// code for if(bool, trueval, falseval) resulting in a scalar
#define VTK_PARSER_IF 41
#define VTK_PARSER_IF 43
// code for if(bool, truevec, falsevec) resulting in a vector
#define VTK_PARSER_VECTOR_IF 42
#define VTK_PARSER_VECTOR_IF 44
// codes for boolean expressions
#define VTK_PARSER_LESS_THAN 43
#define VTK_PARSER_LESS_THAN 45
// codes for boolean expressions
#define VTK_PARSER_GREATER_THAN 44
#define VTK_PARSER_GREATER_THAN 46
// codes for boolean expressions
#define VTK_PARSER_EQUAL_TO 45
#define VTK_PARSER_EQUAL_TO 47
// codes for boolean expressions
#define VTK_PARSER_AND 46
#define VTK_PARSER_AND 48
// codes for boolean expressions
#define VTK_PARSER_OR 47
#define VTK_PARSER_OR 49
// codes for scalar variables come before those for vectors. Do not define
// values for VTK_PARSER_BEGIN_VARIABLES+1, VTK_PARSER_BEGIN_VARIABLES+2, ...,
// because they are used to look up variables numbered 1, 2, ...
#define VTK_PARSER_BEGIN_VARIABLES 48
#define VTK_PARSER_BEGIN_VARIABLES 50
// the value that is retuned as a result if there is an error
#define VTK_PARSER_ERROR_RESULT VTK_FLOAT_MAX
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment