Java tutorial
/* 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. */ /* * GeoVec2D.java * * Created on 31. August 2001, 11:34 */ package geogebra.common.kernel.geos; import geogebra.common.kernel.Kernel; import geogebra.common.kernel.StringTemplate; import geogebra.common.kernel.Matrix.Coords; import geogebra.common.kernel.arithmetic.ExpressionNode; import geogebra.common.kernel.arithmetic.ExpressionNodeConstants.StringType; import geogebra.common.kernel.arithmetic.ExpressionValue; import geogebra.common.kernel.arithmetic.ListValue; import geogebra.common.kernel.arithmetic.MyDouble; import geogebra.common.kernel.arithmetic.MyList; import geogebra.common.kernel.arithmetic.NumberValue; import geogebra.common.kernel.arithmetic.ValidExpression; import geogebra.common.kernel.arithmetic.VectorNDValue; import geogebra.common.kernel.arithmetic.VectorValue; import geogebra.common.kernel.kernelND.GeoPointND; import geogebra.common.kernel.kernelND.GeoVecInterface; import geogebra.common.main.App; import geogebra.common.util.MyMath; import geogebra.common.util.Riemann; import geogebra.common.util.Unicode; import java.util.HashSet; import org.apache.commons.math.complex.Complex; /** * * @author Markus */ final public class GeoVec2D extends ValidExpression implements VectorValue, GeoVecInterface { private double x = Double.NaN; private double y = Double.NaN; private int mode; // POLAR or CARTESIAN private Kernel kernel; /** * Creates new GeoVec2D * * @param kernel * kernel */ public GeoVec2D(Kernel kernel) { this.kernel = kernel; } /** * Creates new GeoVec2D with coordinates (x,y) * * @param kernel * kernel * @param x * x-coord * @param y * y-coord */ public GeoVec2D(Kernel kernel, double x, double y) { this(kernel); this.x = x; this.y = y; } /** * Creates new GeoVec2D with coordinates (a[0],a[1]) * * @param kernel * kernel * @param a * coordinates */ public GeoVec2D(Kernel kernel, double[] a) { this(kernel); x = a[0]; y = a[1]; } /** * Copy constructor * * @param v * vector to copy */ public GeoVec2D(GeoVec2D v) { this(v.kernel); x = v.x; y = v.y; mode = v.mode; } /** * @return true for imaginary unit */ public boolean isImaginaryUnit() { return mode == Kernel.COORD_COMPLEX && x == 0 && y == 1; } public ExpressionValue deepCopy(Kernel kernel2) { return new GeoVec2D(this); } public void resolveVariables() { // do nothing } /** * Creates new GeoVec2D as vector between Points P and Q * * @param kernel * kernel * @param p * start point * @param q * end point */ public GeoVec2D(Kernel kernel, GeoPoint p, GeoPoint q) { this(kernel); x = q.getX() - p.getX(); y = q.getY() - p.getY(); } /** * @param x * new x-coord */ public void setX(double x) { this.x = x; } /** * @param y * new y-coord */ public void setY(double y) { this.y = y; } /** * @param x * new x-coord * @param y * new y-coord */ public void setCoords(double x, double y) { this.x = x; this.y = y; } /** * @param a * array with coords */ public void setCoords(double[] a) { x = a[0]; y = a[1]; } /** * Copy coords from other vector * * @param v * orher vector */ public void setCoords(GeoVec2D v) { x = v.x; y = v.y; } /** * @param r * radius * @param phi * phase */ public void setPolarCoords(double r, double phi) { x = r * Math.cos(phi); y = r * Math.sin(phi); } /** * @return x-coord */ final public double getX() { return x; } /** * @return y-coord */ final public double getY() { return y; } /** * @return radius (polar) */ final public double getR() { return MyMath.length(x, y); } /** * @return phase (polar) */ final public double getPhi() { return Math.atan2(y, x); } /** * @return coordinates as array */ final public double[] getCoords() { double[] res = { x, y }; return res; } /** * Calculates the eucilidian length of this 2D vector. The result is * sqrt(x^2 + y^2). * * @return length of this vector */ final public double length() { return MyMath.length(x, y); } /** * Changes this vector to a vector with the same direction and orientation, * but length 1. */ final public void makeUnitVector() { double len = this.length(); x = x / len; y = y / len; } /** * Returns a new vector with the same direction and orientation, but length * 1. * * @return unit vector with same direction */ final public GeoVec2D getUnitVector() { double len = this.length(); return new GeoVec2D(kernel, x / len, y / len); } /** * Returns the coordinates of a vector with the same direction and * orientation, but length 1. * * @return normalized coords */ final public double[] getUnitCoords() { double len = this.length(); double[] res = { x / len, y / len }; return res; } /** * Calculates the inner product of this vector and vector v. * * @param v * other vector * @return this * v */ final public double inner(GeoVec2D v) { return x * v.x + y * v.y; } /** * Yields true if the coordinates of this vector are equal to those of * vector v. * * @param v * other vector * @return true if both vectors have equal coords */ final public boolean isEqual(GeoVec2D v) { return Kernel.isEqual(x, v.x) && Kernel.isEqual(y, v.y); } /** * Yields true if this vector and v are linear dependent This is done by * calculating the determinant of this vector an v: this = v <=> det(this, * v) = nullvector. * * @param v * other vector * @return true if this is linear dependent on v */ final public boolean linDep(GeoVec2D v) { // v = l* w <=> det(v, w) = o return Kernel.isZero(det(this, v)); } /** * calculates the determinant of u and v. det(u,v) = u1*v2 - u2*v1 * * @param u * u * @param v * v * @return determinant of {u,v} */ final public static double det(GeoVec2D u, GeoVec2D v) { return u.x * v.y - u.y * v.x; /* * // symmetric operation // det(u,v) = -det(v,u) if (u.objectID < * v.objectID) { return u.x * v.y - u.y * v.x; } else { return -(v.x * * u.y - v.y * u.x); } */ } /** * translate this vector by vector v * * @param v * translation vector */ final public void translate(GeoVec2D v) { x += v.x; y += v.y; } /** * rotate this vector by angle phi * * @param phi * angle */ final public void rotate(double phi) { double cos = Math.cos(phi); double sin = Math.sin(phi); double x0 = x * cos - y * sin; y = x * sin + y * cos; x = x0; } /** * mirror this point at point Q * * @param Q * mirror point */ final public void mirror(Coords Q) { x = 2.0 * Q.getX() - x; y = 2.0 * Q.getY() - y; } /** * mirror transform with angle phi [ cos(phi) sin(phi) ] [ sin(phi) * -cos(phi) ] * * @param phi * parameter */ final public void mirror(double phi) { double cos = Math.cos(phi); double sin = Math.sin(phi); double x0 = x * cos + y * sin; y = x * sin - y * cos; x = x0; } /** * returns this + a * * @param a * addend * @return this + a */ final public GeoVec2D add(GeoVec2D a) { GeoVec2D res = new GeoVec2D(kernel, 0, 0); add(this, a, res); return res; } /** * c = a + b * * @param a * addend * @param b * addend * @param c * result */ final public static void add(GeoVec2D a, GeoVec2D b, GeoVec2D c) { c.x = a.x + b.x; c.y = a.y + b.y; if (a.getMode() == Kernel.COORD_COMPLEX || b.getMode() == Kernel.COORD_COMPLEX) c.setMode(Kernel.COORD_COMPLEX); } /** * (xc,yc) = (xa + b , yx) ie complex + real for complex nos or (xc,yc) = * (xa + b , yx + b) for Points/Vectors * * @param a * addend * @param b * addend * @param c * result * */ final public static void add(GeoVec2D a, NumberValue b, GeoVec2D c) { if (a.getMode() == Kernel.COORD_COMPLEX) { c.x = a.x + b.getDouble(); c.y = a.y; c.setMode(Kernel.COORD_COMPLEX); } else { c.x = a.x + b.getDouble(); c.y = a.y + b.getDouble(); } } /** * vector + 2D list (to give another vector) * * @param a * addend * @param b * addend * @param c * result * */ final public static void add(GeoVec2D a, ListValue b, GeoVec2D c) { MyList list = b.getMyList(); if (list.size() != 2) { c.x = Double.NaN; c.y = Double.NaN; return; } double enX = list.getListElement(0).evaluateDouble(); double enY = list.getListElement(1).evaluateDouble(); if (Double.isNaN(enX) || Double.isNaN(enY)) { c.x = Double.NaN; c.y = Double.NaN; return; } c.x = a.x + enX; c.y = a.y + enY; } /* * vector - 2D list (to give another vector) */ /** * @param a * minuend * @param b * subtrahend * @param c * result * @param reverse * true to compute subtrahend - minuend */ final public static void sub(GeoVec2D a, ListValue b, GeoVec2D c, boolean reverse) { MyList list = b.getMyList(); if (list.size() != 2) { c.x = Double.NaN; c.y = Double.NaN; return; } double enX = list.getListElement(0).evaluateDouble(); double enY = list.getListElement(1).evaluateDouble(); if (reverse) { c.x = a.x - enX; c.y = a.y - enY; } else { c.x = enX - a.x; c.y = enY - a.y; } } /** * (xc,yc) = (b - xa, -yx) ie real - complex or (xc,yc) = (b - xa, b - yx) * for Vectors/Points * * @param b * minuend * @param a * subtrahend * @param c * result * */ final public static void sub(NumberValue b, GeoVec2D a, GeoVec2D c) { if (a.getMode() == Kernel.COORD_COMPLEX) { c.x = b.getDouble() - a.x; c.y = -a.y; c.setMode(Kernel.COORD_COMPLEX); } else { c.x = b.getDouble() - a.x; c.y = b.getDouble() - a.y; } } /** * (xc,yc) = (xa - b , yx) ie complex - real or (xc,yc) = (xa - b , yx - b) * for Vectors/Points * * @param a * minuend * @param b * subtrahend * @param c * result * */ final public static void sub(GeoVec2D a, NumberValue b, GeoVec2D c) { if (a.getMode() == Kernel.COORD_COMPLEX) { c.x = a.x - b.getDouble(); c.y = a.y; c.setMode(Kernel.COORD_COMPLEX); } else { c.x = a.x - b.getDouble(); c.y = a.y - b.getDouble(); } } /** * returns this - a * * @param a * subtrahend * @return this - subtrahend */ final public GeoVec2D sub(GeoVec2D a) { GeoVec2D res = new GeoVec2D(kernel, 0, 0); sub(this, a, res); return res; } /** * c = a - b * * @param a * minuend * @param b * subtrahend * @param c * result */ final public static void sub(GeoVec2D a, GeoVec2D b, GeoVec2D c) { c.x = a.x - b.x; c.y = a.y - b.y; if (a.getMode() == Kernel.COORD_COMPLEX || b.getMode() == Kernel.COORD_COMPLEX) c.setMode(Kernel.COORD_COMPLEX); } /** * Multiplies this vector by b * * @param b * factor */ final public void mult(double b) { x = b * x; y = b * y; } /** * c = a * b * * @param a * factor * @param b * factor * @param c * result */ final public static void mult(GeoVec2D a, double b, GeoVec2D c) { c.x = a.x * b; c.y = a.y * b; } /** * c = a / b Michael Borcherds 2007-12-09 * * @param a * dividend * @param b * divisor * @param c * result * * */ final public static void complexDivide(GeoVec2D a, GeoVec2D b, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.divide(new Complex(b.x, b.y)); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = a / b Michael Borcherds 2008-08-12 * * @param a * dividend * @param b * divisor * @param c * result * * */ final public static void complexDivide(NumberValue a, GeoVec2D b, GeoVec2D c) { // NB temporary variables *crucial*: a and c can be the same variable // double x1=a.getDouble(), x2 = b.x, y2 = b.y; // complex division // c.x = (x1 * x2 )/(x2 * x2 + y2 * b.y); // c.y = ( - x1 * y2)/(x2 * x2 + y2 * b.y); Complex out = new Complex(a.getDouble(), 0); out = out.divide(new Complex(b.x, b.y)); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = a * b Michael Borcherds 2007-12-09 * * @param a * factor * @param b * factor * @param c * result */ final public static void complexMultiply(GeoVec2D a, GeoVec2D b, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.multiply(new Complex(b.x, b.y)); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = a ^ b Michael Borcherds 2009-03-10 * * @param a * base * @param b * power * @param c * result */ final public static void complexPower(GeoVec2D a, NumberValue b, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.log().multiply(b.getDouble()).exp(); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = sqrt(a) Michael Borcherds 2010-02-07 * * @param a * a * @param c * c */ final public static void complexSqrt(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.sqrt(); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = sin(a) * * @param a * a * @param c * c */ final public static void complexSin(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.sin(); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = cos(a) * * @param a * a * @param c * c */ final public static void complexCos(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.cos(); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = tan(a) * * @param a * a * @param c * c */ final public static void complexTan(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.tan(); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = sinh(a) * * @param a * a * @param c * c */ final public static void complexSinh(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.sinh(); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = cosh(a) * * @param a * a * @param c * c */ final public static void complexCosh(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.cosh(); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = tanh(a) * * @param a * a * @param c * c */ final public static void complexTanh(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.tanh(); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = sec(a) * * @param a * a * @param c * c */ final public static void complexSec(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = Complex.ONE.divide(out.cos()); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = csc(a) * * @param a * a * @param c * c */ final public static void complexCsc(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = Complex.ONE.divide(out.sin()); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = cot(a) * * @param a * a * @param c * c */ final public static void complexCot(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = Complex.ONE.divide(out.tan()); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = sech(a) * * @param a * a * @param c * c */ final public static void complexSech(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = Complex.ONE.divide(out.cosh()); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = csc(a) * * @param a * a * @param c * c */ final public static void complexCsch(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = Complex.ONE.divide(out.sinh()); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = cot(a) * * @param a * a * @param c * c */ final public static void complexCoth(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = Complex.ONE.divide(out.tanh()); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = zeta(a) Michael Borcherds 2010-02-07 * * @param a * a * @param c * c */ final public static void complexZeta(GeoVec2D a, GeoVec2D c) { double[] s = { a.x, a.y }; s = Riemann.zeta(s); c.x = s[0]; // real c.y = s[1]; // imaginary c.setMode(Kernel.COORD_COMPLEX); } /** * c = cbrt(a) Michael Borcherds 2010-02-07 * * @param a * a * @param c * c */ final public static void complexCbrt(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.pow(new Complex(1 / 3d, 0)); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = conjugate(a) Michael Borcherds 2010-02-07 * * @param a * a * @param c * c */ final public static void complexConjugate(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.conjugate(); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = sqrt(a) Michael Borcherds 2010-02-07 * * @param a * a * @return argument of a */ final public static double arg(GeoVec2D a) { return Math.atan2(a.y, a.x); } /** * c = a ^ b Michael Borcherds 2009-03-10 * * @param a * base * @param b * exponent * @param c * result */ final public static void complexPower(NumberValue a, GeoVec2D b, GeoVec2D c) { Complex out = new Complex(a.getDouble(), 0); out = out.pow(new Complex(b.x, b.y)); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = e ^ a Michael Borcherds 2009-03-10 * * @param a * power * @param c * result */ final public static void complexExp(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.exp(); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = natural log(a) Michael Borcherds 2009-03-10 * * @param a * a * @param c * logaritmus of a */ final public static void complexLog(GeoVec2D a, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.log(); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = abs(a) Michael Borcherds 2009-03-10 * * @param a * a * @return absolute value of a */ final public static double complexAbs(GeoVec2D a) { Complex out = new Complex(a.x, a.y); return out.abs(); } /** * c = a ^ b Michael Borcherds 2009-03-14 * * @param a * base * @param b * exponent * @param c * result */ final public static void complexPower(GeoVec2D a, GeoVec2D b, GeoVec2D c) { Complex out = new Complex(a.x, a.y); out = out.pow(new Complex(b.x, b.y)); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * c = a * b Michael Borcherds 2007-12-09 * * @param a * factor * @param b * factor * @param c * result */ final public static void complexMultiply(GeoVec2D a, NumberValue b, GeoVec2D c) { // NB temporary variables *crucial*: a and c can be the same variable // double x1=a.x,y1=a.y,x2=b.getDouble(); // do multiply // c.x = (x1 * x2); // c.y = (x2 * y1); Complex out = new Complex(a.x, a.y); out = out.multiply(new Complex(b.getDouble(), 0)); c.x = out.getReal(); c.y = out.getImaginary(); c.setMode(Kernel.COORD_COMPLEX); } /** * see also GeoVec3D#vectorProduct() * * @param a * factor * @param b * factor * @param c * vector product */ final public static void vectorProduct(GeoVecInterface a, GeoVecInterface b, MyDouble c) { c.set(a.getX() * b.getY() - a.getY() * b.getX()); } /** * @param a * factor * @param b * factor * @param c * inner product */ final public static void inner(GeoVec2D a, GeoVec2D b, MyDouble c) { c.set(a.x * b.x + a.y * b.y); } /** * c = a / b * * @param a * vector * @param b * divisor * @param c * result */ final public static void div(GeoVec2D a, double b, GeoVec2D c) { c.x = a.x / b; c.y = a.y / b; } @Override final public String toString(StringTemplate tpl) { if (isImaginaryUnit()) { switch (tpl.getStringType()) { case GIAC: return "i"; default: // case GEOGEBRA: // case GEOGEBRA_XML: // case LATEX: return Unicode.IMAGINARY; } } else if (mode == Kernel.COORD_COMPLEX) { sbToString.setLength(0); sbToString.append(tpl.leftBracket()); sbToString.append(kernel.format(x, tpl)); sbToString.append(" "); kernel.formatSignedCoefficient(y, sbToString, tpl); sbToString.append(Unicode.IMAGINARY); sbToString.append(tpl.rightBracket()); return sbToString.toString(); } sbToString.setLength(0); if (tpl.getStringType().equals(StringType.GIAC)) { sbToString.append("point"); } sbToString.append('('); sbToString.append(kernel.format(x, tpl)); sbToString.append(", "); sbToString.append(kernel.format(y, tpl)); sbToString.append(')'); return sbToString.toString(); } private StringBuilder sbToString = new StringBuilder(50); /** * interface VectorValue implementation * Make a copy to make sure eg imaginary(i*5*x) returns 5*x */ final public GeoVec2D getVector() { return new GeoVec2D(this); } final public boolean isConstant() { return true; } final public boolean isLeaf() { return true; } final public int getMode() { return mode; } @Override final public ExpressionValue evaluate(StringTemplate tpl) { return getVector(); } final public HashSet<GeoElement> getVariables() { return null; } final public void setMode(int mode) { this.mode = mode; } @Override final public String toValueString(StringTemplate tpl) { return toString(tpl); } public String toLaTeXString(boolean symbolic, StringTemplate tpl) { return toString(tpl); } // abstract methods of GeoElement /* * final public GeoElement copy() { return new GeoVec2D(this); } * * final public void set(GeoElement geo) { GeoVec2D v = (GeoVec2D) geo; * this.x = v.x; this.y = v.y; } * * final public boolean isDefined() { return true; } */ final public boolean isNumberValue() { return false; } @Override final public boolean evaluatesToNonComplex2DVector() { return this.mode != Kernel.COORD_COMPLEX; } @Override final public boolean evaluatesToVectorNotPoint() { return this.mode != Kernel.COORD_COMPLEX; } final public boolean contains(ExpressionValue ev) { return ev == this; } /** * multiplies 2D vector by a 2x2 matrix * * @param list * 2x2 matrix */ public void multiplyMatrix(MyList list) { if (list.getMatrixCols() != 2 || list.getMatrixRows() != 2) return; double a, b, c, d; a = MyList.getCell(list, 0, 0).evaluateDouble(); b = MyList.getCell(list, 1, 0).evaluateDouble(); c = MyList.getCell(list, 0, 1).evaluateDouble(); d = MyList.getCell(list, 1, 1).evaluateDouble(); matrixTransform(a, b, c, d); } /** * ret = list * v * @param list matrix (assume 2x2) * @param v vector * @param ret list * v */ static public void multiplyMatrix(MyList list, GeoVecInterface v, GeoVec2D ret) { double a, b, c, d; a = MyList.getCell(list, 0, 0).evaluateDouble(); b = MyList.getCell(list, 1, 0).evaluateDouble(); c = MyList.getCell(list, 0, 1).evaluateDouble(); d = MyList.getCell(list, 1, 1).evaluateDouble(); Double x1 = a * v.getX() + b * v.getY(); Double y1 = c * v.getX() + d * v.getY(); ret.x = x1; ret.y = y1; } /** * multiplies 2D vector by a 2x2 matrix * * @param list * 2x2 matrix */ public void multiplyMatrixLeft(MyList list) { if (list.getMatrixCols() != 2 || list.getMatrixRows() != 2) return; double a, b, c, d; a = MyList.getCell(list, 0, 0).evaluateDouble(); b = MyList.getCell(list, 1, 0).evaluateDouble(); c = MyList.getCell(list, 0, 1).evaluateDouble(); d = MyList.getCell(list, 1, 1).evaluateDouble(); matrixTransform(a, c, b, d); } /** (1,2)*{{2,0},{0,3}} * Transforms the object using the matrix * a00 a01 * a10 a11 * @param a a00 * @param b a01 * @param c a10 * @param d a11 */ public void matrixTransform(double a, double b, double c, double d) { Double x1 = a * x + b * y; Double y1 = c * x + d * y; x = x1; y = y1; } /** * multiplies 2D vector by a 3x3 affine matrix a b c d e f g h i * * @param list * 3x3 matrix * @param rt * GeoVec3D (as ExpressionValue) to get homogeneous coords from */ public void multiplyMatrixAffine(MyList list, ExpressionValue rt) { if (list.getMatrixCols() != 3 || list.getMatrixRows() != 3) return; double a, b, c, d, e, f, g, h, i, z1, xx = x, yy = y, zz = 1; boolean vector = false; if ((rt instanceof GeoPoint) || (rt instanceof GeoLine)) { GeoVec3D p = (GeoVec3D) rt; // use homogeneous coordinates if available xx = p.x; yy = p.y; zz = p.z; } else if (rt instanceof VectorNDValue) { GeoVecInterface v = ((VectorNDValue) rt).getVector(); xx = v.getX(); yy = v.getY(); // consistent with 3D vectors zz = 0; vector = true; } else if (rt instanceof GeoPointND) { // 3D point GeoPointND p = (GeoPointND) rt; // use inhomogeneous coordinates xx = p.getInhomX(); yy = p.getInhomY(); zz = 1; } else App.debug("error in GeoVec2D"); a = MyList.getCell(list, 0, 0).evaluateDouble(); b = MyList.getCell(list, 1, 0).evaluateDouble(); c = MyList.getCell(list, 2, 0).evaluateDouble(); d = MyList.getCell(list, 0, 1).evaluateDouble(); e = MyList.getCell(list, 1, 1).evaluateDouble(); f = MyList.getCell(list, 2, 1).evaluateDouble(); g = MyList.getCell(list, 0, 2).evaluateDouble(); h = MyList.getCell(list, 1, 2).evaluateDouble(); i = MyList.getCell(list, 2, 2).evaluateDouble(); x = a * xx + b * yy + c * zz; y = d * xx + e * yy + f * zz; z1 = g * xx + h * yy + i * zz; if (!vector) { x = x / z1; y = y / z1; } else { if (!Kernel.isZero(z1)) { // for a Vector, if z1!=0 then the answer can't be represented // by a 2D vector // so set undefined // won't happen when 3rd row of matrix is (0,0,1) x = Double.NaN; y = Double.NaN; } } return; } public String toOutputValueString(StringTemplate tpl) { return toValueString(tpl); } /** * Transforms the object using the matrix * a00 a01 a02 * a10 a11 a12 * a20 a21 a22 * @param a00 a00 * @param a01 a01 * @param a02 a02 * @param a10 a10 * @param a11 a11 * @param a12 a12 * @param a20 a20 * @param a21 a21 * @param a22 a22 */ public void matrixTransform(double a00, double a01, double a02, double a10, double a11, double a12, double a20, double a21, double a22) { double xx = x; double yy = y; double zz = 1; double x1 = a00 * xx + a01 * yy + a02 * zz; double y1 = a10 * xx + a11 * yy + a12 * zz; double z1 = a20 * xx + a21 * yy + a22 * zz; x = x1 / z1; y = y1 / z1; return; } public Kernel getKernel() { return kernel; } @Override public boolean hasCoords() { return true; } public double getZ() { return 0; } /** * @return (Math.round(x), Math.round(y)) */ public GeoVec2D round() { return new GeoVec2D(kernel, Math.round(x), Math.round(y)); } /** * @return (Math.floor(x), Math.floor(y)) */ public GeoVec2D floor() { return new GeoVec2D(kernel, Math.floor(x), Math.floor(y)); } /** * @return (Math.ceil(x), Math.ceil(y)) */ public GeoVec2D ceil() { return new GeoVec2D(kernel, Math.ceil(x), Math.ceil(y)); } public ExpressionNode wrap() { return new ExpressionNode(kernel, this); } }