package org.geogebra.common.plugin;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.Path;
import org.geogebra.common.kernel.Region;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.arithmetic.BooleanValue;
import org.geogebra.common.kernel.arithmetic.ExpressionNodeConstants;
import org.geogebra.common.kernel.arithmetic.ExpressionNodeEvaluator;
import org.geogebra.common.kernel.arithmetic.ExpressionValue;
import org.geogebra.common.kernel.arithmetic.Functional;
import org.geogebra.common.kernel.arithmetic.ListValue;
import org.geogebra.common.kernel.arithmetic.MyBoolean;
import org.geogebra.common.kernel.arithmetic.MyDouble;
import org.geogebra.common.kernel.arithmetic.MyList;
import org.geogebra.common.kernel.arithmetic.MyNumberPair;
import org.geogebra.common.kernel.arithmetic.MyVecNode;
import org.geogebra.common.kernel.arithmetic.NumberValue;
import org.geogebra.common.kernel.arithmetic.TextValue;
import org.geogebra.common.kernel.arithmetic.VectorNDValue;
import org.geogebra.common.kernel.arithmetic.VectorValue;
import org.geogebra.common.kernel.arithmetic3D.MyVec3DNode;
import org.geogebra.common.kernel.arithmetic3D.Vector3DValue;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoLine;
import org.geogebra.common.kernel.geos.GeoList;
import org.geogebra.common.kernel.geos.GeoVec2D;
import org.geogebra.common.kernel.geos.ParametricCurve;
import org.geogebra.common.kernel.kernelND.Geo3DVecInterface;
import org.geogebra.common.kernel.kernelND.GeoCurveCartesianND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.kernel.kernelND.GeoSurfaceCartesianND;
import org.geogebra.common.kernel.kernelND.GeoVecInterface;
import org.geogebra.common.util.MyMath;
@SuppressWarnings("javadoc")
public enum Operation {
NO_OPERATION {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return null;
}
},
SEQUENCE {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if ((lt.unwrap() instanceof NumberValue)
&& (rt.unwrap() instanceof NumberValue)) {
MyList list = new MyList(ev.getKernel());
double from = Math.round(lt.evaluateDouble());
double to = Math.round(rt.evaluateDouble());
if (from > MyMath.LARGEST_INTEGER
|| from < -MyMath.LARGEST_INTEGER) {
return ev.illegalArgument(lt);
}
if (to > MyMath.LARGEST_INTEGER
|| to < -MyMath.LARGEST_INTEGER) {
return ev.illegalArgument(rt);
}
// also see AlgoSequence.computeRange()
if (from < to) {
// increasing list
for (double k = from; k <= to; k++) {
list.addListElement(new MyDouble(ev.getKernel(), k));
}
} else {
// decreasing list
for (double k = from; k >= to; k--) {
list.addListElement(new MyDouble(ev.getKernel(), k));
}
}
return list;
}
if (!(lt.unwrap() instanceof NumberValue)) {
ev.illegalArgument(lt);
}
return ev.illegalArgument(rt);
}
},
NOT_EQUAL {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
MyBoolean b = ExpressionNodeEvaluator.evalEquals(ev.getKernel(), lt,
rt);
// b can't be null here (findbugs)
// if (b == null) {
// return ev.illegalComparison(lt, rt,
// ExpressionNodeConstants.strNOT_EQUAL);
// }
b.setValue(!b.getBoolean());
return b;
}
},
NOT {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof BooleanValue) {
BooleanValue a = ((BooleanValue) lt);
boolean defined = a.isDefined();
MyBoolean bool = a.getMyBoolean();
bool.setValue(!a.getBoolean());
bool.setDefined(defined);
return bool;
}
return ev.illegalBoolean(lt, ExpressionNodeConstants.strNOT);
}
},
OR {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof BooleanValue && rt instanceof BooleanValue) {
BooleanValue a = ((BooleanValue) lt);
BooleanValue b = ((BooleanValue) rt);
boolean defined = a.isDefined() && b.isDefined();
MyBoolean bool = a.getMyBoolean();
bool.setValue(a.getBoolean() || b.getBoolean());
bool.setDefined(defined);
return bool;
}
return ev.illegalBinary(lt, rt, "IllegalBoolean",
ExpressionNodeConstants.strOR);
}
},
AND {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof BooleanValue && rt instanceof BooleanValue) {
BooleanValue a = ((BooleanValue) lt);
BooleanValue b = ((BooleanValue) rt);
boolean defined = a.isDefined() && b.isDefined();
MyBoolean bool = a.getMyBoolean();
bool.setValue(a.getBoolean() && b.getBoolean());
bool.setDefined(defined);
return bool;
}
return ev.illegalBinary(lt, rt, "IllegalBoolean",
ExpressionNodeConstants.strAND);
}
},
AND_INTERVAL {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return AND.handle(ev, lt, rt, left, right, tpl, holdsLaTeX);
}
},
IMPLICATION {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof BooleanValue && rt instanceof BooleanValue) {
BooleanValue a = ((BooleanValue) lt);
BooleanValue b = ((BooleanValue) rt);
boolean defined = a.isDefined() && b.isDefined();
MyBoolean bool = a.getMyBoolean();
bool.setValue(!a.getBoolean() || b.getBoolean());
bool.setDefined(defined);
return bool;
}
return ev.illegalBinary(lt, rt, "IllegalBoolean",
ExpressionNodeConstants.strNOT);
}
},
EQUAL_BOOLEAN {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
MyBoolean b = ExpressionNodeEvaluator.evalEquals(ev.getKernel(), lt,
rt);
// b can't be null here (findbugs)
// if (b == null) {
// return ev.illegalComparison(lt, rt,
// ExpressionNodeConstants.strNOT_EQUAL);
// }
return b;
}
},
LESS {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof NumberValue) {
double a = ((NumberValue) lt).getDouble();
double b = ((NumberValue) rt).getDouble();
boolean defined = MyDouble.isFinite(a) && MyDouble.isFinite(b);
return new MyBoolean(ev.getKernel(), Kernel.isGreater(b, a),
defined);
}
if (lt instanceof TextValue && rt instanceof TextValue) {
int comp = ((TextValue) lt).toValueString(tpl)
.compareTo(((TextValue) rt).toValueString(tpl));
return new MyBoolean(ev.getKernel(), comp < 0);
}
return ev.illegalComparison(lt, rt, "<");
}
},
GREATER {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof NumberValue) {
double a = ((NumberValue) lt).getDouble();
double b = ((NumberValue) rt).getDouble();
boolean defined = MyDouble.isFinite(a) && MyDouble.isFinite(b);
return new MyBoolean(ev.getKernel(), Kernel.isGreater(a, b),
defined);
}
if (lt instanceof TextValue && rt instanceof TextValue) {
int comp = ((TextValue) lt).toValueString(tpl)
.compareTo(((TextValue) rt).toValueString(tpl));
return new MyBoolean(ev.getKernel(), comp > 0);
}
return ev.illegalComparison(lt, rt, ">");
}
},
LESS_EQUAL {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof NumberValue) {
double a = ((NumberValue) lt).getDouble();
double b = ((NumberValue) rt).getDouble();
boolean defined = MyDouble.isFinite(a) && MyDouble.isFinite(b);
return new MyBoolean(ev.getKernel(),
Kernel.isGreaterEqual(b, a), defined);
}
if (lt instanceof TextValue && rt instanceof TextValue) {
int comp = ((TextValue) lt).toValueString(tpl)
.compareTo(((TextValue) rt).toValueString(tpl));
return new MyBoolean(ev.getKernel(), comp <= 0);
}
return ev.illegalComparison(lt, rt,
ExpressionNodeConstants.strLESS_EQUAL);
}
},
GREATER_EQUAL {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof NumberValue) {
double a = ((NumberValue) lt).getDouble();
double b = ((NumberValue) rt).getDouble();
boolean defined = MyDouble.isFinite(a) && MyDouble.isFinite(b);
return new MyBoolean(ev.getKernel(),
Kernel.isGreaterEqual(a, b), defined);
}
if (lt instanceof TextValue && rt instanceof TextValue) {
int comp = ((TextValue) lt).toValueString(tpl)
.compareTo(((TextValue) rt).toValueString(tpl));
return new MyBoolean(ev.getKernel(), comp >= 0);
}
return ev.illegalComparison(lt, rt,
ExpressionNodeConstants.strGREATER_EQUAL);
}
},
PARALLEL {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if ((lt instanceof GeoLine) && (rt instanceof GeoLine)) {
return new MyBoolean(ev.getKernel(),
((GeoLine) lt).isParallel((GeoLine) rt));
}
return ev.illegalComparison(lt, rt,
ExpressionNodeConstants.strPARALLEL);
}
},
PERPENDICULAR {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if ((lt instanceof GeoLine) && (rt instanceof GeoLine)) {
return new MyBoolean(ev.getKernel(),
((GeoLine) lt).isPerpendicular((GeoLine) rt));
}
return ev.illegalComparison(lt, rt,
ExpressionNodeConstants.strPERPENDICULAR);
}
},
IS_ELEMENT_OF {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (rt instanceof ListValue) {
return new MyBoolean(ev.getKernel(),
MyList.isElementOf(lt, ((ListValue) rt).getMyList()));
}
// checks for 2D or 3D point
if (lt.isGeoElement() && ((GeoElement) lt).isGeoPoint()) {
// check Region before Path (eg Polygon)
if (rt instanceof Region) {
return new MyBoolean(ev.getKernel(),
((Region) rt).isInRegion(((GeoPointND) lt)));
}
if (rt instanceof Path) {
return new MyBoolean(ev.getKernel(), ((Path) rt).isOnPath(
((GeoPointND) lt), Kernel.STANDARD_PRECISION));
}
}
return ev.illegalListOp(lt, rt,
ExpressionNodeConstants.strIS_ELEMENT_OF);
}
},
IS_SUBSET_OF {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof ListValue && rt instanceof ListValue) {
return new MyBoolean(ev.getKernel(),
MyList.listContains(((ListValue) rt).getMyList(),
((ListValue) lt).getMyList(), tpl));
}
return ev.illegalListOp(lt, rt,
ExpressionNodeConstants.strIS_SUBSET_OF);
}
},
IS_SUBSET_OF_STRICT {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof ListValue && rt instanceof ListValue) {
return new MyBoolean(ev.getKernel(),
MyList.listContainsStrict(((ListValue) rt).getMyList(),
((ListValue) lt).getMyList(), tpl));
}
return ev.illegalListOp(lt, rt,
ExpressionNodeConstants.strIS_SUBSET_OF_STRICT);
}
},
SET_DIFFERENCE {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof ListValue && rt instanceof ListValue) {
return MyList.setDifference(ev.getKernel(),
((ListValue) lt).getMyList(),
((ListValue) rt).getMyList());
}
return ev.illegalListOp(lt, rt,
ExpressionNodeConstants.strSET_DIFFERENCE);
}
},
PLUS {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return ev.handlePlus(lt, rt, tpl, holdsLaTeX);
}
},
MINUS {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return ev.handleMinus(lt, rt);
}
},
VECTORPRODUCT {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return ev.handleVectorProduct(lt, rt, tpl, holdsLaTeX);
}
},
// these next three must be adjacent
// so that brackets work for eg a/(b/c)
// and are removed in (a/b)/c
// see case DIVIDE in ExpressionNode
MULTIPLY {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return ev.handleMult(lt, rt, tpl, holdsLaTeX);
}
},
MULTIPLY_OR_FUNCTION {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return ev.handleMult(lt, rt, tpl, holdsLaTeX);
}
},
DIVIDE {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return ev.handleDivide(lt, rt, left, right);
}
},
POWER {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return ev.handlePower(lt, rt, right);
}
},
FREEHAND {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof ListValue) {
double x = ((NumberValue) lt).getDouble();
double ret = Double.NaN;
ListValue list = (ListValue) rt;
if (list instanceof GeoList && ((GeoList) list)
.getElementType() != GeoClass.NUMERIC) {
return new MyDouble(ev.getKernel(), Double.NaN);
}
int n = list.size() - 3;
if (n >= 1) {
double min = ((NumberValue) (list.getListElement(0)))
.getDouble();
double max = ((NumberValue) (list.getListElement(1)))
.getDouble();
if ((min > max) || (x > max) || (x < min)) {
return new MyDouble(ev.getKernel(), Double.NaN);
}
double step = (max - min) / n;
int index = (int) Math.floor((x - min) / step);
if (index > (n - 1)) {
ret = ((NumberValue) (list.getListElement(n + 2)))
.getDouble();
} else {
double y1 = ((NumberValue) (list
.getListElement(index + 2))).getDouble();
double y2 = ((NumberValue) (list
.getListElement(index + 3))).getDouble();
double x1 = min + (index * step);
// linear interpolation between (x1,y1) and
// (x2,y2+step) to give (x,ret)
ret = y1 + (((x - x1) * (y2 - y1)) / step);
}
}
return new MyDouble(ev.getKernel(), ret);
}
return ev.illegalArgument(lt, rt, "freehand(");
}
},
DATA {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof MyNumberPair) {
double x = ((NumberValue) lt).getDouble();
ListValue keyList = (ListValue) ((MyNumberPair) rt).getX();
ListValue valueList = (ListValue) ((MyNumberPair) rt).getY();
if (keyList.size() < 1) {
return new MyDouble(ev.getKernel(), Double.NaN);
}
double max = keyList.getListElement(keyList.size() - 1)
.evaluateDouble();
if (keyList.size() == 1) {
double ret = Double.NaN;
if (Kernel.isEqual(max, x)) {
ret = valueList.getListElement(0).evaluateDouble();
}
return new MyDouble(ev.getKernel(), ret);
}
double min = keyList.getListElement(0).evaluateDouble();
if (max < x || min > x) {
return new MyDouble(ev.getKernel(), Double.NaN);
}
int index = (int) (keyList.size() * (x - min) / (max - min));
index = Math.max(Math.min(index, keyList.size() - 1), 0);
while (index > 0 && keyList.getListElement(index)
.evaluateDouble() >= x) {
index--;
}
while (index < keyList.size() - 1 && keyList
.getListElement(index + 1).evaluateDouble() < x) {
index++;
}
double x1 = keyList.getListElement(index).evaluateDouble();
double x2 = keyList.getListElement(index + 1).evaluateDouble();
double y1 = valueList.getListElement(index).evaluateDouble();
double y2 = valueList.getListElement(index + 1)
.evaluateDouble();
return new MyDouble(ev.getKernel(),
((x - x1) * y2 + y1 * (x2 - x)) / (x2 - x1));
}
return ev.illegalArgument(lt, rt, "dataFunction(");
}
},
COS {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().cos();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sin
GeoVec2D.complexCos(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "cos(");
}
},
SIN {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().sin();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sin
GeoVec2D.complexSin(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "sin(");
}
},
TAN {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().tan();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sin
GeoVec2D.complexTan(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "tan(");
}
},
EXP {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().exp();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex e^z
GeoVec2D.complexExp(vec, vec);
return vec;
} else {
return ev.polynomialOrDie(lt, this, "exp(");
}
}
},
LOG {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().log();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex natural log(z)
GeoVec2D.complexLog(vec, vec);
return vec;
} else {
return ev.polynomialOrDie(lt, this, "log(");
}
}
},
ARCCOS {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().acos(false);
}
return ev.polynomialOrDie(lt, this, "acos(");
}
},
/*
* always returns angle in degrees
*/
ARCCOSD {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().acos(true);
}
return ev.polynomialOrDie(lt, this, "acosd(");
}
},
ARCSIN {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().asin(false);
}
return ev.polynomialOrDie(lt, this, "asin(");
}
},
/*
* always returns angle in degrees
*/
ARCSIND {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().asin(true);
}
return ev.polynomialOrDie(lt, this, "asind(");
}
},
ARCTAN {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().atan(false);
}
return ev.polynomialOrDie(lt, this, "atan(");
}
},
/*
* always returns angle in degrees
*/
ARCTAND {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().atan(true);
}
return ev.polynomialOrDie(lt, this, "atand(");
}
},
ARCTAN2 {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof NumberValue) {
return ((NumberValue) lt).getNumber()
.atan2((NumberValue) rt, false).getNumber();
}
return ev.illegalArgument(lt, rt, "arctan2(");
}
},
ARCTAN2D {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof NumberValue) {
return ((NumberValue) lt).getNumber()
.atan2((NumberValue) rt, true).getNumber();
}
return ev.illegalArgument(lt, rt, "arctan2d(");
}
},
NROOT {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
Kernel kernel = ev.getKernel();
if (rt instanceof NumberValue) {
double n = ((NumberValue) rt).getDouble();
MyDouble exp = new MyDouble(kernel, 1 / n);
if (lt instanceof NumberValue) {
MyDouble root = ((NumberValue) lt).getNumber();
if (Kernel.isGreater(0, root.getDouble())
&& Kernel.isInteger(n) && Math.round(n) % 2 == 1) {
MyDouble.powDoubleSgnChange(root, exp, root);
} else {
MyDouble.pow(root, exp, root);
}
return root;
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sqrt
GeoVec2D.complexPower(vec, exp, vec);
return vec;
}
}
return ev.illegalArgument(lt, rt, "nroot(");
}
},
SQRT {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().sqrt();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sqrt
GeoVec2D.complexSqrt(vec, vec);
return vec;
} else {
return ev.polynomialOrDie(lt, this, "sqrt(");
}
}
},
SQRT_SHORT {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return SQRT.handle(ev, lt, rt, left, right, tpl, holdsLaTeX);
}
},
ABS {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
Kernel kernel = ev.getKernel();
GeoVec2D vec;
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().abs();
} else if (lt instanceof VectorValue) {
vec = ((VectorValue) lt).getVector();
// complex Abs(z)
// or magnitude of point
return new MyDouble(kernel, GeoVec2D.complexAbs(vec));
} else if (lt instanceof Vector3DValue) {
Geo3DVecInterface vec3d = ((Vector3DValue) lt).getVector();
// complex Abs(z)
// or magnitude of point
return new MyDouble(kernel, vec3d.length());
} else {
return ev.polynomialOrDie(lt, Operation.ABS, "abs(");
}
}
},
SGN {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().sgn();
}
return ev.polynomialOrDie(lt, this, "sgn(");
}
},
XCOORD {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt.isGeoElement() && lt instanceof GeoCurveCartesianND) {
return ((GeoCurveCartesianND) lt).getFun(0);
}
return new MyDouble(ev.getKernel(), ev.handleXcoord(lt, this));
}
},
YCOORD {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt.isGeoElement() && lt instanceof GeoCurveCartesianND) {
return ((GeoCurveCartesianND) lt).getFun(1);
}
return new MyDouble(ev.getKernel(), ev.handleYcoord(lt, this));
}
},
ZCOORD {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt.isGeoElement() && lt instanceof GeoCurveCartesianND) {
return ((GeoCurveCartesianND) lt).getFun(2);
}
return new MyDouble(ev.getKernel(), ev.handleZcoord(lt));
}
},
IMAGINARY {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return new MyDouble(ev.getKernel(), ev.handleYcoord(lt, this));
}
},
REAL {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return new MyDouble(ev.getKernel(), ev.handleXcoord(lt, this));
}
},
FRACTIONAL_PART {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().fractionalPart();
}
return ev.polynomialOrDie(lt, this, "fractionalPart(");
}
},
COSH {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().cosh();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sin
GeoVec2D.complexCosh(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "cosh(");
}
},
SINH {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().sinh();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sin
GeoVec2D.complexSinh(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "sinh(");
}
},
TANH {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().tanh();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sin
GeoVec2D.complexTanh(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "tanh(");
}
},
ACOSH {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().acosh();
}
return ev.polynomialOrDie(lt, this, "acosh(");
}
},
ASINH {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().asinh();
}
return ev.polynomialOrDie(lt, this, "asinh(");
}
},
ATANH {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().atanh();
}
return ev.polynomialOrDie(lt, this, "atanh(");
}
},
CSC {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().csc();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sin
GeoVec2D.complexCsc(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "csc(");
}
},
SEC {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().sec();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sin
GeoVec2D.complexSec(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "sec(");
}
},
COT {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().cot();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sin
GeoVec2D.complexCot(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "cot(");
}
},
CSCH {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().csch();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sin
GeoVec2D.complexCsch(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "csch(");
}
},
SECH {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().sech();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sin
GeoVec2D.complexSech(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "sech(");
}
},
COTH {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().coth();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex sin
GeoVec2D.complexCoth(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "coth(");
}
},
FLOOR {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber()
.floor(ev.getKernel().getAngleUnit());
}
if (lt instanceof VectorValue) {
GeoVec2D ret = ((VectorValue) lt).getVector().floor();
// eg complex
ret.setMode(((VectorValue) lt).getMode());
return ret;
}
if (lt instanceof Vector3DValue) {
Geo3DVecInterface ret = ((Vector3DValue) lt).getVector()
.floor();
return ret;
}
return ev.polynomialOrDie(lt, this, "floor(");
}
},
CEIL {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber()
.ceil(ev.getKernel().getAngleUnit());
}
if (lt instanceof VectorValue) {
GeoVec2D ret = ((VectorValue) lt).getVector().ceil();
// eg complex
ret.setMode(((VectorValue) lt).getMode());
return ret;
}
if (lt instanceof Vector3DValue) {
Geo3DVecInterface ret = ((Vector3DValue) lt).getVector().ceil();
return ret;
}
return ev.polynomialOrDie(lt, this, "ceil(");
}
},
FACTORIAL {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().factorial();
}
return ev.polynomialOrDie(lt, this, "", "!");
}
},
ROUND {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber()
.round(ev.getKernel().getAngleUnit());
}
if (lt instanceof VectorValue) {
GeoVec2D ret = ((VectorValue) lt).getVector().round();
// eg complex
ret.setMode(((VectorValue) lt).getMode());
return ret;
}
if (lt instanceof Vector3DValue) {
Geo3DVecInterface ret = ((Vector3DValue) lt).getVector()
.round();
return ret;
}
return ev.polynomialOrDie(lt, this, "round(");
}
},
ROUND2 {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
if (rt instanceof NumberValue
&& (!Double.isNaN(((NumberValue) rt).getDouble())
|| rt.isGeoElement())) {
return ((NumberValue) lt).getNumber().round(
((NumberValue) rt).getDouble(),
ev.getKernel().getAngleUnit());
}
return ((NumberValue) lt).getNumber()
.round(ev.getKernel().getAngleUnit());
}
if (lt instanceof VectorValue) {
GeoVec2D ret = ((VectorValue) lt).getVector().round();
// eg complex
ret.setMode(((VectorValue) lt).getMode());
return ret;
}
if (lt instanceof Vector3DValue) {
Geo3DVecInterface ret = ((Vector3DValue) lt).getVector()
.round();
return ret;
}
return ev.polynomialOrDie(lt, this, "round(");
}
},
GAMMA {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().gamma();
}
return ev.polynomialOrDie(lt, this, "gamma(");
}
},
GAMMA_INCOMPLETE {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof NumberValue) {
return ((NumberValue) rt).getNumber()
.gammaIncomplete((NumberValue) lt);
}
return ev.illegalArgument(lt, rt, "gammaIncomplete");
}
},
GAMMA_INCOMPLETE_REGULARIZED {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof NumberValue) {
return ((NumberValue) rt).getNumber()
.gammaIncompleteRegularized((NumberValue) lt);
}
return ev.illegalArgument(lt, rt, "gammaIncompleteRegularized");
}
},
BETA {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof NumberValue) {
return ((NumberValue) rt).getNumber().beta((NumberValue) lt);
}
return ev.illegalArgument(lt, rt, "beta(");
}
},
BETA_INCOMPLETE {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof VectorValue && rt instanceof NumberValue) {
return ((NumberValue) rt).getNumber()
.betaIncomplete((VectorValue) lt);
}
return ev.illegalArgument(lt, rt, "betaIncomplete(");
}
},
BETA_INCOMPLETE_REGULARIZED {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof VectorValue && rt instanceof NumberValue) {
return ((NumberValue) rt).getNumber()
.betaIncompleteRegularized((VectorValue) lt);
}
return ev.illegalArgument(lt, rt, "betaIncompleteRegularized(");
}
},
ERF {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().erf();
}
return ev.polynomialOrDie(lt, this, "erf(");
}
},
PSI {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().psi();
}
return ev.polynomialOrDie(lt, this, "psi(");
}
},
POLYGAMMA {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof NumberValue) {
return ((NumberValue) rt).getNumber()
.polygamma((NumberValue) lt);
}
return ev.polynomialOrDie(lt, this, "polygamma(");
}
},
LOG10 {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().log10();
}
return ev.polynomialOrDie(lt, this, "log10(");
}
},
LOG2 {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().log2();
}
return ev.polynomialOrDie(lt, this, "log2(");
}
},
LOGB {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue && rt instanceof NumberValue) {
return ((NumberValue) rt).getNumber().log((NumberValue) lt);
}
return ev.illegalArgument(lt, rt, "log(");
}
},
CI {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().cosineIntegral();
}
return ev.polynomialOrDie(lt, this, "cosIntegral(");
}
},
SI {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().sineIntegral();
}
return ev.polynomialOrDie(lt, this, "sinIntegral(");
}
},
EI {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().expIntegral();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
return vec.ei();
}
return ev.polynomialOrDie(lt, this, "expIntegral(");
}
},
CBRT {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().cbrt();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex cbrt
GeoVec2D.complexCbrt(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "cbrt(");
}
},
RANDOM {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return ((NumberValue) lt).getNumber();
}
},
CONJUGATE {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
// complex cbrt
GeoVec2D.complexConjugate(vec, vec);
return vec;
}
return ev.polynomialOrDie(lt, this, "conjugate(");
}
},
ARG {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
Kernel kernel = ev.getKernel();
if (lt instanceof VectorNDValue) {
GeoVecInterface vec = ((VectorNDValue) lt).getVector();
MyDouble ret = new MyDouble(kernel,
Math.atan2(vec.getY(), vec.getX()));
ret.setAngle();
return ret;
} else if (lt instanceof NumberValue) {
return new MyDouble(kernel,
((NumberValue) lt).getDouble() < 0 ? Math.PI : 0);
}
return ev.polynomialOrDie(lt, this, "arg(");
}
},
ALT {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
Kernel kernel = ev.getKernel();
if (lt instanceof VectorValue || lt instanceof NumberValue) {
MyDouble ret = new MyDouble(kernel, 0);
ret.setAngle();
return ret;
} else if (lt instanceof Vector3DValue) {
Geo3DVecInterface vec = ((Vector3DValue) lt).getVector();
double l = MyMath.length(vec.getX(), vec.getY());
MyDouble ret = new MyDouble(kernel, Math.atan2(vec.getZ(), l));
ret.setAngle();
return ret;
}
return ev.polynomialOrDie(lt, this, "alt(");
}
},
FUNCTION {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return ev.handleFunction(lt, rt, left);
}
},
FUNCTION_NVAR {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return ev.handleFunctionNVar(lt, rt);
}
},
VEC_FUNCTION {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (rt instanceof NumberValue) {
NumberValue arg = (NumberValue) rt;
if (lt instanceof GeoCurveCartesianND) {
return ((GeoCurveCartesianND) lt)
.evaluateCurve(arg.getDouble());
}
return ((ParametricCurve) lt).evaluateCurve(arg.getDouble());
}
if (rt instanceof ListValue) {
ListValue arg = (ListValue) rt;
if (lt instanceof GeoSurfaceCartesianND) {
return ((GeoSurfaceCartesianND) lt).evaluateSurface(
arg.getListElement(0).evaluateDouble(),
arg.getListElement(1).evaluateDouble());
}
return ev.illegalArgument(lt);
}
return ev.illegalArgument(rt);
}
},
DERIVATIVE {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (rt instanceof NumberValue) {
if (lt instanceof Functional) { // derivative of GeoFunction
return ((Functional) lt).getGeoDerivative(
(int) Math.round(((NumberValue) rt).getDouble()),
true);
} else if (lt instanceof GeoCurveCartesianND) { // derivative of
// GeoCurveCartesian
return ((GeoCurveCartesianND) lt).getGeoDerivative(
(int) Math.round(((NumberValue) rt).getDouble()));
}
}
return ev.illegalArgument(rt);
}
},
ELEMENT_OF {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return ev.handleElementOf(lt, rt, 0);
}
},
SUBSTITUTION {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return new MyDouble(ev.getKernel(), Double.NaN);
}
},
INTEGRAL {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return new MyDouble(ev.getKernel(), Double.NaN);
}
},
IF {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof BooleanValue) {
if (((BooleanValue) lt).getBoolean()) {
return rt;
}
return rt.getUndefinedCopy(ev.getKernel());
}
return ev.illegalArgument(lt, rt, "if(");
}
},
IF_ELSE {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof MyNumberPair) {
ExpressionValue cond = ((MyNumberPair) lt).getX().evaluate(tpl);
if (cond instanceof BooleanValue) {
if (!((BooleanValue) cond).isDefined()) {
return new MyDouble(ev.getKernel(), Double.NaN);
}
if (((BooleanValue) cond).getBoolean()) {
return ((MyNumberPair) lt).getY().evaluate(tpl);
}
return rt;
}
}
return ev.illegalArgument(lt, rt, "if(");
}
},
IF_LIST {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof MyList && rt instanceof MyList) {
MyList cond = (MyList) lt;
for (int i = 0; i < cond.size(); i++) {
ExpressionValue curr = cond.getListElement(i).evaluate(tpl);
if (curr instanceof BooleanValue) {
if (((BooleanValue) curr).getBoolean()) {
return ((MyList) rt).getListElement(i)
.evaluate(tpl);
}
}
}
return cond.size() == ((MyList) rt).size()
? new MyDouble(ev.getKernel(), Double.NaN)
: ((MyList) rt).getListElement(cond.size())
.evaluate(tpl);
}
return ev.illegalArgument(lt, rt, "if(");
}
},
// spreadsheet absolute reference using $ signs
$VAR_ROW {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return lt;
}
},
$VAR_COL {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return lt;
}
},
$VAR_ROW_COL {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return lt;
}
},
ARBCONST {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return new MyDouble(ev.getKernel(), 0.0);
}
},
ARBINT {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return new MyDouble(ev.getKernel(), 0.0);
}
},
ARBCOMPLEX {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return new MyDouble(ev.getKernel(), 0.0);
}
},
SUM {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return new MyDouble(ev.getKernel(), Double.NaN);
}
},
ZETA {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (lt instanceof NumberValue) {
return ((NumberValue) lt).getNumber().zeta();
} else if (lt instanceof VectorValue) {
GeoVec2D vec = ((VectorValue) lt).getVector();
GeoVec2D.complexZeta(vec, vec);
return vec;
} else {
return ev.polynomialOrDie(lt, this, "zeta(");
}
}
},
DIFF {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
return new MyDouble(ev.getKernel(), Double.NaN);
}
},
MATRIXTOVECTOR {
@Override
public ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX) {
if (!(lt.unwrap() instanceof MyList)) {
return lt;
}
MyList list = (MyList) lt.unwrap();
if (list.size() == 3) {
return new MyVec3DNode(ev.getKernel(),
MyList.getCell(list, 0, 0), MyList.getCell(list, 0, 1),
MyList.getCell(list, 0, 2));
}
return new MyVecNode(ev.getKernel(), MyList.getCell(list, 0, 0),
MyList.getCell(list, 0, 1));
}
};
public static boolean isSimpleFunction(Operation op) {
switch (op) {
case SIN:
case COS:
case TAN:
case ARCSIN:
case ARCSIND:
case ARCCOS:
case ARCTAN:
case SINH:
case COSH:
case TANH:
case ASINH:
case ACOSH:
case ATANH:
case CSC:
case SEC:
case COT:
case CSCH:
case SECH:
case COTH:
case EXP:
case ZETA:
case LOG:
case LOG10:
case LOG2:
case SQRT:
case CBRT:
case ERF:
case ABS:
case CI:
case SI:
case EI:
case PSI:
case GAMMA:
return true;
}
return false;
}
public abstract ExpressionValue handle(ExpressionNodeEvaluator ev,
ExpressionValue lt, ExpressionValue rt, ExpressionValue left,
ExpressionValue right, StringTemplate tpl, boolean holdsLaTeX);
public boolean isPlusorMinus() {
return this.equals(PLUS) || this.equals(MINUS);
}
public boolean isInequality() {
return this.equals(GREATER_EQUAL) || this.equals(GREATER)
|| this.equals(LESS) || this.equals(LESS_EQUAL);
}
/**
*
* @param op
* operation eg Operation.SIN
* @return inverse of op eg Operation.ARCSIN
*/
public static Operation inverse(Operation op) {
switch (op) {
case PLUS:
return Operation.MINUS;
case MINUS:
return Operation.PLUS;
case MULTIPLY:
return Operation.DIVIDE;
case DIVIDE:
return Operation.MULTIPLY;
case SIN:
return Operation.ARCSIN;
case COS:
return Operation.ARCCOS;
case TAN:
return Operation.ARCTAN;
case ARCSIN:
case ARCSIND:
return Operation.SIN;
case ARCCOS:
return Operation.COS;
case ARCTAN:
return Operation.TAN;
case SINH:
return Operation.ASINH;
case COSH:
return Operation.ACOSH;
case TANH:
return Operation.ATANH;
case ASINH:
return Operation.SINH;
case ACOSH:
return Operation.COSH;
case ATANH:
return Operation.TANH;
case EXP:
return Operation.LOG;
case LOG:
return Operation.EXP;
default:
return null;
}
}
/**
* @return negation of this expression (optimizes negation of >,<,=>,<=)
*/
public Operation negate() {
switch (this) {
case GREATER:
return Operation.LESS_EQUAL;
case GREATER_EQUAL:
return Operation.LESS;
case LESS:
return Operation.GREATER_EQUAL;
case LESS_EQUAL:
return Operation.GREATER;
case EQUAL_BOOLEAN:
return Operation.NOT_EQUAL;
case NOT_EQUAL:
return Operation.EQUAL_BOOLEAN;
default:
return Operation.NOT;
}
}
/**
* @return operation swapped left to right
*/
public Operation reverseLeftToRight() {
switch (this) {
case GREATER:
return Operation.LESS;
case GREATER_EQUAL:
return Operation.LESS_EQUAL;
case LESS:
return Operation.GREATER;
case LESS_EQUAL:
return Operation.GREATER_EQUAL;
case EQUAL_BOOLEAN:
return Operation.EQUAL_BOOLEAN;
case NOT_EQUAL:
return Operation.NOT_EQUAL;
}
return Operation.NO_OPERATION;
}
public static boolean includesFreehandOrData(Operation op) {
switch (op) {
case DATA:
case FREEHAND:
return true;
}
return false;
}
public static boolean integralIsNonContinuous(Operation op) {
switch (op) {
case ABS:
case SGN:
case FLOOR:
case CEIL:
case ROUND:
case ROUND2:
case TAN:
case COT:
case SEC:
case CSC:
case FRACTIONAL_PART:
case ZETA:
case GAMMA:
case GAMMA_INCOMPLETE:
case GAMMA_INCOMPLETE_REGULARIZED:
case BETA:
case BETA_INCOMPLETE:
case BETA_INCOMPLETE_REGULARIZED:
case POLYGAMMA:
case PSI:
case IF:
case IF_ELSE:
case DATA:
case FREEHAND:
return true;
}
return false;
}
}