]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling/src/org/simantics/modeling/InvertBasicExpressionVisitor.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / InvertBasicExpressionVisitor.java
1 package org.simantics.modeling;\r
2 \r
3 import gnu.trove.map.hash.THashMap;\r
4 \r
5 import java.util.Stack;\r
6 \r
7 import org.simantics.basicexpression.Expressions;\r
8 import org.simantics.basicexpression.analysis.DepthFirstAdapter;\r
9 import org.simantics.basicexpression.node.AConstantValue;\r
10 import org.simantics.basicexpression.node.ADivMultiplicative;\r
11 import org.simantics.basicexpression.node.AMultMultiplicative;\r
12 import org.simantics.basicexpression.node.APlusExpression;\r
13 import org.simantics.basicexpression.node.AVariablePrimary;\r
14 import org.simantics.db.ReadGraph;\r
15 import org.simantics.db.Resource;\r
16 import org.simantics.db.WriteGraph;\r
17 import org.simantics.db.exception.DatabaseException;\r
18 import org.simantics.db.layer0.variable.Variable;\r
19 import org.simantics.scl.compiler.types.Type;\r
20 import org.simantics.structural.stubs.StructuralResource2;\r
21 import org.simantics.utils.datastructures.Pair;\r
22 import org.simantics.utils.datastructures.Triple;\r
23 \r
24 public class InvertBasicExpressionVisitor extends DepthFirstAdapter {\r
25 \r
26         Stack<Object> stack = new Stack<Object>();\r
27 \r
28         public Object getResult() {\r
29                 if(stack.size() != 1) return null; \r
30                 return stack.pop();\r
31         }\r
32 \r
33         public void outAConstantValue(AConstantValue node) {\r
34                 stack.push(Double.valueOf(node.toString()));\r
35         }\r
36 \r
37         @Override\r
38         public void outAVariablePrimary(AVariablePrimary node) {\r
39         String value = node.toString().trim();\r
40         stack.push(Triple.make(1.0, 0.0, value));\r
41         }\r
42         \r
43         @SuppressWarnings("unchecked")\r
44     public void outAPlusExpression(APlusExpression node) {\r
45                 \r
46                 final Object o1 = stack.pop();\r
47                 final Object o2 = stack.pop();\r
48                 \r
49                 if(o1 instanceof Double && o2 instanceof Triple) {\r
50                         Triple<Double, Double, String> p = (Triple<Double, Double, String>)o2;\r
51                         stack.push(Triple.make(p.first, p.second + (Double)o1, p.third));\r
52                 } else if (o2 instanceof Double && o1 instanceof Triple) {\r
53                         Triple<Double, Double, String> p = (Triple<Double, Double, String>)o1;\r
54                         stack.push(Triple.make(p.first, p.second + (Double)o2, p.third));\r
55                 } else if (o2 instanceof Double && o1 instanceof Double) {\r
56                         stack.push((Double)o1 + (Double)o2);\r
57                 } else {\r
58                         stack.push(Double.NaN);\r
59                 }\r
60                 \r
61         }\r
62 \r
63         @SuppressWarnings("unchecked")\r
64     public void outAMinusExpression(APlusExpression node) {\r
65                 \r
66                 final Object o1 = stack.pop();\r
67                 final Object o2 = stack.pop();\r
68                 \r
69                 if(o1 instanceof Double && o2 instanceof Triple) {\r
70                         Triple<Double, Double, String> p = (Triple<Double, Double, String>)o2;\r
71                         stack.push(Triple.make(-p.first, (Double)o1 - p.second, p.third ));\r
72                 } else if (o2 instanceof Double && o1 instanceof Triple) {\r
73                         Triple<Double, Double, String> p = (Triple<Double, Double, String>)o1;\r
74                         stack.push(Triple.make(p.first, p.second - (Double)o2, p.third));\r
75                 } else if (o2 instanceof Double && o1 instanceof Double) {\r
76                         stack.push((Double)o1 - (Double)o2);\r
77                 } else {\r
78                         stack.push(Double.NaN);\r
79                 }\r
80                 \r
81         }\r
82 \r
83         @SuppressWarnings("unchecked")\r
84     public void outAMultMultiplicative(AMultMultiplicative node) {\r
85                 \r
86                 final Object o1 = stack.pop();\r
87                 final Object o2 = stack.pop();\r
88                 \r
89                 if(o1 instanceof Double && o2 instanceof Triple) {\r
90                         Triple<Double, Double, String> p = (Triple<Double, Double, String>)o2;\r
91                         stack.push(Triple.make(p.first * (Double)o1, p.second * (Double)o1, p.third));\r
92                 } else if (o2 instanceof Double && o1 instanceof Triple) {\r
93                         Triple<Double, Double, String> p = (Triple<Double, Double, String>)o1;\r
94                         stack.push(Triple.make(p.first * (Double)o2, p.second * (Double)o2, p.third));\r
95                 } else if (o2 instanceof Double && o1 instanceof Double) {\r
96                         stack.push((Double)o1 * (Double)o2);\r
97                 } else {\r
98                         stack.push(Double.NaN);\r
99                 }\r
100                 \r
101         }\r
102 \r
103         @SuppressWarnings("unchecked")\r
104     public void outADivMultiplicative(ADivMultiplicative node) {\r
105                 \r
106                 final Object o1 = stack.pop();\r
107                 final Object o2 = stack.pop();\r
108                 \r
109                 if(o1 instanceof Double && o2 instanceof Triple) {\r
110                         stack.push(Double.NaN);\r
111                 } else if (o2 instanceof Double && o1 instanceof Triple) {\r
112                         Triple<Double, Double, String> p = (Triple<Double,Double, String>)o1;\r
113                         stack.push(Triple.make(p.first / (Double)o2, p.second / (Double)o2, p.third));\r
114                 } else if (o2 instanceof Double && o1 instanceof Double) {\r
115                         stack.push((Double)o1 / (Double)o2);\r
116                 } else {\r
117                         stack.push(Double.NaN);\r
118                 }\r
119                 \r
120         }\r
121 \r
122         private static final String MAGIC = "_111_";\r
123         \r
124         private static String replaced(String expression) {\r
125             return expression.replaceAll("\\.([A-Za-z])", MAGIC + "$1");\r
126         }\r
127         \r
128     public static void invert(WriteGraph graph, Variable base, String expression, Object value) throws DatabaseException {\r
129         InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();\r
130         Expressions.evaluate(replaced(expression), visitor);\r
131         Object pair = visitor.getResult();\r
132         if(pair == null) return;\r
133         if(pair instanceof Triple) {\r
134             @SuppressWarnings("unchecked")\r
135             Triple<Double, Double, String> data = (Triple<Double, Double, String>)pair;\r
136             String key = data.third.replace(MAGIC, ".");\r
137             String path = getVariablePath(graph, base, key);\r
138             Variable targetVariable = base.browse(graph, path);\r
139             if(value instanceof Number) {\r
140                 if(Math.abs(data.first) > 1e-9) {\r
141                     Double inverted = (((Number)value).doubleValue() - data.second) / data.first;\r
142                     targetVariable.setValue(graph, inverted);\r
143                 }\r
144             } else if (value instanceof Boolean) {\r
145                 // TODO: support 'not'\r
146                 targetVariable.setValue(graph, value);\r
147             }\r
148         }\r
149         \r
150     }\r
151     \r
152     private static String getVariablePath(ReadGraph graph, Variable base, String key) throws DatabaseException {\r
153         StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
154         Resource type = base.getPossibleType(graph);\r
155         if(type == null)\r
156             return null;\r
157         boolean procedural = graph.isInstanceOf(type, STR.ProceduralComponentType);\r
158         Pair<String, Type> pair;\r
159         if(procedural)\r
160             pair = graph.sync(new ProceduralSubstructureMapRequest(base)).get(key);\r
161         else\r
162             pair = ComponentTypeSubstructure.forType(graph, type).possibleTypedRVI(key);\r
163         if(pair == null)\r
164             return null;\r
165         return pair.first;\r
166     }\r
167 \r
168     /**\r
169      * @param graph\r
170      * @param base\r
171      * @param expression the expression to check for invertibility. An empty is expression is not invertible.\r
172      * @return\r
173      * @throws DatabaseException\r
174      * @throws NullPointerException for null expression\r
175      */\r
176     public static boolean isInvertible(ReadGraph graph, Variable base, String expression) throws DatabaseException {\r
177         if (expression == null)\r
178             throw new NullPointerException("null expression for variable " + base.getURI(graph));\r
179         if (expression.isEmpty())\r
180             return false;\r
181 \r
182         Resource type = base.getPossibleType(graph);\r
183         if(type == null) return false;\r
184 \r
185         InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();\r
186         Expressions.evaluate(replaced(expression), visitor);\r
187         Object pair = visitor.getResult();\r
188         if(pair == null) return false;\r
189         if(pair instanceof Triple) {\r
190             @SuppressWarnings("unchecked")\r
191             Triple<Double, Double, String> data = (Triple<Double, Double, String>)pair;\r
192             String key = data.third.replace(MAGIC,".");\r
193             return getVariablePath(graph, base, key) != null;\r
194         }\r
195         return false;\r
196         \r
197     }\r
198 \r
199     public static Variable possibleInvertibleExpressionReferencedProperty(ReadGraph graph, Variable base, String expression) throws DatabaseException {\r
200         if (base == null || expression == null || expression.isEmpty())\r
201             return null;\r
202         InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();\r
203         //System.out.println("invert : " + expression + " -> " + replaced(expression) + " for " + base.getURI(graph));\r
204         Expressions.evaluate(replaced(expression), visitor);\r
205         Object pair = visitor.getResult();\r
206         if(pair == null)\r
207             return null;\r
208         if(pair instanceof Triple) {\r
209             @SuppressWarnings("unchecked")\r
210             Triple<Double, Double, String> data = (Triple<Double, Double, String>)pair;\r
211             String key = data.third.replace(MAGIC,".");\r
212             String path = getVariablePath(graph, base, key);\r
213             Variable targetVariable = base.browsePossible(graph, path);\r
214             return targetVariable;\r
215         }\r
216         return null;\r
217     }\r
218 \r
219 }\r