package org.geogebra.common.kernel.arithmetic; import java.util.ArrayList; import java.util.Map; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.algos.AlgoElement; import org.geogebra.common.kernel.algos.Algos; import org.geogebra.common.kernel.algos.ConstructionElement; import org.geogebra.common.kernel.geos.GeoCasCell; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoNumeric; /** * Arbitrary constant comming from native CAS * * Each scope (cas cell or CAS using algo) should have an own instance of this * class */ public class MyArbitraryConstant { /** arbitrary integer */ public static final int ARB_INT = 0; /** arbitrary double */ public static final int ARB_CONST = 1; /** arbitrary complex number */ public static final int ARB_COMPLEX = 2; private ArrayList<GeoNumeric> consts = new ArrayList<GeoNumeric>(), ints = new ArrayList<GeoNumeric>(), complexNumbers = new ArrayList<GeoNumeric>(); private ConstructionElement ce; /** * Creates new arbitrary constant handler * * @param ce * associated construction element */ public MyArbitraryConstant(ConstructionElement ce) { this.ce = ce; } private int position = 0; /** * @param myDouble * constant index (global) * @return real constant */ public GeoNumeric nextConst(double myDouble) { return nextConst(consts, ce.getConstruction().constsM, "c", myDouble); } /** * @param myDouble * constant index (global) * @return integer constant */ public GeoNumeric nextInt(double myDouble) { return nextConst(ints, ce.getConstruction().intsM, "k", myDouble); } /** * @param myDouble * constant index (global) * @return complex constant */ public GeoNumeric nextComplex(double myDouble) { return nextConst(complexNumbers, ce.getConstruction().complexNumbersM, "c", myDouble); } /** * Returns a number for this scope that corresponds to given native index * * @param consts2 * all constants of given type (integer / real / complex) in this * scope cached from last computation * * @param map * maps geo labels to constants in the whole construction * @param prefix * prefix fro this constant type: c for real / complex, k for * integer * @param index * index we got from native CAS, we assume it's getting bigger * with each computation but two constants with the same name * always refer to the same number eg * {x+arbonst(10),2x+arbconst(10)+arbconst(9)} * @return element of consts2; if one with a given index already exists in * map take that one, otherwise pick the next one from consts2 (or * create one if there are not enough) */ protected GeoNumeric nextConst(ArrayList<GeoNumeric> consts2, Map<Integer, GeoNumeric> map, String prefix, double index) { Integer indexInt = Integer.valueOf((int) Math.round(index)); GeoNumeric found = map.get(indexInt); if (found != null) { return found; } Construction c = ce.getConstruction(); if (position >= consts2.size() || consts2.get(position) == null) { GeoNumeric add = new GeoNumeric(c); add.setSendValueToCas(false); // GGB-810 // don't use constants as auxiliary objects // add.setAuxiliaryObject(true); boolean oldLabeling = c.isSuppressLabelsActive(); c.setSuppressLabelCreation(false); // let construction know that we need new constant // after geoCasCell update c.setNotXmlLoading(true); add.setLabel(c.getIndexLabel(prefix)); c.setNotXmlLoading(false); c.setSuppressLabelCreation(oldLabeling); AlgoDependentArbconst algo = new AlgoDependentArbconst(c, add, ce); c.removeFromConstructionList(algo); consts2.add(position, add); position++; map.put(indexInt, add); add.setIsDependentConst(true); return add; } GeoNumeric ret = consts2.get(position); map.put(indexInt, ret); // put existent constant into construction // after geoCasCell update if (c.isFileLoading()) { c.addToConstructionList(ret, false); c.putLabel(ret); } else { c.putLabel(ret); } position++; return ret; } /** * Resets the handler; must be called before the first next*() call in each * update of the CAS algo that is creating arbconsts */ public void reset() { position = 0; } /** * Gets arbconst * * @param i * index of arbconst within this handler * @return arbconst */ public GeoNumeric getConst(int i) { return consts.get(i); } /** * Return the list of constants * * @return consts */ public ArrayList<GeoNumeric> getConstList() { if (consts != null) { return consts; } return null; } /** * @return cas cell that contains the constant */ public GeoCasCell getCasCell() { if (isCAS()) { return (GeoCasCell) ce; } return null; } /** * @param ce * - geoCasCell */ public void setCasCell(GeoCasCell ce) { if (isCAS()) { this.ce = ce; } } /** * @return number of arbconsts, arbcomplexes and arbints together */ public int getTotalNumberOfConsts() { return consts.size() + ints.size() + complexNumbers.size(); } /** * Ensures that update of the constant (if visualised as slider) triggers * update of resulting geo. This is not meant to be contained in * construction protocol. * */ public static class AlgoDependentArbconst extends AlgoElement { private GeoElement constant; private ConstructionElement outCE; // private ArrayList<AlgoElement> updateList; /** * @param c * construction * @param constant * the constant as a (complex) number * @param outCE * element that needs updating if the constant changes */ public AlgoDependentArbconst(Construction c, GeoElement constant, ConstructionElement outCE) { super(c, false); this.constant = constant; this.outCE = outCE; /** * if(outCE instanceof AlgoElement){ updateList = new ArrayList * <AlgoElement>(); updateList.add((AlgoElement)outCE); } */ setInputOutput(); } @Override protected void setInputOutput() { input = new GeoElement[] { constant }; setDependencies(); } @Override public void compute() { if (outCE instanceof AlgoElement && ((AlgoElement) outCE).getOutputLength() == 1) { ((AlgoElement) outCE).getOutput(0).updateCascade(); } else if (outCE instanceof GeoCasCell) { outCE.update(); if (((GeoCasCell) outCE).getTwinGeo() != null) { ((GeoCasCell) outCE).getTwinGeo().update(); } } else if (outCE != null) { outCE.update(); } } @Override public Algos getClassName() { return Algos.Expression; } /** * For cas cells replace CAS cell with the right cell on given row */ public void replaceOutCE() { if (outCE instanceof GeoCasCell) { this.outCE = cons .getCasCell(((GeoCasCell) outCE).getRowNumber()); } } } /** * @return whether this handler is bound with CAS cell */ public boolean isCAS() { return ce instanceof GeoCasCell; } /** * TODO having just one position assumes that only one of real / integer / * complex is used * * @return index of next constant */ public int getPosition() { return position; } }