/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. */ /* * AlgoDependentNumber.java * * Created on 30. August 2001, 21:37 */ package org.geogebra.common.kernel.algos; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.arithmetic.ExpressionNode; import org.geogebra.common.kernel.arithmetic.ExpressionValue; import org.geogebra.common.kernel.arithmetic.Function; import org.geogebra.common.kernel.arithmetic.FunctionNVar; import org.geogebra.common.kernel.arithmetic.MyBoolean; import org.geogebra.common.kernel.arithmetic.MyList; import org.geogebra.common.kernel.arithmetic.MyStringBuffer; import org.geogebra.common.kernel.arithmetic.NumberValue; import org.geogebra.common.kernel.arithmetic.VectorValue; import org.geogebra.common.kernel.arithmetic3D.Vector3DValue; import org.geogebra.common.kernel.geos.GeoBoolean; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoFunction; import org.geogebra.common.kernel.geos.GeoFunctionNVar; import org.geogebra.common.kernel.geos.GeoList; import org.geogebra.common.kernel.geos.GeoNumeric; import org.geogebra.common.kernel.geos.GeoPoint; import org.geogebra.common.kernel.geos.GeoText; import org.geogebra.common.kernel.geos.GeoVec2D; import org.geogebra.common.kernel.kernelND.Geo3DVecInterface; import org.geogebra.common.kernel.kernelND.GeoPointND; import org.geogebra.common.util.debug.Log; /** * List expression, e.g. with L1 = {3, 2, 1}, L2 = {5, 1, 7} such an expression * could be L1 + L2 */ public class AlgoDependentListExpression extends AlgoElement implements DependentAlgo { private GeoList list; // output /** * Creates new dependent list algo. * * @param cons * construction * @param root * expression deining the list */ public AlgoDependentListExpression(Construction cons, ExpressionNode root) { super(cons); list = new GeoList(cons); list.setDefinition(root); setInputOutput(); // for AlgoElement // compute value of dependent list compute(); } @Override public Algos getClassName() { return Algos.Expression; } // for AlgoElement @Override protected void setInputOutput() { input = list.getDefinition().getGeoElementVariables(); setOutputLength(1); setOutput(0, list); setDependencies(); // done by AlgoElement } /** * Returns the resulting list * * @return resulting list */ public GeoList getList() { return list; } /** * Returns the input expression * * @return input expression */ @Override public ExpressionNode getExpression() { return list.getDefinition(); } // evaluate the current value of the arithmetic tree @Override public final void compute() { // get resulting list of ExpressionNodes ExpressionValue evlist = list.getDefinition() .evaluate(StringTemplate.defaultTemplate); MyList myList = (evlist instanceof MyList) ? (MyList) evlist : ((GeoList) evlist).getMyList(); if (!myList.isDefined()) { list.setUndefined(); return; } list.setDefined(true); int evalListSize = myList.size(); int cachedListSize = list.getCacheSize(); list.clear(); for (int i = 0; i < evalListSize; i++) { ExpressionValue element = myList.getListElement(i) .evaluate(StringTemplate.defaultTemplate); GeoElement cached = null; if (i < cachedListSize) { cached = list.getCached(i); } GeoElement geo = toGeo(element, cached, cons); if (geo != null) { list.add(geo); } } } private static GeoElement toGeo(ExpressionValue element, GeoElement cachedGeo, Construction cons) { GeoElement geo = null; // number result if (element instanceof NumberValue) { ExpressionNode definition = element.isGeoElement() ? ((GeoElement) element).getDefinition() : null; double val = ((NumberValue) element).getDouble(); // try to use cached element of same type if (cachedGeo != null) { // the cached element is a number: set value if (cachedGeo.isGeoNumeric()) { ((GeoNumeric) cachedGeo).setValue(val); geo = cachedGeo; } } // no cached number: create new one if (geo == null) { geo = new GeoNumeric(cons, val); } geo.setDefinition(definition); // add number to list return geo; } // point else if (element instanceof VectorValue) { GeoVec2D vec = ((VectorValue) element).getVector(); // try to use cached element of same type if (cachedGeo != null) { // the cached element is a point: set value if (cachedGeo.isGeoPoint()) { ((GeoPoint) cachedGeo).setCoords(vec); geo = cachedGeo; } } // no cached point: create new one if (geo == null) { GeoPoint point = new GeoPoint(cons); point.setCoords(vec); geo = point; } // add point to list return geo; } // point else if (element instanceof Vector3DValue) { Geo3DVecInterface vec = ((Vector3DValue) element).getVector(); // try to use cached element of same type if (cachedGeo != null) { // the cached element is a point: set value if (cachedGeo.isGeoPoint()) { ((GeoPointND) cachedGeo).setCoords(vec.getX(), vec.getY(), vec.getZ(), 1); geo = cachedGeo; } } // no cached point: create new one if (geo == null) { GeoPoint3D point = new GeoPoint3D(cons); point.setCoords(vec.getX(), vec.getY(), vec.getZ(), 1); geo = point; } // add point to list return geo; } // needed for matrix multiplication // eg {{1,3,5},{2,4,6}}*{{11,14},{12,15},{13,a}} else if (element instanceof MyList) { MyList myList2 = (MyList) element; GeoList list2 = new GeoList(cons); list2.clear(); /* * removed Michael Borcherds 20080602 bug: 9PointCubic.ggb (matrix * multiplication) // try to use cached element of type GeoList * GeoList list2 = null; if (i < cachedListSize) { GeoElement * cachedGeo = list.getCached(i); * * // the cached element is a number: set value if * (cachedGeo.isGeoList()) { list2 = (GeoList) cachedGeo; } } * * if (list2 == null) { list2 = new GeoList(cons); } */ for (int j = 0; j < myList2.size(); j++) { ExpressionValue en = myList2.getListElement(j); ExpressionValue ev = en .evaluate(StringTemplate.defaultTemplate); GeoElement geo2 = toGeo(ev, null, cons); if (geo2 != null) { list2.add(geo2); } } return list2; } else if (element instanceof MyStringBuffer) { MyStringBuffer str = (MyStringBuffer) element; // try to use cached element of same type if (cachedGeo != null) { // the cached element is a point: set value if (cachedGeo.isGeoText()) { ((GeoText) cachedGeo).setTextString( str.toValueString(StringTemplate.defaultTemplate)); geo = cachedGeo; } } // no cached point: create new one if (geo == null) { GeoText text = new GeoText(cons); text.setTextString( str.toValueString(StringTemplate.defaultTemplate)); geo = text; } // add point to list return geo; } else if (element instanceof MyBoolean) { MyBoolean bool = (MyBoolean) element; // try to use cached element of same type if (cachedGeo != null) { // the cached element is a point: set value if (cachedGeo.isGeoBoolean()) { ((GeoBoolean) cachedGeo).setValue(bool.getBoolean()); geo = cachedGeo; } } // no cached point: create new one if (geo == null) { GeoBoolean geoBool = new GeoBoolean(cons); geoBool.setValue(bool.getBoolean()); geo = geoBool; } // add point to list return geo; } else if (element instanceof GeoFunction) { GeoFunction fun = (GeoFunction) element; return getFunction(fun, cachedGeo); } else if (element instanceof GeoText) { GeoText text = (GeoText) element; if (cachedGeo != null) { // the cached element is a point: set value if (cachedGeo.isGeoText()) { ((GeoText) cachedGeo).set(text); geo = cachedGeo; } } // no cached text: create new one if (geo == null) { GeoText geoFun = new GeoText(cons); geoFun.set(text); geo = geoFun; } return geo; } else if (element instanceof Function) { GeoFunction fun = new GeoFunction(cons, (Function) element); return getFunction(fun, cachedGeo); } else if (element instanceof FunctionNVar) { GeoFunctionNVar fun = new GeoFunctionNVar(cons, (FunctionNVar) element); return toGeo(fun, cachedGeo, cons); } else if (element instanceof GeoElement) { GeoElement geo0 = (GeoElement) element; if (cachedGeo != null) { // the cached element is the same type: set value if (cachedGeo.getGeoClassType() .equals(geo0.getGeoClassType())) { cachedGeo.set(geo0); geo = cachedGeo; } } // no cached object: create new one if (geo == null) { geo = geo0.copy(); } return geo; } else { Log.debug("unsupported list operation: " + element.getClass() + ""); return null; } } private static GeoElement getFunction(GeoFunction fun, GeoElement cachedGeo) { GeoElement geo = null; if (cachedGeo != null) { // the cached element is a point: set value if (cachedGeo.isGeoFunction()) { ((GeoFunction) cachedGeo).set(fun); geo = cachedGeo; } } // no cached point: create new one if (geo == null) { GeoFunction geoFun = new GeoFunction(fun.getConstruction()); geoFun.set(fun); geo = geoFun; } return geo; } @Override final public String toString(StringTemplate tpl) { // was defined as e.g. L = 3 * {a, b, c} return list.getDefinition().toString(tpl); } }