package org.geogebra.common.kernel.arithmetic; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.arithmetic3D.MyVec3DNode; import org.geogebra.common.kernel.kernelND.GeoCurveCartesianND; import org.geogebra.common.plugin.Operation; /** * Functions for csymbolic computation with vectors */ public class VectorArithmetic { /** * @param kernel * kernel for output expression * @param left * left subtree * @param right * right subtree * @param operation * operation * @return x(left)*x(right)+y(left)*y(right) */ static ExpressionNode expandScalarProduct(Kernel kernel, ExpressionValue left, ExpressionValue right, Operation operation) { if (operation == Operation.MULTIPLY && left.evaluatesToNonComplex2DVector() && right.evaluatesToNonComplex2DVector()) { return scalarProductComponent(kernel, 0, left, right) .plus(scalarProductComponent(kernel, 1, left, right)); } if (operation == Operation.MULTIPLY && left.evaluatesTo3DVector() && right.evaluatesTo3DVector()) { return scalarProductComponent(kernel, 0, left, right) .plus(scalarProductComponent(kernel, 1, left, right)) .plus(scalarProductComponent(kernel, 2, left, right)); } if (operation == Operation.POWER && left.evaluatesToNonComplex2DVector() && ExpressionNode.isConstantDouble(right, 2)) { return scalarProductComponent(kernel, 0, left, left) .plus(scalarProductComponent(kernel, 1, left, left)); } if (operation == Operation.POWER && left.evaluatesTo3DVector() && ExpressionNode.isConstantDouble(right, 2)) { return scalarProductComponent(kernel, 0, left, left) .plus(scalarProductComponent(kernel, 1, left, left).plus( scalarProductComponent(kernel, 2, left, left))); } return null; } /** * @param kernel0 * target kernel, ignored ATM */ private static ExpressionNode scalarProductComponent(Kernel kernel0, int i, ExpressionValue left1, ExpressionValue right1) { return computeCoord(left1.wrap(), i, kernel0).multiply( computeCoord(right1.wrap(), i, kernel0)); } /** * @param exp * expression * @param i * 0 for x, 1 for y, 2 for z * @return given coordinate of expression */ public static ExpressionNode computeCoord(ExpressionNode exp, int i) { return computeCoord(exp, i, exp.getKernel()); } private static ExpressionNode computeCoord(ExpressionNode exp, int i, Kernel kernel) { Operation[] ops = new Operation[] { Operation.XCOORD, Operation.YCOORD, Operation.ZCOORD }; if (exp.isLeaf()) { ExpressionValue coord = extractCoord(exp, i, kernel); if (coord != null) { return coord.traverse(new CoordComputer()).wrap(); } } switch (exp.getOperation()) { case VEC_FUNCTION: if (exp.getLeft() instanceof GeoCurveCartesianND) { ExpressionNode parent = ((GeoCurveCartesianND) exp.getLeft()) .getFun(i) .getExpression().deepCopy(kernel); return parent.replace( ((GeoCurveCartesianND) exp.getLeft()).getFun(i) .getFunctionVariable(), exp.getRight()).wrap(); } return new ExpressionNode(kernel, exp.traverse(new CoordComputer()), ops[i], null); case IF: return new ExpressionNode(kernel, exp.getLeft().deepCopy(kernel), Operation.IF, computeCoord(exp.getRightTree(), i)); case PLUS: return computeCoord(exp.getLeftTree(), i).plus( computeCoord(exp.getRightTree(), i)); case MINUS: return computeCoord(exp.getLeftTree(), i).subtract( computeCoord(exp.getRightTree(), i)); case MULTIPLY: if (exp.getRight().evaluatesToNDVector()) { ExpressionNode ret = matrixMulVector(exp, i, kernel); if (ret != null) { return ret; } return computeCoord(exp.getRightTree(), i).multiply( exp.getLeft()); } else if (exp.getLeft().evaluatesToNDVector()) { return computeCoord(exp.getLeftTree(), i).multiply( exp.getRight()); } default: return new ExpressionNode(kernel, exp, ops[i], null); } } private static ExpressionNode matrixMulVector(ExpressionNode exp, int i, Kernel kernel) { if (exp.getLeft().unwrap() instanceof ListValue && exp.getLeft().unwrap().getListDepth() == 2 && ((ListValue) exp.getLeft().unwrap()).size() > i) { ListValue lv = (ListValue) ((ListValue) exp.getLeft()) .getListElement(i); if (lv.size() == 2 || lv.size() == 3) { ExpressionNode sum = new ExpressionNode(kernel, 0); for (int j = 0; j < lv.size(); j++) { sum = sum.plus(computeCoord(exp.getRightTree(), j) .multiply(lv.getListElement(j))); } return sum; } } return null; } private static ExpressionValue extractCoord(ExpressionNode exp, int i, Kernel kernel) { if (exp.getLeft() instanceof MyVecNode && ((MyVecNode) exp.getLeft()) .getMode() == Kernel.COORD_CARTESIAN) { return i == 0 ? ((MyVecNode) exp.getLeft()).getX().wrap() : (i == 1 ? ((MyVecNode) exp.getLeft()).getY().wrap() : new ExpressionNode(kernel, 0)); } if (exp.getLeft() instanceof MyVecNode && ((MyVecNode) exp.getLeft()) .getMode() == Kernel.COORD_POLAR) { if (i == 2) { return new ExpressionNode(kernel, 0); } return ((MyVecNode) exp.getLeft()).getX().wrap() .multiply(((MyVecNode) exp.getLeft()).getY().wrap() .apply(i == 0 ? Operation.COS : Operation.SIN)); } if (exp.getLeft() instanceof MyVec3DNode && (((MyVec3DNode) exp.getLeft()) .getMode() == Kernel.COORD_CARTESIAN || ((MyVec3DNode) exp.getLeft()) .getMode() == Kernel.COORD_CARTESIAN_3D)) { return i == 0 ? ((MyVec3DNode) exp.getLeft()).getX().wrap() : (i == 1 ? ((MyVec3DNode) exp.getLeft()).getY().wrap() : ((MyVec3DNode) exp.getLeft()).getZ().wrap()); } return null; } }