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