]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/InvertBasicExpressionVisitor.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/InvertBasicExpressionVisitor.java
new file mode 100644 (file)
index 0000000..75660a1
--- /dev/null
@@ -0,0 +1,219 @@
+package org.simantics.modeling;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import java.util.Stack;\r
+\r
+import org.simantics.basicexpression.Expressions;\r
+import org.simantics.basicexpression.analysis.DepthFirstAdapter;\r
+import org.simantics.basicexpression.node.AConstantValue;\r
+import org.simantics.basicexpression.node.ADivMultiplicative;\r
+import org.simantics.basicexpression.node.AMultMultiplicative;\r
+import org.simantics.basicexpression.node.APlusExpression;\r
+import org.simantics.basicexpression.node.AVariablePrimary;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.scl.compiler.types.Type;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+import org.simantics.utils.datastructures.Pair;\r
+import org.simantics.utils.datastructures.Triple;\r
+\r
+public class InvertBasicExpressionVisitor extends DepthFirstAdapter {\r
+\r
+       Stack<Object> stack = new Stack<Object>();\r
+\r
+       public Object getResult() {\r
+               if(stack.size() != 1) return null; \r
+               return stack.pop();\r
+       }\r
+\r
+       public void outAConstantValue(AConstantValue node) {\r
+               stack.push(Double.valueOf(node.toString()));\r
+       }\r
+\r
+       @Override\r
+       public void outAVariablePrimary(AVariablePrimary node) {\r
+        String value = node.toString().trim();\r
+        stack.push(Triple.make(1.0, 0.0, value));\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+    public void outAPlusExpression(APlusExpression node) {\r
+               \r
+               final Object o1 = stack.pop();\r
+               final Object o2 = stack.pop();\r
+               \r
+               if(o1 instanceof Double && o2 instanceof Triple) {\r
+                       Triple<Double, Double, String> p = (Triple<Double, Double, String>)o2;\r
+                       stack.push(Triple.make(p.first, p.second + (Double)o1, p.third));\r
+               } else if (o2 instanceof Double && o1 instanceof Triple) {\r
+                       Triple<Double, Double, String> p = (Triple<Double, Double, String>)o1;\r
+                       stack.push(Triple.make(p.first, p.second + (Double)o2, p.third));\r
+               } else if (o2 instanceof Double && o1 instanceof Double) {\r
+                       stack.push((Double)o1 + (Double)o2);\r
+               } else {\r
+                       stack.push(Double.NaN);\r
+               }\r
+               \r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+    public void outAMinusExpression(APlusExpression node) {\r
+               \r
+               final Object o1 = stack.pop();\r
+               final Object o2 = stack.pop();\r
+               \r
+               if(o1 instanceof Double && o2 instanceof Triple) {\r
+                       Triple<Double, Double, String> p = (Triple<Double, Double, String>)o2;\r
+                       stack.push(Triple.make(-p.first, (Double)o1 - p.second, p.third ));\r
+               } else if (o2 instanceof Double && o1 instanceof Triple) {\r
+                       Triple<Double, Double, String> p = (Triple<Double, Double, String>)o1;\r
+                       stack.push(Triple.make(p.first, p.second - (Double)o2, p.third));\r
+               } else if (o2 instanceof Double && o1 instanceof Double) {\r
+                       stack.push((Double)o1 - (Double)o2);\r
+               } else {\r
+                       stack.push(Double.NaN);\r
+               }\r
+               \r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+    public void outAMultMultiplicative(AMultMultiplicative node) {\r
+               \r
+               final Object o1 = stack.pop();\r
+               final Object o2 = stack.pop();\r
+               \r
+               if(o1 instanceof Double && o2 instanceof Triple) {\r
+                       Triple<Double, Double, String> p = (Triple<Double, Double, String>)o2;\r
+                       stack.push(Triple.make(p.first * (Double)o1, p.second * (Double)o1, p.third));\r
+               } else if (o2 instanceof Double && o1 instanceof Triple) {\r
+                       Triple<Double, Double, String> p = (Triple<Double, Double, String>)o1;\r
+                       stack.push(Triple.make(p.first * (Double)o2, p.second * (Double)o2, p.third));\r
+               } else if (o2 instanceof Double && o1 instanceof Double) {\r
+                       stack.push((Double)o1 * (Double)o2);\r
+               } else {\r
+                       stack.push(Double.NaN);\r
+               }\r
+               \r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+    public void outADivMultiplicative(ADivMultiplicative node) {\r
+               \r
+               final Object o1 = stack.pop();\r
+               final Object o2 = stack.pop();\r
+               \r
+               if(o1 instanceof Double && o2 instanceof Triple) {\r
+                       stack.push(Double.NaN);\r
+               } else if (o2 instanceof Double && o1 instanceof Triple) {\r
+                       Triple<Double, Double, String> p = (Triple<Double,Double, String>)o1;\r
+                       stack.push(Triple.make(p.first / (Double)o2, p.second / (Double)o2, p.third));\r
+               } else if (o2 instanceof Double && o1 instanceof Double) {\r
+                       stack.push((Double)o1 / (Double)o2);\r
+               } else {\r
+                       stack.push(Double.NaN);\r
+               }\r
+               \r
+       }\r
+\r
+       private static final String MAGIC = "_111_";\r
+       \r
+       private static String replaced(String expression) {\r
+           return expression.replaceAll("\\.([A-Za-z])", MAGIC + "$1");\r
+       }\r
+       \r
+    public static void invert(WriteGraph graph, Variable base, String expression, Object value) throws DatabaseException {\r
+        InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();\r
+        Expressions.evaluate(replaced(expression), visitor);\r
+        Object pair = visitor.getResult();\r
+        if(pair == null) return;\r
+        if(pair instanceof Triple) {\r
+            @SuppressWarnings("unchecked")\r
+            Triple<Double, Double, String> data = (Triple<Double, Double, String>)pair;\r
+            String key = data.third.replace(MAGIC, ".");\r
+            String path = getVariablePath(graph, base, key);\r
+            Variable targetVariable = base.browse(graph, path);\r
+            if(value instanceof Number) {\r
+                if(Math.abs(data.first) > 1e-9) {\r
+                    Double inverted = (((Number)value).doubleValue() - data.second) / data.first;\r
+                    targetVariable.setValue(graph, inverted);\r
+                }\r
+            } else if (value instanceof Boolean) {\r
+                // TODO: support 'not'\r
+                targetVariable.setValue(graph, value);\r
+            }\r
+        }\r
+        \r
+    }\r
+    \r
+    private static String getVariablePath(ReadGraph graph, Variable base, String key) throws DatabaseException {\r
+        StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+        Resource type = base.getPossibleType(graph);\r
+        if(type == null)\r
+            return null;\r
+        boolean procedural = graph.isInstanceOf(type, STR.ProceduralComponentType);\r
+        Pair<String, Type> pair;\r
+        if(procedural)\r
+            pair = graph.sync(new ProceduralSubstructureMapRequest(base)).get(key);\r
+        else\r
+            pair = ComponentTypeSubstructure.forType(graph, type).possibleTypedRVI(key);\r
+        if(pair == null)\r
+            return null;\r
+        return pair.first;\r
+    }\r
+\r
+    /**\r
+     * @param graph\r
+     * @param base\r
+     * @param expression the expression to check for invertibility. An empty is expression is not invertible.\r
+     * @return\r
+     * @throws DatabaseException\r
+     * @throws NullPointerException for null expression\r
+     */\r
+    public static boolean isInvertible(ReadGraph graph, Variable base, String expression) throws DatabaseException {\r
+        if (expression == null)\r
+            throw new NullPointerException("null expression for variable " + base.getURI(graph));\r
+        if (expression.isEmpty())\r
+            return false;\r
+\r
+        Resource type = base.getPossibleType(graph);\r
+        if(type == null) return false;\r
+\r
+        InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();\r
+        Expressions.evaluate(replaced(expression), visitor);\r
+        Object pair = visitor.getResult();\r
+        if(pair == null) return false;\r
+        if(pair instanceof Triple) {\r
+            @SuppressWarnings("unchecked")\r
+            Triple<Double, Double, String> data = (Triple<Double, Double, String>)pair;\r
+            String key = data.third.replace(MAGIC,".");\r
+            return getVariablePath(graph, base, key) != null;\r
+        }\r
+        return false;\r
+        \r
+    }\r
+\r
+    public static Variable possibleInvertibleExpressionReferencedProperty(ReadGraph graph, Variable base, String expression) throws DatabaseException {\r
+        if (base == null || expression == null || expression.isEmpty())\r
+            return null;\r
+        InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();\r
+        //System.out.println("invert : " + expression + " -> " + replaced(expression) + " for " + base.getURI(graph));\r
+        Expressions.evaluate(replaced(expression), visitor);\r
+        Object pair = visitor.getResult();\r
+        if(pair == null)\r
+            return null;\r
+        if(pair instanceof Triple) {\r
+            @SuppressWarnings("unchecked")\r
+            Triple<Double, Double, String> data = (Triple<Double, Double, String>)pair;\r
+            String key = data.third.replace(MAGIC,".");\r
+            String path = getVariablePath(graph, base, key);\r
+            Variable targetVariable = base.browsePossible(graph, path);\r
+            return targetVariable;\r
+        }\r
+        return null;\r
+    }\r
+\r
+}\r