1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkExprTkFunctionParser.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkExprTkFunctionParser.h"
16 #include "vtkObjectFactory.h"
17
18 #include <algorithm>
19 #include <cctype>
20 #include <random>
21 #include <regex>
22
23 // exprtk macros
24 #define exprtk_disable_string_capabilities
25 #define exprtk_disable_rtl_io_file
26 #define exprtk_disable_caseinsensitivity
27 #include "vtk_exprtk.h"
28 #include "vtksys/SystemTools.hxx"
29
30 using ExprTkResultType = exprtk::results_context<double>::type_store_t::store_type;
31
32 /**
33 * Implementation of vtkExprTkTools
34 */
35 struct vtkExprTkTools
36 {
37 exprtk::symbol_table<double> SymbolTable;
38 exprtk::expression<double> Expression;
39 exprtk::parser<double> Parser;
40 };
41
42 /**
43 * Implementation of the magnitude function
44 */
45 template <typename T>
46 class mag : public exprtk::igeneric_function<T>
47 {
48 public:
49 typedef typename exprtk::igeneric_function<T> igfun_t;
50 typedef typename igfun_t::parameter_list_t parameter_list_t;
51 typedef typename igfun_t::generic_type generic_type;
52 typedef typename generic_type::scalar_view scalar_t;
53 typedef typename generic_type::vector_view vector_t;
54
55 using exprtk::igeneric_function<T>::operator();
56
mag()57 mag()
58 : exprtk::igeneric_function<T>("V|VTT")
59 /*
60 Overloads:
61 0. V - x(vector)
62 1. VTT - x(vector), r0, r1
63 */
64 {
65 }
66
operator ()(const std::size_t & ps_index,parameter_list_t parameters)67 inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) override
68 {
69 const vector_t x(parameters[0]);
70
71 std::size_t r0 = 0;
72 std::size_t r1 = x.size() - 1;
73
74 if ((1 == ps_index) &&
75 !exprtk::rtl::vecops::helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0))
76 {
77 return std::numeric_limits<T>::quiet_NaN();
78 }
79 else if (exprtk::rtl::vecops::helper::invalid_range(x, r0, r1))
80 {
81 return std::numeric_limits<T>::quiet_NaN();
82 }
83
84 T result = T(0);
85
86 for (std::size_t i = r0; i <= r1; ++i)
87 {
88 result += (x[i] * x[i]);
89 }
90 result = std::sqrt(result);
91
92 return result;
93 }
94 };
95
96 /**
97 * Implementation of the x element of cross product function
98 */
99 template <typename T>
100 class crossX : public exprtk::igeneric_function<T>
101 {
102 public:
103 typedef typename exprtk::igeneric_function<T> igfun_t;
104 typedef typename igfun_t::parameter_list_t parameter_list_t;
105 typedef typename igfun_t::generic_type generic_type;
106 typedef typename generic_type::scalar_view scalar_t;
107 typedef typename generic_type::vector_view vector_t;
108
109 using exprtk::igeneric_function<T>::operator();
110
crossX()111 crossX()
112 : exprtk::igeneric_function<T>("VV|VVTT")
113 /*
114 Overloads:
115 0. VV - x(vector), y(vector)
116 1. VVTT - x(vector), y(vector), r0, r1
117 */
118 {
119 }
120
operator ()(const std::size_t & ps_index,parameter_list_t parameters)121 inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) override
122 {
123 const vector_t x(parameters[0]);
124 const vector_t y(parameters[1]);
125
126 std::size_t r0 = 0;
127 std::size_t r1 = std::min(x.size(), y.size()) - 1;
128
129 if ((1 == ps_index) &&
130 !exprtk::rtl::vecops::helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0))
131 {
132 return std::numeric_limits<T>::quiet_NaN();
133 }
134 else if (exprtk::rtl::vecops::helper::invalid_range(y, r0, r1))
135 {
136 return std::numeric_limits<T>::quiet_NaN();
137 }
138
139 T result = x[1] * y[2] - x[2] * y[1];
140
141 return result;
142 }
143 };
144
145 /**
146 * Implementation of the y element of cross product function
147 */
148 template <typename T>
149 class crossY : public exprtk::igeneric_function<T>
150 {
151 public:
152 typedef typename exprtk::igeneric_function<T> igfun_t;
153 typedef typename igfun_t::parameter_list_t parameter_list_t;
154 typedef typename igfun_t::generic_type generic_type;
155 typedef typename generic_type::scalar_view scalar_t;
156 typedef typename generic_type::vector_view vector_t;
157
158 using exprtk::igeneric_function<T>::operator();
159
crossY()160 crossY()
161 : exprtk::igeneric_function<T>("VV|VVTT")
162 /*
163 Overloads:
164 0. VV - x(vector), y(vector)
165 1. VVTT - x(vector), y(vector), r0, r1
166 */
167 {
168 }
169
operator ()(const std::size_t & ps_index,parameter_list_t parameters)170 inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) override
171 {
172 const vector_t x(parameters[0]);
173 const vector_t y(parameters[1]);
174
175 std::size_t r0 = 0;
176 std::size_t r1 = std::min(x.size(), y.size()) - 1;
177
178 if ((1 == ps_index) &&
179 !exprtk::rtl::vecops::helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0))
180 {
181 return std::numeric_limits<T>::quiet_NaN();
182 }
183 else if (exprtk::rtl::vecops::helper::invalid_range(y, r0, r1))
184 {
185 return std::numeric_limits<T>::quiet_NaN();
186 }
187
188 T result = x[2] * y[0] - x[0] * y[2];
189
190 return result;
191 }
192 };
193
194 /**
195 * Implementation of the z element of cross product function
196 */
197 template <typename T>
198 class crossZ : public exprtk::igeneric_function<T>
199 {
200 public:
201 typedef typename exprtk::igeneric_function<T> igfun_t;
202 typedef typename igfun_t::parameter_list_t parameter_list_t;
203 typedef typename igfun_t::generic_type generic_type;
204 typedef typename generic_type::scalar_view scalar_t;
205 typedef typename generic_type::vector_view vector_t;
206
207 using exprtk::igeneric_function<T>::operator();
208
crossZ()209 crossZ()
210 : exprtk::igeneric_function<T>("VV|VVTT")
211 /*
212 Overloads:
213 0. VV - x(vector), y(vector)
214 1. VVTT - x(vector), y(vector), r0, r1
215 */
216 {
217 }
218
operator ()(const std::size_t & ps_index,parameter_list_t parameters)219 inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) override
220 {
221 const vector_t x(parameters[0]);
222 const vector_t y(parameters[1]);
223
224 std::size_t r0 = 0;
225 std::size_t r1 = std::min(x.size(), y.size()) - 1;
226
227 if ((1 == ps_index) &&
228 !exprtk::rtl::vecops::helper::load_vector_range<T>::process(parameters, r0, r1, 2, 3, 0))
229 {
230 return std::numeric_limits<T>::quiet_NaN();
231 }
232 else if (exprtk::rtl::vecops::helper::invalid_range(y, r0, r1))
233 {
234 return std::numeric_limits<T>::quiet_NaN();
235 }
236
237 T result = x[0] * y[1] - x[1] * y[0];
238
239 return result;
240 }
241 };
242
243 namespace
244 {
245 /**
246 * Implementation of sign function.
247 */
sign(double v)248 inline double sign(double v)
249 {
250 if (v == 0.)
251 {
252 return 0.;
253 }
254 else if (std::signbit(v))
255 {
256 return -1.;
257 }
258 else
259 {
260 return 1.;
261 }
262 }
263
264 // compile-time declaration of needed function/variables/vectors/packages
265 // these are useful to minimize the construction cost, especially when
266 // multiple instances of this class are instantiated
267 exprtk::rtl::vecops::package<double> vectorOperationsPackage;
268 std::vector<double> iHat = { 1, 0, 0 };
269 std::vector<double> jHat = { 0, 1, 0 };
270 std::vector<double> kHat = { 0, 0, 1 };
271 mag<double> magnitude;
272 crossX<double> crossXProduct;
273 crossY<double> crossYProduct;
274 crossZ<double> crossZProduct;
275
276 // the value that is returned as a result if there is an error
277 double vtkParserErrorResult = std::numeric_limits<double>::quiet_NaN();
278 double vtkParserVectorErrorResult[3] = { vtkParserErrorResult, vtkParserErrorResult,
279 vtkParserErrorResult };
280
281 //------------------------------------------------------------------------------
RemoveSpacesFrom(std::string str)282 std::string RemoveSpacesFrom(std::string str)
283 {
284 str.erase(remove_if(str.begin(), str.end(), isspace), str.end());
285 return str;
286 }
287
288 //------------------------------------------------------------------------------
HasEnding(const std::string & fullString,const std::string & ending)289 bool HasEnding(const std::string& fullString, const std::string& ending)
290 {
291 if (fullString.size() >= ending.size())
292 {
293 return (fullString.compare(fullString.size() - ending.size(), ending.size(), ending) == 0);
294 }
295 else
296 {
297 return false;
298 }
299 }
300
301 //------------------------------------------------------------------------------
GenerateRandomAlphabeticString(unsigned int len)302 std::string GenerateRandomAlphabeticString(unsigned int len)
303 {
304 static constexpr auto chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
305 "abcdefghijklmnopqrstuvwxyz";
306 auto rng = std::default_random_engine(std::random_device{}());
307 auto dist = std::uniform_int_distribution<int>(0, static_cast<int>(std::strlen(chars) - 1));
308 auto result = std::string(len, '\0');
309 std::generate_n(begin(result), len, [&]() { return chars[dist(rng)]; });
310
311 return result;
312 }
313
314 //------------------------------------------------------------------------------
GenerateUniqueVariableName(const std::vector<std::string> & variableNames,const std::string & variableName)315 std::string GenerateUniqueVariableName(
316 const std::vector<std::string>& variableNames, const std::string& variableName)
317 {
318 std::string sanitizedName = vtkExprTkFunctionParser::SanitizeName(variableName.c_str());
319 do
320 {
321 sanitizedName += GenerateRandomAlphabeticString(5);
322 } while (
323 std::find(variableNames.begin(), variableNames.end(), sanitizedName) != variableNames.end());
324
325 return sanitizedName;
326 }
327 }
328
329 vtkStandardNewMacro(vtkExprTkFunctionParser);
330
331 //------------------------------------------------------------------------------
vtkExprTkFunctionParser()332 vtkExprTkFunctionParser::vtkExprTkFunctionParser()
333 {
334 this->EvaluateMTime.Modified();
335 this->VariableMTime.Modified();
336 this->ParseMTime.Modified();
337 this->FunctionMTime.Modified();
338
339 this->ReplaceInvalidValues = 0;
340 this->ReplacementValue = 0.0;
341
342 this->ExprTkTools = new vtkExprTkTools;
343 // add vector support
344 this->ExprTkTools->SymbolTable.add_package(vectorOperationsPackage);
345 // add unit vectors
346 this->ExprTkTools->SymbolTable.add_vector("iHat", iHat);
347 this->ExprTkTools->SymbolTable.add_vector("jHat", jHat);
348 this->ExprTkTools->SymbolTable.add_vector("kHat", kHat);
349 // add ln and sign
350 this->ExprTkTools->SymbolTable.add_function("ln", std::log);
351 this->ExprTkTools->SymbolTable.add_function("sign", sign);
352 // add magnitude function
353 this->ExprTkTools->SymbolTable.add_function("mag", magnitude);
354 // add functions which are used to implement cross product
355 this->ExprTkTools->SymbolTable.add_function("crossX", crossXProduct);
356 this->ExprTkTools->SymbolTable.add_function("crossY", crossYProduct);
357 this->ExprTkTools->SymbolTable.add_function("crossZ", crossZProduct);
358 // register symbol table
359 this->ExprTkTools->Expression.register_symbol_table(this->ExprTkTools->SymbolTable);
360 // enable the collection of variables, which will be used in UpdateNeededVariables
361 this->ExprTkTools->Parser.dec().collect_variables() = true;
362 }
363
364 //------------------------------------------------------------------------------
~vtkExprTkFunctionParser()365 vtkExprTkFunctionParser::~vtkExprTkFunctionParser()
366 {
367 this->RemoveAllVariables();
368 delete this->ExprTkTools;
369 }
370
371 //------------------------------------------------------------------------------
SetFunction(const char * function)372 void vtkExprTkFunctionParser::SetFunction(const char* function)
373 {
374 // check if we have already set the same function string
375 if (!this->Function.empty() && function && this->Function == function)
376 {
377 return;
378 }
379
380 if (function)
381 {
382 this->Function = function;
383 this->FunctionWithUsedVariableNames = this->Function;
384 }
385 else
386 {
387 this->Function = std::string();
388 this->FunctionWithUsedVariableNames = std::string();
389 }
390
391 this->FunctionMTime.Modified();
392 this->ScalarVariableNeeded.clear();
393 this->VectorVariableNeeded.clear();
394 this->Modified();
395 }
396
397 //------------------------------------------------------------------------------
Parse(ParseMode mode)398 int vtkExprTkFunctionParser::Parse(ParseMode mode)
399 {
400 if (this->Function.empty())
401 {
402 vtkErrorMacro("Parse: no function has been set");
403 return 0;
404 }
405
406 // During the parsing of the first mode, perform the necessary changes in the function
407 if (mode == ParseMode::DetectReturnType)
408 {
409 // Before parsing, replace the original variable names in the function
410 // with the valid ones if needed.
411 for (size_t i = 0; i < this->OriginalScalarVariableNames.size(); ++i)
412 {
413 if (this->OriginalScalarVariableNames[i] != this->UsedScalarVariableNames[i])
414 {
415 vtksys::SystemTools::ReplaceString(this->FunctionWithUsedVariableNames,
416 this->OriginalScalarVariableNames[i], this->UsedScalarVariableNames[i]);
417 }
418 }
419 for (size_t i = 0; i < this->OriginalVectorVariableNames.size(); ++i)
420 {
421 if (this->OriginalVectorVariableNames[i] != this->UsedVectorVariableNames[i])
422 {
423 vtksys::SystemTools::ReplaceString(this->FunctionWithUsedVariableNames,
424 this->OriginalVectorVariableNames[i], this->UsedVectorVariableNames[i]);
425 }
426 }
427
428 // remove spaces to perform replacement for norm and cross
429 this->FunctionWithUsedVariableNames = RemoveSpacesFrom(this->FunctionWithUsedVariableNames);
430
431 // check for usage of old dot format product, e.g. (v1.v2) instead of dot(v1,v2)
432 if (this->CheckOldFormatOfDotProductUsage())
433 {
434 std::string oldDotUsageError =
435 "Warn: 0000 Type: [Old Usage] Msg: "
436 "Possible usage of old format of dot product v1.v2. Please use dot(v1,v2)."
437 "\tExpression: " +
438 this->Function + '\n';
439 vtkWarningMacro(<< oldDotUsageError);
440 }
441
442 // fix cross occurrences with something that ExprTk can understand
443 this->FunctionWithUsedVariableNames =
444 FixVectorReturningFunctionOccurrences(VectorReturningFunction::Cross);
445
446 // fix norm occurrences with something that ExprTk can understand
447 this->FunctionWithUsedVariableNames =
448 FixVectorReturningFunctionOccurrences(VectorReturningFunction::Norm);
449 }
450
451 if (mode == ParseMode::DetectReturnType)
452 {
453 // ExprTK, in order to extract vector and scalar results, and identify the result type,
454 // it requires to "return results" instead of just evaluating an expression
455 this->ExpressionString = "return [" + this->FunctionWithUsedVariableNames + "];";
456 }
457 else
458 {
459 // Since we know now the return type, we can assign the result to a result scalar/vector
460 std::string resultName = GenerateRandomAlphabeticString(10);
461 if (this->ResultType == ExprTkResultType::e_scalar)
462 {
463 this->ExprTkTools->SymbolTable.add_variable(resultName, this->Result[0]);
464 this->ExpressionString = resultName + " := " + this->FunctionWithUsedVariableNames + ";";
465 }
466 else
467 {
468 this->ExprTkTools->SymbolTable.add_vector(
469 resultName, this->Result.GetData(), this->Result.GetSize());
470 this->ExpressionString = resultName + " := [" + this->FunctionWithUsedVariableNames + "];";
471 }
472 }
473
474 bool parsingResult =
475 this->ExprTkTools->Parser.compile(this->ExpressionString, this->ExprTkTools->Expression);
476 // check parsing result
477 if (!parsingResult)
478 {
479 // print error only once
480 if (mode == ParseMode::DetectReturnType)
481 {
482 std::stringstream parsingErrorStream;
483 // save error
484 for (std::size_t i = 0; i < this->ExprTkTools->Parser.error_count(); ++i)
485 {
486 auto error = this->ExprTkTools->Parser.get_error(i);
487 parsingErrorStream << "Err: " << i << " Type: [" << exprtk::parser_error::to_str(error.mode)
488 << "] Msg: " << error.diagnostic << "\tExpression: " << this->Function
489 << "\n";
490 }
491 vtkErrorMacro(<< parsingErrorStream.str());
492 }
493
494 return 0;
495 }
496
497 if (mode == ParseMode::DetectReturnType)
498 {
499 // Collect meta-data about variables that are needed for evaluation of the
500 // function.
501 this->UpdateNeededVariables();
502 }
503 this->ParseMTime.Modified();
504 return 1;
505 }
506
FixVectorReturningFunctionOccurrences(VectorReturningFunction vectorReturningFunction)507 std::string vtkExprTkFunctionParser::FixVectorReturningFunctionOccurrences(
508 VectorReturningFunction vectorReturningFunction)
509 {
510 std::string desiredFunction;
511 std::string functionWithoutParenthesis;
512 if (vectorReturningFunction == VectorReturningFunction::Cross)
513 {
514 desiredFunction = "cross(";
515 functionWithoutParenthesis = "cross";
516 }
517 else
518 {
519 desiredFunction = "norm(";
520 functionWithoutParenthesis = "norm";
521 }
522
523 // collect all the variables that end with the desired function, e.g. mycross, m1cross
524 std::vector<std::string> variableNamesContainingFunction;
525 for (const auto& scalarVariable : this->UsedScalarVariableNames)
526 {
527 if (HasEnding(scalarVariable, functionWithoutParenthesis))
528 {
529 variableNamesContainingFunction.push_back(scalarVariable);
530 }
531 }
532 for (const auto& vectorVariable : this->UsedVectorVariableNames)
533 {
534 if (HasEnding(vectorVariable, functionWithoutParenthesis))
535 {
536 variableNamesContainingFunction.push_back(vectorVariable);
537 }
538 }
539 // sort vector by size to ensure that the largest variables names will be checked first
540 std::sort(variableNamesContainingFunction.begin(), variableNamesContainingFunction.end(),
541 [](const std::string& s1, const std::string& s2) -> bool { return s1.size() > s2.size(); });
542
543 static const std::string allowedChars = "01234565789.,()+-*/%^|&=<>!";
544 std::string::size_type pos = 0;
545 std::string function = this->FunctionWithUsedVariableNames;
546 while ((pos = function.find(desiredFunction, pos)) != std::string::npos)
547 {
548 // if we are not in the beginning
549 if (static_cast<int>(pos) - 1 != -1)
550 {
551 // check the found occurrence if it's part of a variable
552 // this check is required because the previous character could be a number
553 // and that is part of a variable name which includes cross, such m1cross
554 bool foundVariableOccurrence = false;
555 for (const auto& variable : variableNamesContainingFunction)
556 {
557 // check the size of the variable vs the function
558 if (variable.size() >= functionWithoutParenthesis.size())
559 {
560 const int sizeDifference =
561 static_cast<int>(variable.size() - functionWithoutParenthesis.size());
562 // check pos to not exceed the beginning
563 if (static_cast<int>(pos) - sizeDifference >= 0)
564 {
565 // check if occurrence match variable
566 if (function.substr(pos - sizeDifference, variable.size()) == variable)
567 {
568 foundVariableOccurrence = true;
569 break;
570 }
571 }
572 }
573 }
574 // skip the found occurrence if it's part of a variable
575 if (foundVariableOccurrence)
576 {
577 pos += desiredFunction.size();
578 continue;
579 }
580
581 // check if a character that is allowed is found
582 bool allowedCharFound = false;
583 for (char allowedChar : allowedChars)
584 {
585 if (function[pos - 1] == allowedChar)
586 {
587 allowedCharFound = true;
588 break;
589 }
590 }
591
592 // skip the found occurrence if no allowed character has been found
593 if (!allowedCharFound)
594 {
595 pos += desiredFunction.size();
596 continue;
597 }
598 }
599
600 pos += desiredFunction.size();
601
602 // match the number of parenthesis
603 int leftParenthesis = 1; // 1 because we have already detected one
604 int rightParenthesis = 0;
605 std::stringstream interior;
606 for (size_t i = pos; i < function.size(); ++i)
607 {
608 if (function[i] == ')')
609 {
610 ++rightParenthesis;
611 }
612 if (function[i] == '(')
613 {
614 ++leftParenthesis;
615 }
616
617 if (leftParenthesis == rightParenthesis)
618 {
619 break;
620 }
621 else
622 {
623 interior << function[i];
624 }
625 }
626 // if the number of left and right parenthesis is equal, then replace appropriately
627 if (rightParenthesis == leftParenthesis)
628 {
629 // go back to replace
630 pos -= desiredFunction.size();
631
632 std::string replacement;
633 if (vectorReturningFunction == VectorReturningFunction::Cross)
634 {
635 // (iHat*crossX(v1,v2)+jHat*crossY(v1,v2)+kHat*crossZ(v1,v2))
636 replacement = "(iHat*crossX(" + interior.str() + ")" + "+jHat*crossY(" + interior.str() +
637 ")" + "+kHat*crossZ(" + interior.str() + "))";
638 }
639 else
640 {
641 // ((v)/mag(v))
642 replacement = "((" + interior.str() + ")/mag(" + interior.str() + "))";
643 }
644
645 // perform replacement, +1 is for the right parenthesis
646 function.replace(pos, desiredFunction.size() + interior.str().size() + 1, replacement);
647 }
648 else
649 {
650 // ExprTk will catch it the parenthesis mismatch
651 // ExprTk will also catch all the cases that the interior is not valid
652 break;
653 }
654 }
655 return function;
656 }
657
658 //------------------------------------------------------------------------------
CheckOldFormatOfDotProductUsage()659 bool vtkExprTkFunctionParser::CheckOldFormatOfDotProductUsage()
660 {
661 const std::string function = this->FunctionWithUsedVariableNames;
662 std::string::size_type pos = 0;
663 while ((pos = function.find('.', pos)) != std::string::npos)
664 {
665 // if we are not in the beginning
666 if (static_cast<int>(pos) - 1 != -1)
667 {
668 // check if left character is digit
669 bool leftCharacterIsDigit = false;
670 if (std::isdigit(function[pos - 1]))
671 {
672 leftCharacterIsDigit = true;
673 }
674
675 // check if right character is digit
676 bool rightCharacterIsDigit = false;
677 // before that check, check if you can look at the right character
678 if (pos + 1 < function.size())
679 {
680 if (std::isdigit(function[pos + 1]))
681 {
682 rightCharacterIsDigit = true;
683 }
684 }
685
686 // both left character and right character are not digits
687 // then this is a possible product usage
688 if (!leftCharacterIsDigit && !rightCharacterIsDigit)
689 {
690 return true;
691 }
692 else
693 {
694 ++pos;
695 }
696 }
697 else
698 {
699 // check if right character is number
700 bool rightCharacterIsNumber = false;
701 // before that check, check if you can look at the right character
702 if (pos + 1 < function.size())
703 {
704 if (std::isdigit(function[pos + 1]))
705 {
706 rightCharacterIsNumber = true;
707 }
708 }
709 // right character is not a number
710 // then this is a possible product usage
711 if (!rightCharacterIsNumber)
712 {
713 return true;
714 }
715 else
716 {
717 ++pos;
718 }
719 }
720 }
721 return false;
722 }
723
724 //------------------------------------------------------------------------------
InvalidateFunction()725 void vtkExprTkFunctionParser::InvalidateFunction()
726 {
727 this->FunctionMTime.Modified();
728 }
729
730 //------------------------------------------------------------------------------
Evaluate()731 bool vtkExprTkFunctionParser::Evaluate()
732 {
733 if (this->FunctionMTime.GetMTime() > this->ParseMTime.GetMTime())
734 {
735 // compile with mode 0 to identify return type
736 if (this->Parse(ParseMode::DetectReturnType) == 0)
737 {
738 return false;
739 }
740 // perform evaluation to identify the return type
741 this->ExprTkTools->Expression.value();
742 this->ResultType = this->ExprTkTools->Expression.results()[0].type;
743
744 // compile with mode 1 to save results in the result array
745 if (this->Parse(ParseMode::SaveResultInVariable) == 0)
746 {
747 return false;
748 }
749 }
750 // perform evaluation
751 this->ExprTkTools->Expression.value();
752
753 switch (this->ResultType)
754 {
755 case ExprTkResultType::e_scalar:
756 if (std::isnan(this->Result[0]) || std::isinf(this->Result[0]))
757 {
758 if (this->ReplaceInvalidValues)
759 {
760 this->Result[0] = this->ReplacementValue;
761 }
762 else
763 {
764 vtkErrorMacro("Invalid result because of mathematically wrong input.");
765 return false;
766 }
767 }
768 break;
769 case ExprTkResultType::e_vector:
770 for (int i = 0; i < 3; i++)
771 {
772 if (std::isnan(this->Result[i]) || std::isinf(this->Result[i]))
773 {
774 if (this->ReplaceInvalidValues)
775 {
776 this->Result[i] = this->ReplacementValue;
777 }
778 else
779 {
780 vtkErrorMacro("Invalid vector element result because of mathematically wrong input.");
781 return false;
782 }
783 }
784 }
785 break;
786 default:
787 vtkErrorMacro("Not supported result type.");
788 return false;
789 }
790
791 this->EvaluateMTime.Modified();
792
793 return true;
794 }
795
796 //------------------------------------------------------------------------------
IsScalarResult()797 int vtkExprTkFunctionParser::IsScalarResult()
798 {
799 if (this->VariableMTime.GetMTime() > this->EvaluateMTime.GetMTime() ||
800 this->FunctionMTime.GetMTime() > this->EvaluateMTime.GetMTime())
801 {
802 if (this->Evaluate() == false)
803 return 0;
804 }
805 return (this->ResultType == ExprTkResultType::e_scalar);
806 }
807
808 //------------------------------------------------------------------------------
GetScalarResult()809 double vtkExprTkFunctionParser::GetScalarResult()
810 {
811 if (!(this->IsScalarResult()))
812 {
813 vtkErrorMacro("GetScalarResult: no valid scalar result");
814 return vtkParserErrorResult;
815 }
816 return this->Result[0];
817 }
818
819 //------------------------------------------------------------------------------
IsVectorResult()820 int vtkExprTkFunctionParser::IsVectorResult()
821 {
822 if (this->VariableMTime.GetMTime() > this->EvaluateMTime.GetMTime() ||
823 this->FunctionMTime.GetMTime() > this->EvaluateMTime.GetMTime())
824 {
825 if (this->Evaluate() == false)
826 return 0;
827 }
828 return (this->ResultType == ExprTkResultType::e_vector);
829 }
830
831 //------------------------------------------------------------------------------
GetVectorResult()832 double* vtkExprTkFunctionParser::GetVectorResult()
833 {
834 if (!(this->IsVectorResult()))
835 {
836 vtkErrorMacro("GetVectorResult: no valid vector result");
837 return vtkParserVectorErrorResult;
838 }
839 return this->Result.GetData();
840 }
841
842 //------------------------------------------------------------------------------
GetScalarVariableName(int i)843 std::string vtkExprTkFunctionParser::GetScalarVariableName(int i)
844 {
845 if (i >= 0 && i < this->GetNumberOfScalarVariables())
846 {
847 return this->OriginalScalarVariableNames[i];
848 }
849 return std::string();
850 }
851
852 //------------------------------------------------------------------------------
GetVectorVariableName(int i)853 std::string vtkExprTkFunctionParser::GetVectorVariableName(int i)
854 {
855 if (i >= 0 && i < this->GetNumberOfVectorVariables())
856 {
857 return this->OriginalVectorVariableNames[i];
858 }
859 return std::string();
860 }
861
862 //------------------------------------------------------------------------------
SetScalarVariableValue(const std::string & inVariableName,double value)863 void vtkExprTkFunctionParser::SetScalarVariableValue(
864 const std::string& inVariableName, double value)
865 {
866 if (inVariableName.empty())
867 {
868 vtkErrorMacro("Variable name is empty");
869 return;
870 }
871 // check if variable name exists in vectors
872 for (size_t i = 0; i < this->OriginalVectorVariableNames.size(); i++)
873 {
874 if (this->OriginalVectorVariableNames[i] == inVariableName)
875 {
876 vtkErrorMacro("Scalar variable name is already registered as a vector variable name");
877 return;
878 }
879 }
880 // check if variable already exists
881 for (size_t i = 0; i < this->OriginalScalarVariableNames.size(); i++)
882 {
883 if (this->OriginalScalarVariableNames[i] == inVariableName)
884 {
885 if (*this->ScalarVariableValues[i] != value)
886 {
887 *this->ScalarVariableValues[i] = value;
888 this->VariableMTime.Modified();
889 this->Modified();
890 }
891 return;
892 }
893 }
894
895 double* scalarValue = new double(value);
896 // if variable name is not sanitized, create a unique sanitized string and set it as variable name
897 std::string variableName = vtkExprTkFunctionParser::SanitizeName(inVariableName.c_str());
898 if (variableName != inVariableName)
899 {
900 variableName = GenerateUniqueVariableName(this->UsedScalarVariableNames, inVariableName);
901 }
902
903 // check if variable is a registered keyword, e.g. sin().
904 bool additionResult = this->ExprTkTools->SymbolTable.add_variable(variableName, *scalarValue);
905 if (additionResult)
906 {
907 this->ScalarVariableValues.push_back(scalarValue);
908 this->OriginalScalarVariableNames.push_back(inVariableName);
909 this->UsedScalarVariableNames.push_back(variableName);
910
911 this->VariableMTime.Modified();
912 this->Modified();
913 }
914 else
915 {
916 delete scalarValue;
917 vtkErrorMacro("Scalar variable `" << inVariableName << "` is a reserved keyword");
918 }
919 }
920
921 //------------------------------------------------------------------------------
SetScalarVariableValue(int i,double value)922 void vtkExprTkFunctionParser::SetScalarVariableValue(int i, double value)
923 {
924 if (i < 0 || i >= this->GetNumberOfScalarVariables())
925 {
926 return;
927 }
928
929 if (*this->ScalarVariableValues[i] != value)
930 {
931 *this->ScalarVariableValues[i] = value;
932 this->VariableMTime.Modified();
933 }
934 this->Modified();
935 }
936
937 //------------------------------------------------------------------------------
GetScalarVariableValue(const std::string & inVariableName)938 double vtkExprTkFunctionParser::GetScalarVariableValue(const std::string& inVariableName)
939 {
940 for (size_t i = 0; i < this->OriginalScalarVariableNames.size(); i++)
941 {
942 if (this->OriginalScalarVariableNames[i] == inVariableName)
943 {
944 return *this->ScalarVariableValues[i];
945 }
946 }
947 vtkErrorMacro(
948 "GetScalarVariableValue: scalar variable name " << inVariableName << " does not exist");
949 return vtkParserErrorResult;
950 }
951
952 //------------------------------------------------------------------------------
GetScalarVariableValue(int i)953 double vtkExprTkFunctionParser::GetScalarVariableValue(int i)
954 {
955 if (i < 0 || i >= this->GetNumberOfScalarVariables())
956 {
957 vtkErrorMacro("GetScalarVariableValue: scalar variable number " << i << " does not exist");
958 return vtkParserErrorResult;
959 }
960
961 return *this->ScalarVariableValues[i];
962 }
963
964 //------------------------------------------------------------------------------
SetVectorVariableValue(const std::string & inVariableName,double xValue,double yValue,double zValue)965 void vtkExprTkFunctionParser::SetVectorVariableValue(
966 const std::string& inVariableName, double xValue, double yValue, double zValue)
967 {
968 if (inVariableName.empty())
969 {
970 vtkErrorMacro("Variable name is empty");
971 return;
972 }
973 // check if variable name exists in vectors
974 for (size_t i = 0; i < this->OriginalScalarVariableNames.size(); i++)
975 {
976 if (this->OriginalScalarVariableNames[i] == inVariableName)
977 {
978 vtkErrorMacro("Vector variable name is already registered as a scalar variable name");
979 return;
980 }
981 }
982 // check if variable already exists
983 for (size_t i = 0; i < this->OriginalVectorVariableNames.size(); i++)
984 {
985 if (this->OriginalVectorVariableNames[i] == inVariableName)
986 {
987 if ((*this->VectorVariableValues[i])[0] != xValue ||
988 (*this->VectorVariableValues[i])[1] != yValue ||
989 (*this->VectorVariableValues[i])[2] != zValue)
990 {
991 (*this->VectorVariableValues[i])[0] = xValue;
992 (*this->VectorVariableValues[i])[1] = yValue;
993 (*this->VectorVariableValues[i])[2] = zValue;
994 this->VariableMTime.Modified();
995 this->Modified();
996 }
997 return;
998 }
999 }
1000
1001 vtkTuple<double, 3>* vector = new vtkTuple<double, 3>();
1002 (*vector)[0] = xValue;
1003 (*vector)[1] = yValue;
1004 (*vector)[2] = zValue;
1005
1006 // if variable name is not sanitized, create a unique sanitized string and set it as variable name
1007 std::string variableName = vtkExprTkFunctionParser::SanitizeName(inVariableName.c_str());
1008 if (variableName != inVariableName)
1009 {
1010 variableName = GenerateUniqueVariableName(this->UsedVectorVariableNames, inVariableName);
1011 }
1012 // check if variable is a registered keyword, e.g. sin().
1013 bool additionResult =
1014 this->ExprTkTools->SymbolTable.add_vector(variableName, vector->GetData(), vector->GetSize());
1015 if (additionResult)
1016 {
1017 this->VectorVariableValues.push_back(vector);
1018 this->OriginalVectorVariableNames.push_back(inVariableName);
1019 this->UsedVectorVariableNames.push_back(variableName);
1020
1021 this->VariableMTime.Modified();
1022 this->Modified();
1023 }
1024 else
1025 {
1026 delete vector;
1027 vtkErrorMacro("Vector variable `" << inVariableName << "` is a reserved keyword");
1028 }
1029 }
1030
1031 //------------------------------------------------------------------------------
SetVectorVariableValue(int i,double xValue,double yValue,double zValue)1032 void vtkExprTkFunctionParser::SetVectorVariableValue(
1033 int i, double xValue, double yValue, double zValue)
1034 {
1035 if (i < 0 || i >= this->GetNumberOfVectorVariables())
1036 {
1037 return;
1038 }
1039 if ((*this->VectorVariableValues[i])[0] != xValue ||
1040 (*this->VectorVariableValues[i])[1] != yValue || (*this->VectorVariableValues[i])[2] != zValue)
1041 {
1042 (*this->VectorVariableValues[i])[0] = xValue;
1043 (*this->VectorVariableValues[i])[1] = yValue;
1044 (*this->VectorVariableValues[i])[2] = zValue;
1045 this->VariableMTime.Modified();
1046 this->Modified();
1047 }
1048 }
1049
1050 //------------------------------------------------------------------------------
GetVectorVariableValue(const std::string & inVariableName)1051 double* vtkExprTkFunctionParser::GetVectorVariableValue(const std::string& inVariableName)
1052 {
1053 for (size_t i = 0; i < this->OriginalVectorVariableNames.size(); i++)
1054 {
1055 if (this->OriginalVectorVariableNames[i] == inVariableName)
1056 {
1057 return this->VectorVariableValues[i]->GetData();
1058 }
1059 }
1060 vtkErrorMacro(
1061 "GetVectorVariableValue: vector variable name " << inVariableName << " does not exist");
1062 return vtkParserVectorErrorResult;
1063 }
1064
1065 //------------------------------------------------------------------------------
GetVectorVariableValue(int i)1066 double* vtkExprTkFunctionParser::GetVectorVariableValue(int i)
1067 {
1068 if (i < 0 || i >= this->GetNumberOfVectorVariables())
1069 {
1070 vtkErrorMacro("GetVectorVariableValue: vector variable number " << i << " does not exist");
1071 return vtkParserVectorErrorResult;
1072 }
1073 return this->VectorVariableValues[i]->GetData();
1074 }
1075
1076 //------------------------------------------------------------------------------
RemoveScalarVariables()1077 void vtkExprTkFunctionParser::RemoveScalarVariables()
1078 {
1079 this->ExprTkTools->SymbolTable.clear_variables();
1080 this->OriginalScalarVariableNames.clear();
1081 this->UsedScalarVariableNames.clear();
1082 for (size_t i = 0; i < this->ScalarVariableValues.size(); ++i)
1083 {
1084 delete this->ScalarVariableValues[i];
1085 }
1086 this->ScalarVariableValues.clear();
1087 }
1088
1089 //------------------------------------------------------------------------------
RemoveVectorVariables()1090 void vtkExprTkFunctionParser::RemoveVectorVariables()
1091 {
1092 // we clear vector variables to avoid removing iHat,jHat, kHat
1093 for (size_t i = 0; i < this->UsedVectorVariableNames.size(); ++i)
1094 {
1095 this->ExprTkTools->SymbolTable.remove_vector(this->UsedVectorVariableNames[i]);
1096 }
1097 this->OriginalVectorVariableNames.clear();
1098 this->UsedVectorVariableNames.clear();
1099 for (size_t i = 0; i < this->VectorVariableValues.size(); ++i)
1100 {
1101 delete this->VectorVariableValues[i];
1102 }
1103 this->VectorVariableValues.clear();
1104 }
1105
1106 //------------------------------------------------------------------------------
RemoveAllVariables()1107 void vtkExprTkFunctionParser::RemoveAllVariables()
1108 {
1109 this->RemoveScalarVariables();
1110 this->RemoveVectorVariables();
1111 }
1112
1113 //------------------------------------------------------------------------------
GetMTime()1114 vtkMTimeType vtkExprTkFunctionParser::GetMTime()
1115 {
1116 vtkMTimeType mTime = this->Superclass::GetMTime();
1117
1118 if (this->EvaluateMTime > mTime)
1119 {
1120 mTime = this->EvaluateMTime;
1121 }
1122 if (this->VariableMTime > mTime)
1123 {
1124 mTime = this->VariableMTime;
1125 }
1126 if (this->ParseMTime > mTime)
1127 {
1128 mTime = this->ParseMTime;
1129 }
1130 if (this->FunctionMTime > mTime)
1131 {
1132 mTime = this->FunctionMTime;
1133 }
1134
1135 return mTime;
1136 }
1137
1138 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)1139 void vtkExprTkFunctionParser::PrintSelf(ostream& os, vtkIndent indent)
1140 {
1141 this->Superclass::PrintSelf(os, indent);
1142
1143 os << indent << "Function: " << (this->GetFunction() ? this->GetFunction() : "(none)") << endl;
1144
1145 os << indent << "FunctionWithUsedVariableNames: "
1146 << (!this->FunctionWithUsedVariableNames.empty() ? this->FunctionWithUsedVariableNames
1147 : "(none)")
1148 << endl;
1149
1150 os << indent << "ExpressionString: "
1151 << (!this->ExpressionString.empty() ? this->ExpressionString : "(none)") << endl;
1152
1153 for (size_t i = 0; i < this->OriginalScalarVariableNames.size(); i++)
1154 {
1155 os << indent << " " << this->OriginalScalarVariableNames[i] << " / "
1156 << this->UsedScalarVariableNames[i] << ": " << (*this->ScalarVariableValues[i]) << endl;
1157 }
1158
1159 for (size_t i = 0; i < this->OriginalVectorVariableNames.size(); i++)
1160 {
1161 os << indent << " " << this->OriginalVectorVariableNames[i] << " / "
1162 << this->UsedVectorVariableNames[i] << ": (" << (*this->VectorVariableValues[i])[0] << ", "
1163 << (*this->VectorVariableValues[i])[1] << ", " << (*this->VectorVariableValues[i])[2] << ")"
1164 << endl;
1165 }
1166
1167 if (this->EvaluateMTime.GetMTime() > this->FunctionMTime.GetMTime() &&
1168 this->EvaluateMTime.GetMTime() > this->VariableMTime.GetMTime() &&
1169 this->ExprTkTools->Expression.results().count() > 0)
1170 {
1171 if (this->ResultType == ExprTkResultType::e_scalar)
1172 {
1173 os << indent << "ScalarResult: " << this->GetScalarResult() << endl;
1174 os << indent << "VectorResult: "
1175 << "(none)" << endl;
1176 }
1177 else
1178 {
1179 os << indent << "ScalarResult: "
1180 << "(none)" << endl;
1181 os << indent << "VectorResult: "
1182 << "(" << this->GetVectorResult()[0] << ", " << this->GetVectorResult()[1] << ", "
1183 << this->GetVectorResult()[2] << ")" << endl;
1184 }
1185 }
1186 else
1187 {
1188 os << indent << "ScalarResult: "
1189 << "(none)" << endl;
1190 os << indent << "VectorResult: "
1191 << "(none)" << endl;
1192 }
1193
1194 os << indent << "Replace Invalid Values: " << (this->GetReplaceInvalidValues() ? "On" : "Off")
1195 << endl;
1196 os << indent << "Replacement Value: " << this->GetReplacementValue() << endl;
1197 }
1198
1199 //------------------------------------------------------------------------------
UpdateNeededVariables()1200 void vtkExprTkFunctionParser::UpdateNeededVariables()
1201 {
1202 this->ScalarVariableNeeded.clear();
1203 this->ScalarVariableNeeded.resize(this->UsedScalarVariableNames.size(), false);
1204
1205 this->VectorVariableNeeded.clear();
1206 this->VectorVariableNeeded.resize(this->UsedVectorVariableNames.size(), false);
1207
1208 // store variables after parsing
1209 std::deque<exprtk::parser<double>::dependent_entity_collector::symbol_t> symbolList;
1210 this->ExprTkTools->Parser.dec().symbols(symbolList);
1211 // convert them to a set to remove duplicates
1212 std::set<std::string> variables;
1213 for (const auto& symbol : symbolList)
1214 {
1215 variables.insert(symbol.first);
1216 }
1217
1218 for (auto& variable : variables)
1219 {
1220 // check if variable exists in scalars
1221 for (size_t j = 0; j < this->UsedScalarVariableNames.size(); ++j)
1222 {
1223 if (variable == this->UsedScalarVariableNames[j])
1224 {
1225 this->ScalarVariableNeeded[j] = true;
1226 break;
1227 }
1228 }
1229
1230 // check if variable exists in vectors
1231 for (size_t j = 0; j < this->UsedVectorVariableNames.size(); ++j)
1232 {
1233 if (variable == this->UsedVectorVariableNames[j])
1234 {
1235 this->VectorVariableNeeded[j] = true;
1236 break;
1237 }
1238 }
1239 }
1240 }
1241
1242 //------------------------------------------------------------------------------
SanitizeName(const char * name)1243 std::string vtkExprTkFunctionParser::SanitizeName(const char* name)
1244 {
1245 if (!name || name[0] == '\0')
1246 {
1247 return std::string();
1248 }
1249
1250 std::ostringstream cname;
1251 for (size_t cc = 0; name[cc]; cc++)
1252 {
1253 if (isalnum(name[cc]) || name[cc] == '_')
1254 {
1255 cname << name[cc];
1256 }
1257 }
1258 // if first character is not an alphabet, add an 'a' to it.
1259 if (cname.str().empty() || isalpha(cname.str()[0]))
1260 {
1261 return cname.str();
1262 }
1263 else
1264 {
1265 return "a" + cname.str();
1266 }
1267 }
1268
1269 //------------------------------------------------------------------------------
GetScalarVariableIndex(const std::string & inVariableName)1270 int vtkExprTkFunctionParser::GetScalarVariableIndex(const std::string& inVariableName)
1271 {
1272 for (size_t i = 0; i < this->OriginalScalarVariableNames.size(); ++i)
1273 {
1274 if (this->OriginalScalarVariableNames[i] == inVariableName)
1275 {
1276 return static_cast<int>(i);
1277 }
1278 }
1279 return -1;
1280 }
1281
1282 //------------------------------------------------------------------------------
GetScalarVariableNeeded(int i)1283 bool vtkExprTkFunctionParser::GetScalarVariableNeeded(int i)
1284 {
1285 if (i < 0 || i >= static_cast<int>(this->ScalarVariableNeeded.size()))
1286 {
1287 return false;
1288 }
1289 return this->ScalarVariableNeeded[i];
1290 }
1291
1292 //------------------------------------------------------------------------------
GetScalarVariableNeeded(const std::string & inVariableName)1293 bool vtkExprTkFunctionParser::GetScalarVariableNeeded(const std::string& inVariableName)
1294 {
1295 std::vector<std::string>::const_iterator iter =
1296 std::find(this->OriginalScalarVariableNames.begin(), this->OriginalScalarVariableNames.end(),
1297 inVariableName);
1298 if (iter != this->OriginalScalarVariableNames.end())
1299 {
1300 return this->GetScalarVariableNeeded(
1301 static_cast<int>(iter - this->OriginalScalarVariableNames.begin()));
1302 }
1303 else
1304 {
1305 vtkErrorMacro(
1306 "GetScalarVariableNeeded: scalar variable name " << inVariableName << " does not exist");
1307 return false;
1308 }
1309 }
1310
1311 //------------------------------------------------------------------------------
GetVectorVariableIndex(const std::string & inVariableName)1312 int vtkExprTkFunctionParser::GetVectorVariableIndex(const std::string& inVariableName)
1313 {
1314 for (size_t i = 0; i < this->OriginalVectorVariableNames.size(); i++)
1315 {
1316 if (this->OriginalVectorVariableNames[i] == inVariableName)
1317 {
1318 return static_cast<int>(i);
1319 }
1320 }
1321 return -1;
1322 }
1323
1324 //------------------------------------------------------------------------------
GetVectorVariableNeeded(int i)1325 bool vtkExprTkFunctionParser::GetVectorVariableNeeded(int i)
1326 {
1327 if (i < 0 || i >= static_cast<int>(this->VectorVariableNeeded.size()))
1328 {
1329 return false;
1330 }
1331 return this->VectorVariableNeeded[i];
1332 }
1333
1334 //------------------------------------------------------------------------------
GetVectorVariableNeeded(const std::string & inVariableName)1335 bool vtkExprTkFunctionParser::GetVectorVariableNeeded(const std::string& inVariableName)
1336 {
1337 std::vector<std::string>::const_iterator iter =
1338 std::find(this->OriginalVectorVariableNames.begin(), this->OriginalVectorVariableNames.end(),
1339 inVariableName);
1340 if (iter != this->OriginalVectorVariableNames.end())
1341 {
1342 return this->GetVectorVariableNeeded(
1343 static_cast<int>(iter - this->OriginalVectorVariableNames.begin()));
1344 }
1345 else
1346 {
1347 vtkErrorMacro(
1348 "GetVectorVariableNeeded: scalar variable name " << inVariableName << " does not exist");
1349 return false;
1350 }
1351 }
1352