@@ -267,7 +267,8 @@ class CycleNode final : public CalculatorNode {
267267
268268// -------------------------------------------------------------------
269269
270- class RandomNode final : public CalculatorNode {
270+ class RandomNode : public CalculatorNode {
271+ protected:
271272 std::unique_ptr<CalculatorNode> m_seed, m_min, m_max, m_arg;
272273
273274public:
@@ -312,6 +313,48 @@ class RandomNode final : public CalculatorNode {
312313 }
313314};
314315
316+ // -------------------------------------------------------------------
317+
318+ class PeriodicRandomNode final : public RandomNode {
319+ std::unique_ptr<CalculatorNode> m_period;
320+
321+ public:
322+ PeriodicRandomNode (Calculator *calc) : RandomNode(calc), m_period() {}
323+
324+ void setPeriod (CalculatorNode *arg) {
325+ assert (m_period.get () == 0 );
326+ m_period.reset (arg);
327+ }
328+
329+ double compute (double vars[3 ]) const override {
330+ double s = (m_seed.get () != 0 ) ? m_seed->compute (vars) : 0 ;
331+ double period = m_period->compute (vars);
332+ if (period == 0 ) period = 1 ;
333+ double f = m_arg->compute (vars);
334+
335+ double f0 = period * std::floor (f / period);
336+ double f1 = period * (std::floor (f / period) + 1 );
337+ double ratio = (f - f0) / (f1 - f0);
338+
339+ double r0 = RandomManager::instance ()->getValue (s, fabs (f0));
340+ double r1 = RandomManager::instance ()->getValue (s, fabs (f1));
341+ double r = (1 - ratio) * r0 + ratio * r1;
342+
343+ if (m_min.get () == 0 )
344+ if (m_max.get () == 0 )
345+ return r;
346+ else
347+ return m_max->compute (vars) * r;
348+ else
349+ return (1 - r) * m_min->compute (vars) + r * m_max->compute (vars);
350+ }
351+
352+ void accept (CalculatorNodeVisitor &visitor) override {
353+ RandomNode::accept (visitor);
354+ if (m_period.get ()) m_period->accept (visitor);
355+ }
356+ };
357+
315358// ===================================================================
316359// Patterns
317360// -------------------------------------------------------------------
@@ -538,7 +581,8 @@ class QuestionTernaryPattern final : public Pattern {
538581 bool matchToken (const std::vector<Token> &previousTokens,
539582 const Token &token) const override {
540583 int i = (int )previousTokens.size ();
541- return ((i == 1 && token.getText () == " ?" ) || (i == 3 && token.getText () == " :" ));
584+ return ((i == 1 && token.getText () == " ?" ) ||
585+ (i == 3 && token.getText () == " :" ));
542586 }
543587 bool isFinished (const std::vector<Token> &previousTokens,
544588 const Token &token) const override {
@@ -648,7 +692,7 @@ class FunctionPattern : public Pattern {
648692 const Token &token) const override {
649693 if (previousTokens.empty ()) return false ;
650694 return ((m_minArgCount == 0 && previousTokens.size () == 1 &&
651- token.getText () != " (" ) ||
695+ token.getText () != " (" ) ||
652696 (previousTokens.back ().getText () == " )" ));
653697 }
654698 TokenType getTokenType (const std::vector<Token> &previousTokens,
@@ -692,11 +736,11 @@ class FunctionPattern : public Pattern {
692736 while (k > 0 ) nodes[--k] = popNode (stack);
693737 } else {
694738 while (k > 1 ) nodes[--k] = popNode (stack);
695- nodes[0 ] = new VariableNode (calc, CalculatorNode::FRAME);
739+ nodes[0 ] = new VariableNode (calc, CalculatorNode::FRAME);
696740 }
697741
698742 // add default values
699- for (int i = 0 ; i < m; i++)
743+ for (int i = 0 ; i < m; i++)
700744 nodes[n - m + i] = new NumberNode (calc, m_optionalArgDefaults[i]);
701745 }
702746};
@@ -843,6 +887,36 @@ class RandomPattern final : public FunctionPattern {
843887 }
844888};
845889
890+ // -------------------------------------------------------------------
891+
892+ class PeriodicRandomPattern final : public FunctionPattern {
893+ bool m_seed;
894+
895+ public:
896+ PeriodicRandomPattern (std::string functionName, bool seed,
897+ std::string description)
898+ : FunctionPattern(functionName, seed ? 2 : 1 ), m_seed(seed) {
899+ allowImplicitArg (true );
900+ addOptionalArg (0 );
901+ addOptionalArg (0 );
902+ setDescription (description);
903+ }
904+ void createNode (Calculator *calc, std::vector<CalculatorNode *> &stack,
905+ const std::vector<Token> &tokens) const override {
906+ int n = ((int )tokens.size () - 1 ) / 2 ;
907+ n--;
908+ if (m_seed) n--;
909+ PeriodicRandomNode *randomNode = new PeriodicRandomNode (calc);
910+ if (n > 0 ) {
911+ randomNode->setMax (popNode (stack));
912+ if (n > 1 ) randomNode->setMin (popNode (stack));
913+ }
914+ if (m_seed) randomNode->setSeed (popNode (stack));
915+ randomNode->setPeriod (popNode (stack));
916+ stack.push_back (randomNode);
917+ }
918+ };
919+
846920// ===================================================================
847921
848922class PatternTable {
@@ -1085,7 +1159,7 @@ class Saw {
10851159 double operator ()(double x, double length, double height) const {
10861160 if (length <= 0.0 ) return 0.0 ;
10871161 if (height <= 0.0 ) height = length;
1088- double q = x / length;
1162+ double q = x / length;
10891163 return height * (q - floor (q));
10901164 }
10911165};
@@ -1224,6 +1298,33 @@ Grammar::Grammar() : m_imp(new Imp()) {
12241298 " 0,max)\n rnd_s(seed,min,max)\n " +
12251299 rnd_s_desc));
12261300
1301+ const std::string rnd_p_desc =
1302+ rnd_desc + " ; values are interpolated in periodic intervals" ;
1303+ addPattern (new PeriodicRandomPattern (
1304+ " random_p" , false ,
1305+ " random_p(period) = random_p(period,0,1)\n random_p(period,max) = "
1306+ " random_p(period,0,max)\n random_p(period,min,max)\n " +
1307+ rnd_p_desc));
1308+ addPattern (new PeriodicRandomPattern (
1309+ " rnd_p" , false ,
1310+ " rnd_p(period) = rnd_p(period,0,1)\n rnd_p(period,max) = "
1311+ " rnd_p(period,0,max)\n rnd_p(period,min,max)\n " +
1312+ rnd_p_desc));
1313+ const std::string rnd_ps_desc =
1314+ rnd_s_desc + " ; values are interpolated in periodic intervals" ;
1315+ addPattern (new PeriodicRandomPattern (
1316+ " random_ps" , true ,
1317+ " random_ps(period,seed) = random_ps(period,seed, "
1318+ " 0,1)\n random_ps(period,seed,max) = random_ps(period,seed, "
1319+ " 0,max)\n random_ps(period,seed,min,max)\n " +
1320+ rnd_ps_desc));
1321+ addPattern (new PeriodicRandomPattern (
1322+ " rnd_ps" , true ,
1323+ " rnd_ps(period,seed) = rnd_ps(period,seed, "
1324+ " 0,1)\n rnd_ps(period,seed,max) = rnd_ps(period,seed, "
1325+ " 0,max)\n rnd_ps(period,seed,min,max)\n " +
1326+ rnd_ps_desc));
1327+
12271328 addPattern (new CyclePattern (" cycle" ));
12281329}
12291330
0 commit comments