1
+ package org.openrndr.extra.fcurve
2
+
3
+ import org.openrndr.extra.expressions.evaluateExpression
4
+
5
+ /* *
6
+ * expand efcurve to fcurve
7
+ * @param ef an efcurve string
8
+ * @param constants a map of constants that is passed to [evaluateExpression]
9
+ */
10
+ fun efcurve (ef : String , constants : Map <String , Double > = emptyMap()): String {
11
+ val expression = Regex (" _([^_]+)_" )
12
+ val repetition = Regex (" \\ |([^|]+)\\ |\\ [([^\\ [\\ ]]+)]" )
13
+ val list = Regex (" \\ |([^|]+)\\ |\\ {([^\\ [\\ ]]+)}" )
14
+
15
+ /* *
16
+ * perform comment substitution
17
+ * (?m) enables multiline mode
18
+ */
19
+ var curve = Regex (" (?m)(#.*)$" ).replace(ef, " " )
20
+
21
+ /* *
22
+ * Allow for nested repetitions and lists
23
+ */
24
+ do {
25
+ val referenceCurve = curve
26
+
27
+ /* *
28
+ * perform list expansion |text|{items}
29
+ */
30
+ curve = list.replace(curve) { occ ->
31
+ val listText = expression.replace(occ.groupValues[2 ]) { exp ->
32
+ val expressionText = exp.groupValues[1 ]
33
+ evaluateExpression(expressionText, constants)?.toString()
34
+ ? : error(" parse error in repetition count expression '$expressionText '" )
35
+ }
36
+ val listTokens = listText.split(Regex (" [,;][\t\n ]*|[\t\n ]+" ))
37
+ val listItems = listTokens.filter { it.isNotEmpty() }
38
+ .map { it.trim().toDoubleOrNull() ? : error(" '$it ' is not a number in $listTokens " ) }
39
+
40
+ listItems.mapIndexed { index, value ->
41
+ expression.replace(occ.groupValues[1 ]) { exp ->
42
+ val expressionText = exp.groupValues[1 ]
43
+ evaluateExpression(
44
+ exp.groupValues[1 ],
45
+ constants + mapOf (" index" to index.toDouble(), " it" to value)
46
+ )?.toString() ? : error(" parse error in repeated expression '$expressionText '" )
47
+ }
48
+ }.joinToString(" " )
49
+ }
50
+
51
+ /* *
52
+ * perform repetition expansion |text|[repeat-count]
53
+ */
54
+ curve = repetition.replace(curve) { occ ->
55
+ val repetitions = expression.replace(occ.groupValues[2 ]) { exp ->
56
+ val expressionText = exp.groupValues[1 ]
57
+ evaluateExpression(expressionText, constants)?.toInt()?.toString()
58
+ ? : error(" parse error in repetition count expression '$expressionText '" )
59
+ }.toInt()
60
+ List (repetitions) { repetition ->
61
+ expression.replace(occ.groupValues[1 ]) { exp ->
62
+ val expressionText = exp.groupValues[1 ]
63
+ evaluateExpression(exp.groupValues[1 ], constants + mapOf (" it" to repetition.toDouble()))?.toString()
64
+ ? : error(" parse error in repeated expression '$expressionText '" )
65
+ }
66
+ }.joinToString(" " )
67
+ }
68
+ } while (curve != referenceCurve)
69
+
70
+ /* *
71
+ * evaluate expression in expansion
72
+ */
73
+ return (expression.replace(curve) { ef ->
74
+ evaluateExpression(ef.groupValues[1 ], constants)?.toString() ? : error(" parse error in '$curve " )
75
+ })
76
+ }
77
+
78
+ fun main () {
79
+ efcurve(""" M1 |h5 m3|{
80
+ |10.3 # toch wel handig zo'n comment
81
+ |11.2
82
+ |14.5
83
+ |}
84
+ """ .trimMargin())
85
+
86
+ println (efcurve(" |M0 |h4 m3|[2]|[5]" ))
87
+
88
+ println (efcurve(""" M0|h4 m_it_|{|_cos(it * PI * 0.5)_ |[4]}""" ))
89
+ }
0 commit comments