package org.simantics.modeling; import org.simantics.basicexpression.Expressions; 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 InvertBasicExpressionVisitorBase { 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 result = visitor.getResult(); if(result == null) return; if(result instanceof Triple) { @SuppressWarnings("unchecked") Triple data = (Triple)result; 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 = (double) (((Number)value).doubleValue() - data.second) / data.first; Object invertedValue = numericValueInType(inverted, value.getClass()); targetVariable.setValue(graph, invertedValue); } } else if (value instanceof Boolean) { // TODO: support 'not' targetVariable.setValue(graph, value); } } } private static Object numericValueInType(double value, Class type) { if (type == Integer.class) { return (int) value; } else if (type == Long.class) { return (long) value; } else if (type == Byte.class) { return (byte) value; } else if (type == Float.class) { return (float) value; } return 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 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 data = (Triple)pair; String key = data.third.replace(MAGIC,"."); return getVariablePath(graph, base, key) != null; } return false; } @SuppressWarnings("unchecked") private static Triple possibleInvertibleExpression(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 result = visitor.getResult(); if (result instanceof Triple) return (Triple) result; return null; } public static Variable possibleInvertibleExpressionReferencedProperty(ReadGraph graph, Variable base, String expression) throws DatabaseException { Triple data = possibleInvertibleExpression(graph, base, expression); if (data == null) return null; String path = getVariablePath(graph, base, data.third.replace(MAGIC, ".")); return path != null ? base.browsePossible(graph, path) : null; } public static Triple possibleInvertibleExpressionReferencedTransformedProperty(ReadGraph graph, Variable base, String expression) throws DatabaseException { Triple data = possibleInvertibleExpression(graph, base, expression); if (data == null) return null; String path = getVariablePath(graph, base, data.third.replace(MAGIC, ".")); if (path == null) return null; Variable targetVariable = base.browsePossible(graph, path); return targetVariable != null ? Triple.make(data.first, data.second, targetVariable) : null; } }