package org.geogebra.common.kernel.arithmetic; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.arithmetic3D.MyVec3DNode; import org.geogebra.common.kernel.geos.GeoDummyVariable; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoNumeric; import org.geogebra.common.kernel.geos.GeoText; import org.geogebra.common.kernel.geos.GeoVec2D; import org.geogebra.common.kernel.geos.GeoVector; import org.geogebra.common.kernel.kernelND.GeoPlaneND; import org.geogebra.common.plugin.Operation; import org.geogebra.common.util.debug.Log; /** * Allows checking whether at least one part of structured expression value has * certain property. * */ public interface Inspecting { /** * Do the local check * * @param v * expression * @return whether this expression itself has given property (not the * subparts) */ public boolean check(ExpressionValue v); /** * Checks whether the expression contains operations <,<=, >, >= * */ public enum IneqFinder implements Inspecting { /** singleton instance */ INSTANCE; @Override public boolean check(ExpressionValue v) { return v.isExpressionNode() && ((ExpressionNode) v).getOperation().isInequality(); } } /** Checks presence of Commands */ public enum CommandFinder implements Inspecting { /** singleton instance */ INSTANCE; @Override public boolean check(ExpressionValue v) { return v instanceof Command; } } /** Checks presence of complex number */ public enum ComplexChecker implements Inspecting { /** singleton instance */ INSTANCE; @Override public boolean check(ExpressionValue v) { return v instanceof GeoVec2D && ((GeoVec2D) v).isImaginaryUnit(); } } /** * Checks for presence of commands and derivatives * */ public enum ExtendedCommandFinder implements Inspecting { /** singleton instance */ INSTANCE; @Override public boolean check(ExpressionValue v) { if (v instanceof Command) { return true; } if (v instanceof ExpressionNode) { ExpressionNode en = (ExpressionNode) v; if (en.getOperation().equals(Operation.DERIVATIVE)) { return true; } } return false; } } /** * Checks if a ValidExpression is unplottable * * @author bencze * @warning it always returns false for MyList, the checking has to be done * manually for each element * */ public class UnplottableChecker implements Inspecting { private boolean isOtherVar; private int nrOfPoints; private static int type, dim; @Override public boolean check(ExpressionValue v) { switch (type) { case 0: // first define the top type of our expression isOtherVar = false; nrOfPoints = 0; break; // Command case 1: return false; // Equation case 2: if (v instanceof MyVec3DNode) { nrOfPoints++; } else if (v.isExpressionNode() && ((ExpressionNode) v) .getLeft() instanceof GeoDummyVariable && ((ExpressionNode) v) .getRight() instanceof MyVec3DNode) { String str = ((ExpressionNode) v).getLeft() .toString(StringTemplate.defaultTemplate); if ("\u03BB".equals(str)) { nrOfPoints++; } } if (v instanceof GeoDummyVariable) { GeoDummyVariable gdv = (GeoDummyVariable) v; String varString = gdv .toString(StringTemplate.defaultTemplate); if (!"x".equals(varString) && !"y".equals(varString) && !"X".equals(varString) && (dim < 3 || !"z".equals(varString))) { if ("\u03BB".equals(varString) && !isOtherVar && nrOfPoints == 2) { return false; } isOtherVar = true; GeoElement subst = gdv.getElementWithSameName(); if (subst != null && (!subst.getSendValueToCas() // skip constants // needed for GGB-810 || (subst.getLabelSimple() != null && subst .getLabelSimple().startsWith("c_")))) { return false; } return true; } if ("x".equals(varString) || "z".equals(varString)) { isOtherVar = true; } } return false; // Function, FunctionNVar case 3: case 10: if (v instanceof GeoDummyVariable) { GeoElement subst = ((GeoDummyVariable) v) .getElementWithSameName(); if (subst != null && (!subst.getSendValueToCas() // skip constants // needed for GGB-810 || (subst.getLabelSimple() != null && subst .getLabelSimple().startsWith("c_")))) { return false; } return true; } return false; // MyBoolean case 4: // MyDouble case 5: // MyList case 6: return false; // ExpressionNode case 11: if (v instanceof GeoDummyVariable) { GeoDummyVariable gdv = (GeoDummyVariable) v; if (!gdv.toString(StringTemplate.defaultTemplate) .equals("x") && !gdv.toString(StringTemplate.defaultTemplate) .equals("y")) { return true; } } else if (!(v instanceof MyDouble || v instanceof ExpressionNode || v instanceof GeoNumeric || v instanceof MyVecNode || v instanceof GeoVector || v instanceof MyList)) { return true; } return false; default: return false; } return setType(v); } private static UnplottableChecker checker = new UnplottableChecker(); private static boolean setType(ExpressionValue v) { if (v instanceof Command) { type = 1; return false; } else if (v instanceof Equation) { ExpressionValue ev = ((Equation) v).getRHS().unwrap(); // TODO needs to have evaluatesTo..., also check for complex if (!ev.evaluatesToNumber(true) && !ev.evaluatesTo3DVector()) { return true; } type = 2; return false; } else if (v instanceof Function) { type = 3; return false; } else if (v instanceof MyBoolean) { type = 4; return true; } else if (v instanceof MyDouble) { type = 5; return false; } else if (v instanceof MyList) { type = 6; return false; } else if (v instanceof Polynomial) { type = 8; return false; } else if (v instanceof Variable || v instanceof GeoDummyVariable) { if (v.toString(StringTemplate.defaultTemplate).equals("x")) { return false; } return true; } else if (v instanceof ExpressionNode) { type = 11; return false; } else if (v instanceof FunctionNVar) { type = 10; return ((FunctionNVar) v).getVarNumber() > 2; } return false; } /** * @param dimension * 2 or 3: in how many dimensions can we plot a point * @return UnplottableChecker singleton instance */ public static UnplottableChecker getChecker(int dimension) { type = 0; dim = dimension; return checker; } } /** * Instead of isConstant we sometimes (always?) want to check only for Geos * that are not labeled, symbolic or dependent ie we don't nned to * distinguish between MyDouble(1) and GeoNumeric(1) */ public static Inspecting dynamicGeosFinder = new Inspecting() { @Override public boolean check(ExpressionValue v) { if (!v.isGeoElement()) { return false; } GeoElement geo = (GeoElement) v; return (!geo.isIndependent() || geo.isLabelSet() || geo.isLocalVariable() || v instanceof GeoDummyVariable || geo.isGeoCasCell() || geo.isRandomGeo()); } }; /** * returns true if strings have been found in the expression (MyStringBuffer * || GeoText) */ public static Inspecting textFinder = new Inspecting() { @Override public boolean check(ExpressionValue v) { return (v instanceof GeoText || v instanceof MyStringBuffer); } }; /** * returns true if Plane have been found in the expression */ public static Inspecting planeFinder = new Inspecting() { @Override public boolean check(ExpressionValue v) { if (v instanceof GeoDummyVariable) { String name = ((GeoDummyVariable) v) .toString(StringTemplate.defaultTemplate); Log.debug(name); GeoElement geo = ((GeoDummyVariable) v).getKernel() .lookupLabel(name); return (geo instanceof GeoPlaneND) || "z".equals(name); } return (v instanceof GeoPlaneND); } }; /** * @author csilla check whether the expression contains only "+" (needed for * Theorem proving) */ public enum PlusChecker implements Inspecting { /** singleton instance */ INSTANCE; @Override public boolean check(ExpressionValue v) { if (v instanceof GeoDummyVariable) { return true; } if (v instanceof ExpressionNode) { ExpressionNode en = (ExpressionNode) v; if (en.getOperation().equals(Operation.PLUS)) { return check(en.getLeft()) && check(en.getRight()); } } return false; } } /** * @author csilla check whether the expression contains only "-" (needed for * Theorem proving) */ public enum MinusChecker implements Inspecting { /** singleton instance */ INSTANCE; @Override public boolean check(ExpressionValue v) { if (v instanceof GeoDummyVariable) { return true; } if (v instanceof ExpressionNode) { ExpressionNode en = (ExpressionNode) v; if (en.getOperation().equals(Operation.MULTIPLY) && en.getLeft() instanceof MyDouble && en.getLeft().evaluateDouble() == -1 && en.getRight() instanceof GeoDummyVariable) { return true; } if (en.getOperation().equals(Operation.MINUS)) { return check(en.getLeft()) && check(en.getRight()); } } return false; } } }