Vuo  2.3.2
VuoMathExpressionParser.cc
Go to the documentation of this file.
1 
10 #include <muParser/muParser.h>
11 #include <set>
12 using namespace std;
13 
14 #include "module.h"
15 
16 extern "C"
17 {
19 #include "VuoGradientNoiseCommon.h"
20 
21 #ifdef VUO_COMPILER
23  "title" : "VuoMathExpressionParser",
24  "dependencies" : [
25  "VuoInteger",
26  "VuoReal",
27  "VuoText",
28  "VuoList_VuoInteger",
29  "VuoList_VuoReal",
30  "VuoList_VuoText",
31  "VuoDictionary_VuoText_VuoReal",
32  "VuoGradientNoiseCommon",
33  "muparser"
34  ]
35  });
36 #endif
37 }
38 
39 
44 {
45 public:
46  string message;
47  vector<unsigned long> expressionIndices;
48 
52  VuoMathExpressionErrorInternal(const mu::ParserError &error) :
53  message(error.GetMsg())
54  {
55  size_t positionIndex = message.find(" at position ");
56  if (positionIndex != string::npos)
57  message = message.substr(0, positionIndex);
58  }
59 
63  VuoMathExpressionErrorInternal(const string &message) :
64  message(message)
65  {
66  }
67 
71  VuoMathExpressionErrorInternal(const char *message) :
72  message(message)
73  {
74  }
75 };
76 
83 {
85  return e->message.c_str();
86 }
87 
94 {
96 
98  for (vector<unsigned long>::iterator i = e->expressionIndices.begin(); i != e->expressionIndices.end(); ++i)
99  VuoListAppendValue_VuoInteger(indices, *i);
100 
101  return indices;
102 }
103 
108 {
110  delete e;
111 }
112 
113 
114 static const size_t MAX_VARIABLE_COUNT = 64;
115 
119 static double deg2rad(double degrees)
120 {
121  return degrees * 0.0174532925;
122 }
123 
127 static double rad2deg(double radians)
128 {
129  return radians * 57.2957795;
130 }
131 
135 static double muparser_rint(double x)
136 {
137  return floor(x + .5);
138 }
139 
143 static double fract(double x)
144 {
145  return x - floor(x);
146 }
147 
151 static double clamp(double x, double minVal, double maxVal)
152 {
153  return MIN(MAX(x, minVal), maxVal);
154 }
155 
159 static double step(double edge, double x)
160 {
161  return x < edge ? 0 : 1;
162 }
163 
167 static double smoothstep(double edge0, double edge1, double x)
168 {
169  double t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
170  return t * t * (3.0 - 2.0 * t);
171 }
172 
176 static double mix(double x, double y, double a)
177 {
178  return x * (1. - a) + y * a;
179 }
180 
182 
185 static double sinInDegrees(double degrees) { return sin(deg2rad(degrees)); }
186 static double cosInDegrees(double degrees) { return cos(deg2rad(degrees)); }
187 static double tanInDegrees(double degrees) { return tan(deg2rad(degrees)); }
188 static double asinInDegrees(double x) { return rad2deg(asin(x)); }
189 static double acosInDegrees(double x) { return rad2deg(acos(x)); }
190 static double atanInDegrees(double x) { return rad2deg(atan(x)); }
191 static double atan2InDegrees(double y, double x) { return rad2deg(atan2(y,x)); }
192 static double sinhInDegrees(double degrees) { return sinh(deg2rad(degrees)); }
193 static double coshInDegrees(double degrees) { return cosh(deg2rad(degrees)); }
194 static double tanhInDegrees(double degrees) { return tanh(deg2rad(degrees)); }
195 static double asinhInDegrees(double x) { return rad2deg(asinh(x)); }
196 static double acoshInDegrees(double x) { return rad2deg(acosh(x)); }
197 static double atanhInDegrees(double x) { return rad2deg(atanh(x)); }
199 
201 
204 static double perlin2d (double x, double y ) { return VuoGradientNoise_perlin_VuoPoint2d_VuoReal (VuoPoint2d_make(x,y )); }
205 static double perlin3d (double x, double y, double z ) { return VuoGradientNoise_perlin_VuoPoint3d_VuoReal (VuoPoint3d_make(x,y,z )); }
206 static double perlin4d (double x, double y, double z, double w) { return VuoGradientNoise_perlin_VuoPoint4d_VuoReal (VuoPoint4d_make(x,y,z,w)); }
207 static double simplex2d(double x, double y ) { return VuoGradientNoise_simplex_VuoPoint2d_VuoReal(VuoPoint2d_make(x,y )); }
208 static double simplex3d(double x, double y, double z ) { return VuoGradientNoise_simplex_VuoPoint3d_VuoReal(VuoPoint3d_make(x,y,z )); }
209 static double simplex4d(double x, double y, double z, double w) { return VuoGradientNoise_simplex_VuoPoint4d_VuoReal(VuoPoint4d_make(x,y,z,w)); }
211 
216 {
217  mu::Parser *muParser = (mu::Parser *)p;
218 
219  muParser->DefineConst("pi", (double)3.14159265359);
220  muParser->DefineConst("PI", (double)3.14159265359);
221 
222  muParser->DefineOprt("%", fmod, mu::prMUL_DIV, mu::oaLEFT, true);
223 
224  // Trigonometry
225  muParser->DefineFun("deg2rad", deg2rad, true);
226  muParser->DefineFun("rad2deg", rad2deg, true);
227  muParser->DefineFun("sin", sinInDegrees, true);
228  muParser->DefineFun("cos", cosInDegrees, true);
229  muParser->DefineFun("tan", tanInDegrees, true);
230  muParser->DefineFun("asin", asinInDegrees, true);
231  muParser->DefineFun("acos", acosInDegrees, true);
232  muParser->DefineFun("atan", atanInDegrees, true);
233  muParser->DefineFun("atan2", atan2InDegrees, true);
234  muParser->DefineFun("sinh", sinhInDegrees, true);
235  muParser->DefineFun("cosh", coshInDegrees, true);
236  muParser->DefineFun("tanh", tanhInDegrees, true);
237  muParser->DefineFun("asinh", asinhInDegrees, true);
238  muParser->DefineFun("acosh", acoshInDegrees, true);
239  muParser->DefineFun("atanh", atanhInDegrees, true);
240 
241  // Real -> Integer
242  muParser->DefineFun("round", muparser_rint, true);
243  muParser->DefineFun<mu::fun_type1>("floor", ::floor, true);
244  muParser->DefineFun<mu::fun_type1>("ceil", ::ceil, true);
245  muParser->DefineFun<mu::fun_type1>("trunc", ::trunc, true);
246 
247  // GLSL
248  muParser->DefineFun("fract", fract, true);
249  muParser->DefineFun("clamp", clamp);
250  muParser->DefineFun("step", step);
251  muParser->DefineFun("smoothstep", smoothstep);
252  muParser->DefineFun("mix", mix);
253 
254  // Random / noise
255  muParser->DefineFun("random", VuoReal_random, false /* since it generates a new value each call */);
256 
257  muParser->DefineFun("perlin1d", VuoGradientNoise_perlin_VuoReal_VuoReal, true);
258  muParser->DefineFun("perlin2d", perlin2d, true);
259  muParser->DefineFun("perlin3d", perlin3d, true);
260  muParser->DefineFun("perlin4d", perlin4d, true);
261 
262  muParser->DefineFun("simplex1d", VuoGradientNoise_simplex_VuoReal_VuoReal, true);
263  muParser->DefineFun("simplex2d", simplex2d, true);
264  muParser->DefineFun("simplex3d", simplex3d, true);
265  muParser->DefineFun("simplex4d", simplex4d, true);
266 }
267 
268 
273 {
274 public:
275  mu::Parser muParser;
276  size_t variableCount;
277  double variableValues[MAX_VARIABLE_COUNT];
278  map<string, size_t> variableNamesAndIndices;
279  vector<string> inputVariableNames;
280  vector<string> outputVariableNames;
281 
285  static double * addVariable(const char *variable, void *userData)
286  {
288 
290  throw mu::ParserError("Too many variables");
291 
292  size_t index = mi->variableCount;
293  mi->variableCount++;
294  mi->variableValues[index] = 0;
295  mi->variableNamesAndIndices[variable] = index;
296  return &mi->variableValues[index];
297  }
298 
306  VuoMathExpressionParserInternal(const string &expression, const vector<string> &outputVariableNames_ = vector<string>()) :
307  outputVariableNames(outputVariableNames_)
308  {
309  this->variableCount = 0;
310 
312 
313  muParser.SetVarFactory(addVariable, this);
314  muParser.SetExpr(expression); // checks for some errors
315  muParser.GetUsedVar(); // checks for more errors
316 
317  if (! outputVariableNames.empty())
318  {
319  string baseName = "result";
320  if (muParser.GetNumResults() == 1)
321  {
322  if (outputVariableNames[0].empty())
323  outputVariableNames[0] = baseName;
324  }
325  else
326  {
327  for (size_t i = 0; i < outputVariableNames.size(); ++i)
328  {
329  if (outputVariableNames[i].empty())
330  {
331  string name;
332  int suffix = 1;
333  do {
334  ostringstream oss;
335  oss << baseName << suffix;
336  name = oss.str();
337  ++suffix;
338  } while (find(outputVariableNames.begin(), outputVariableNames.end(), name) != outputVariableNames.end());
339  outputVariableNames[i] = name;
340  }
341  }
342  }
343  }
344 
345  for (map<string, size_t>::iterator i = variableNamesAndIndices.begin(); i != variableNamesAndIndices.end(); ++i)
346  if (find(outputVariableNames.begin(), outputVariableNames.end(), i->first) == outputVariableNames.end())
347  inputVariableNames.push_back(i->first);
348 
349  std::sort(inputVariableNames.begin(), inputVariableNames.end());
350  }
351 
355  static string getExpressionSeparator(void)
356  {
357  return string(1, mu::Parser().GetArgSep());
358  }
359 };
360 
361 
367 static vector<string> splitSingleExpressionOnAssignmentOperators(string expression)
368 {
369  vector<string> expressionParts;
370 
371  size_t partStartIndex, searchStartIndex, assignmentIndex;
372  partStartIndex = searchStartIndex = 0;
373  while ((assignmentIndex = expression.find("=", searchStartIndex)) != string::npos)
374  {
375  char charBefore = expression[assignmentIndex - 1];
376  char charAfter = expression[assignmentIndex + 1];
377  if (charBefore == '<' || charBefore == '>' || charBefore == '!')
378  searchStartIndex = assignmentIndex + 1;
379  else if (charAfter == '=')
380  searchStartIndex = assignmentIndex + 2;
381  else
382  {
383  string part = expression.substr(partStartIndex, assignmentIndex - partStartIndex);
384  expressionParts.push_back(part);
385  partStartIndex = searchStartIndex = assignmentIndex + 1;
386  }
387  }
388 
389  string part = expression.substr(partStartIndex);
390  expressionParts.push_back(part);
391 
392  return expressionParts;
393 }
394 
398 static void checkSyntaxOfSingleExpression(string expression, VuoMathExpressionError *error)
399 {
400  try
401  {
402  VuoMathExpressionParserInternal parser(expression);
403 
404  if (parser.muParser.GetNumResults() > 1)
405  {
407  *error = new VuoMathExpressionErrorInternal("Unexpected \"" + separator + "\"");
408  return;
409  }
410  }
411  catch (mu::ParserError &e)
412  {
413  *error = new VuoMathExpressionErrorInternal(e);
414  return;
415  }
416 
417  vector<string> expressionParts = splitSingleExpressionOnAssignmentOperators(expression);
418  if (expressionParts.size() > 2)
419  {
420  *error = new VuoMathExpressionErrorInternal("Too many \"=\" operators");
421  return;
422  }
423 }
424 
429 {
430  unsigned long count = VuoListGetCount_VuoText(expressions);
431  for (unsigned long i = 1; i <= count; ++i)
432  {
433  VuoText expression = VuoListGetValue_VuoText(expressions, i);
434  checkSyntaxOfSingleExpression(expression, error);
435  if (*error)
436  {
438  e->expressionIndices.push_back(i);
439  return;
440  }
441  }
442 }
443 
449 static void parseVariablesFromSingleExpression(string expression,
450  vector<string> &inputVariableNames, string &outputVariableName,
451  VuoMathExpressionError *error)
452 {
453  vector<string> expressionParts = splitSingleExpressionOnAssignmentOperators(expression);
454 
455  if (expressionParts.size() > 1)
456  {
457  string outputExpression = expressionParts.front();
458  VuoMathExpressionParserInternal outputParser(outputExpression);
459  outputVariableName = *outputParser.inputVariableNames.begin();
460  }
461 
462  VuoMathExpressionParserInternal inputParser(expressionParts.back());
463  inputVariableNames = inputParser.inputVariableNames;
464 
465  if (! outputVariableName.empty() && find(inputVariableNames.begin(), inputVariableNames.end(), outputVariableName) != inputVariableNames.end())
466  {
467  *error = new VuoMathExpressionErrorInternal("Variable \"" + outputVariableName + "\" can't be on both sides of the \"=\" operator");
468  return;
469  }
470 }
471 
478  vector<string> &inputVariableNames, vector<string> &outputVariableNames,
479  VuoMathExpressionError *error)
480 {
481  map<string, vector<unsigned long> > expressionsForInputVariable;
482  map<string, vector<unsigned long> > expressionsForOutputVariable;
483 
484  unsigned long count = VuoListGetCount_VuoText(expressions);
485  for (unsigned long i = 1; i <= count; ++i)
486  {
487  VuoText expression = VuoListGetValue_VuoText(expressions, i);
488 
489  vector<string> currInputVariableNames;
490  string currOutputVariableName;
491  parseVariablesFromSingleExpression(expression, currInputVariableNames, currOutputVariableName, error);
492  if (*error)
493  {
495  e->expressionIndices.push_back(i);
496  return;
497  }
498 
499  for (vector<string>::iterator j = currInputVariableNames.begin(); j != currInputVariableNames.end(); ++j)
500  expressionsForInputVariable[*j].push_back(i);
501  expressionsForOutputVariable[currOutputVariableName].push_back(i);
502 
503  inputVariableNames.insert(inputVariableNames.end(), currInputVariableNames.begin(), currInputVariableNames.end());
504 
505  if (! currOutputVariableName.empty() && find(outputVariableNames.begin(), outputVariableNames.end(), currOutputVariableName) != outputVariableNames.end())
506  {
507  VuoMathExpressionErrorInternal *e = new VuoMathExpressionErrorInternal("Variable \"" + currOutputVariableName + "\" can't be on the left side of the \"=\" operator in multiple expressions");
508  e->expressionIndices = expressionsForOutputVariable[currOutputVariableName];
509  *error = e;
510  return;
511  }
512  outputVariableNames.push_back(currOutputVariableName);
513  }
514 
515  set<string> allVariableNames;
516  allVariableNames.insert(inputVariableNames.begin(), inputVariableNames.end());
517  allVariableNames.insert(outputVariableNames.begin(), outputVariableNames.end());
518  for (set<string>::iterator i = allVariableNames.begin(); i != allVariableNames.end(); ++i)
519  {
520  if (find(inputVariableNames.begin(), inputVariableNames.end(), *i) != inputVariableNames.end() &&
521  find(outputVariableNames.begin(), outputVariableNames.end(), *i) != outputVariableNames.end())
522  {
523  VuoMathExpressionErrorInternal *e = new VuoMathExpressionErrorInternal("Variable \"" + *i + "\" can't be on both sides of the \"=\" operator");
524 
525  vector<unsigned long> expressionsForVariable( expressionsForInputVariable[*i].size() + expressionsForOutputVariable[*i].size() );
526  merge( expressionsForInputVariable[*i].begin(), expressionsForInputVariable[*i].end(),
527  expressionsForOutputVariable[*i].begin(), expressionsForOutputVariable[*i].end(),
528  expressionsForVariable.begin() );
529  vector<unsigned long>::iterator endIter = unique( expressionsForVariable.begin(), expressionsForVariable.end() );
530  expressionsForVariable.resize( distance( expressionsForVariable.begin(), endIter ) );
531  e->expressionIndices = expressionsForVariable;
532 
533  *error = e;
534  return;
535  }
536  }
537 }
538 
539 
544 {
545  delete static_cast<VuoMathExpressionParserInternal *>(me);
546 }
547 
554  VuoMathExpressionError *error)
555 {
556  checkSyntaxOfSingleExpression(expression, error);
557  if (*error)
558  return NULL;
559 
560  vector<string> inputVariableNames;
561  string outputVariableName;
562  parseVariablesFromSingleExpression(expression, inputVariableNames, outputVariableName, error);
563  if (*error)
564  return NULL;
565  vector<string> outputVariableNames(1, outputVariableName);
566 
567  VuoMathExpressionParser m = (VuoMathExpressionParser)new VuoMathExpressionParserInternal(expression, outputVariableNames);
569  return m;
570 }
571 
578  VuoMathExpressionError *error)
579 {
580  checkSyntaxOfMultipleExpressions(expressions, error);
581  if (*error)
582  return NULL;
583 
584  vector<string> inputVariableNames;
585  vector<string> outputVariableNames;
586  parseVariablesFromMultipleExpressions(expressions, inputVariableNames, outputVariableNames, error);
587  if (*error)
588  return NULL;
589 
590  string joinedExpression;
592  unsigned long count = VuoListGetCount_VuoText(expressions);
593  for (unsigned long i = 1; i <= count; ++i)
594  {
595  VuoText assignmentExpression = VuoListGetValue_VuoText(expressions, i);
596  joinedExpression += assignmentExpression;
597  if (i < count)
598  joinedExpression += separator;
599  }
600 
601  VuoMathExpressionParser m = (VuoMathExpressionParser)new VuoMathExpressionParserInternal(joinedExpression, outputVariableNames);
603  return m;
604 }
605 
610 {
612  VuoList_VuoText inputVariables = VuoListCreate_VuoText();
613 
614  for (vector<string>::iterator i = mi->inputVariableNames.begin(); i != mi->inputVariableNames.end(); ++i)
615  VuoListAppendValue_VuoText(inputVariables, VuoText_make((*i).c_str()));
616 
617  return inputVariables;
618 }
619 
626 {
628  VuoList_VuoText outputVariables = VuoListCreate_VuoText();
629 
630  for (vector<string>::iterator i = mi->outputVariableNames.begin(); i != mi->outputVariableNames.end(); ++i)
631  VuoListAppendValue_VuoText(outputVariables, VuoText_make((*i).c_str()));
632 
633  return outputVariables;
634 }
635 
645 {
647 
648  for (size_t i = 0; i < MAX_VARIABLE_COUNT; ++i)
649  mi->variableValues[i] = 0;
650 
651  VuoText *inputVariablesArray = VuoListGetData_VuoText(inputValues.keys);
652  VuoReal *inputValuesArray = VuoListGetData_VuoReal(inputValues.values);
653  unsigned long inputCount = VuoListGetCount_VuoText(inputValues.keys);
654  for (int i = 0; i < inputCount; ++i)
655  {
656  map<string, size_t>::iterator variableIter = mi->variableNamesAndIndices.find(inputVariablesArray[i]);
657  if (variableIter != mi->variableNamesAndIndices.end())
658  {
659  size_t index = variableIter->second;
660  mi->variableValues[index] = inputValuesArray[i];
661  }
662  }
663 
664  int outputCount;
665  double *results = mi->muParser.Eval(outputCount);
666 
667  VuoList_VuoText keys = VuoListCreateWithCount_VuoText(outputCount, NULL);
668  VuoText *keysArray = VuoListGetData_VuoText(keys);
669 
670  VuoList_VuoReal values = VuoListCreateWithCount_VuoReal(outputCount, 0);
671  VuoReal *valuesArray = VuoListGetData_VuoReal(values);
672 
673  for (int i = 0; i < outputCount; ++i)
674  {
675  keysArray[i] = VuoText_make( mi->outputVariableNames[i].c_str() );
676  VuoRetain(keysArray[i]);
677  valuesArray[i] = results[i];
678  }
679 
681 }
682 
687 {
688  if (!m || !xValues)
689  return NULL;
690 
692 
693  for (size_t i = 0; i < MAX_VARIABLE_COUNT; ++i)
694  mi->variableValues[i] = 0;
695 
696  VuoText *inputVariablesArray = VuoListGetData_VuoText(constants.keys);
697  VuoReal *inputValuesArray = VuoListGetData_VuoReal(constants.values);
698  unsigned long inputCount = VuoListGetCount_VuoText(constants.keys);
699  for (int i = 0; i < inputCount; ++i)
700  {
701  map<string, size_t>::iterator variableIter = mi->variableNamesAndIndices.find(inputVariablesArray[i]);
702  if (variableIter != mi->variableNamesAndIndices.end())
703  {
704  size_t index = variableIter->second;
705  mi->variableValues[index] = inputValuesArray[i];
706  }
707  }
708 
709  map<string, size_t>::iterator xIterLC = mi->variableNamesAndIndices.find("x");
710  double *xLC = NULL;
711  if (xIterLC != mi->variableNamesAndIndices.end())
712  xLC = &mi->variableValues[xIterLC->second];
713 
714  map<string, size_t>::iterator xIterUC = mi->variableNamesAndIndices.find("X");
715  double *xUC = NULL;
716  if (xIterUC != mi->variableNamesAndIndices.end())
717  xUC = &mi->variableValues[xIterUC->second];
718 
719  map<string, size_t>::iterator iIterLC = mi->variableNamesAndIndices.find("i");
720  double *iLC = NULL;
721  if (iIterLC != mi->variableNamesAndIndices.end())
722  iLC = &mi->variableValues[iIterLC->second];
723 
724  map<string, size_t>::iterator iIterUC = mi->variableNamesAndIndices.find("I");
725  double *iUC = NULL;
726  if (iIterUC != mi->variableNamesAndIndices.end())
727  iUC = &mi->variableValues[iIterUC->second];
728 
729  unsigned long xValueCount = VuoListGetCount_VuoReal(xValues);
730  VuoReal *xValueReals = (VuoReal *)VuoListGetData_VuoReal(xValues);
731 
732  VuoList_VuoReal results = VuoListCreateWithCount_VuoReal(xValueCount, 0);
733  VuoReal *resultReals = (VuoReal *)VuoListGetData_VuoReal(results);
734 
735  for (unsigned long i = 0; i < xValueCount; ++i)
736  {
737  if (xLC)
738  *xLC = xValueReals[i];
739  if (xUC)
740  *xUC = xValueReals[i];
741  if (iLC)
742  *iLC = i + 1;
743  if (iUC)
744  *iUC = i + 1;
745 
746  int outputCount;
747  resultReals[i] = mi->muParser.Eval(outputCount)[0];
748  }
749 
750  return results;
751 }