/* 
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.kernel;

import geogebra.kernel.arithmetic.ExpressionNode;
import geogebra.kernel.arithmetic.ExpressionValue;
import geogebra.kernel.arithmetic.ListValue;
import geogebra.kernel.arithmetic.MyDouble;
import geogebra.kernel.arithmetic.MyList;
import geogebra.kernel.arithmetic.NumberValue;
import geogebra.kernel.arithmetic.ValidExpression;
import geogebra.kernel.arithmetic.VectorValue;
import geogebra.main.Application;
import geogebra.util.Unicode;

import java.util.HashSet;

import org.apache.commons.math.complex.Complex;

/** 
 * 
 * @author  Markus
 * @version 
 */
final public class GeoVec2D extends ValidExpression implements MatrixTransformable, VectorValue {        

    public double x = Double.NaN;
    public double y = Double.NaN;    
    
    private int mode; // POLAR or CARTESIAN  
    private static GeoVec2D imaginaryUnit;
    
    private Kernel kernel;
    
    
    /** Creates new GeoVec2D */
    public GeoVec2D(Kernel kernel) {
    	this.kernel = kernel;
    }
    
    /** Creates new GeoVec2D with coordinates (x,y)*/
    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])*/
    public GeoVec2D(Kernel kernel, double [] a) {
    	this(kernel);
        x = a[0];
        y = a[1];
    }
    
    /** Copy constructor */
    public GeoVec2D(GeoVec2D v) {
    	this(v.kernel);
        x = v.x;
        y = v.y;
        mode = v.mode;
    }
    
    public static GeoVec2D getImaginaryUnit(Kernel kernel) {
    	if (imaginaryUnit == null) {
    		imaginaryUnit = new GeoVec2D(kernel, 0, 1);
    		imaginaryUnit.setMode(Kernel.COORD_COMPLEX);
    	}
    	
    	return imaginaryUnit;
    }
    
    public boolean isImaginaryUnit() {
    	return mode == Kernel.COORD_COMPLEX && x == 0 && y == 1;
    }
    
	public ExpressionValue deepCopy(Kernel kernel) {
		return new GeoVec2D(this);
	}   
	
    public void resolveVariables() {     
    }
            
    /** Creates new GeoVec2D as vector between Points P and Q */
    public GeoVec2D(Kernel kernel, GeoPoint p, GeoPoint q) {   
    	this(kernel);    
        x = q.x - p.x;
        y = q.y - p.y;
    }
   
    public void setX(double x) { this.x = x; }
    public void setY(double y) { this.y = y; }
    public void setCoords(double x, double y) {
        this.x = x;
        this.y = y;
    }
    public void setCoords(double [] a) {
        x = a[0];
        y = a[1];
    }
    
    public void setCoords(GeoVec2D v) {
        x = v.x;
        y = v.y;
    }
    
    public void setPolarCoords(double r, double phi) {              
        x = r * Math.cos( phi );
        y = r * Math.sin( phi );  
    } 
   
    final public double getX() { return x; }
    final public double getY() { return y; }  
    final public double getR() {  return length(x, y); }
    final public double getPhi() { return Math.atan2(y, x); }    
    
    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).
     */
    final public double length() {
        return length(x, y);
    } 
    
    /** Calculates the eucilidian length of this 2D vector.
     * The result is sqrt(a[0]^2  + a[1]^2).
     */
    final public static double length(double [] a) {
        return length(a[0], a[1]);
    } 
    
     /** Calculates the euclidian length sqrt(a^2  + b^2).     
     */
    final public static double length(double a, double b) {                
        //return Math.sqrt(a*a + b*b);
        
        /*
         * The Algorithm ist taken
         * from Numerical Recipes, Appendix C, p.949 (Cabs) and
         * avoids overflows.         
         */
        double res;        
        double x = Math.abs(a);
        double y = Math.abs(b);
        
        if ( x == 0 ) 
            res = y;
        else if ( y == 0 )
            res = x;
        else if ( x > y ) {
            double temp = y / x;
            res  = x * Math.sqrt(1.0 + temp * temp);
        } else {
            double temp = x / y;
            res  = y * Math.sqrt(1.0 + temp * temp);
        }
        return res;
               
    } 
    
    /** 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.
     */
    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.
     */
    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.
     */
    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. 
     */
    final public boolean equals(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.
     */
    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
     */
    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
     */
    final public void translate(GeoVec2D v) {
        x += v.x;
        y += v.y;
    }
    
    /**
     * rotate this vector by angle phi
     */
    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
     */
    final public void mirror(GeoPoint Q) {           
        x = 2.0 * Q.inhomX - x;
        y = 2.0 * Q.inhomY - y;
    }
    
    /**
     * mirror transform with angle phi
     *  [ cos(phi)       sin(phi)   ]
     *  [ sin(phi)      -cos(phi)   ]  
     */
    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 */
    final public GeoVec2D add(GeoVec2D a) {
        GeoVec2D res = new GeoVec2D(kernel, 0,0);
        add(this, a, res);
        return res;
    }                
    
    /** c = a + b */
    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
     * */
    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) 
     * */
    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;
    	}
    	
    	ExpressionValue enX = list.getListElement(0).evaluate();
    	ExpressionValue enY = list.getListElement(1).evaluate();
    	
    	if (!enX.isNumberValue() || !enY.isNumberValue()) {
    		c.x = Double.NaN;
    		c.y = Double.NaN;
    		return;    		
    	}
    	
    	c.x = a.x + ((NumberValue)enX).getDouble();
    	c.y = a.y + ((NumberValue)enY).getDouble();
    }
    
    /* vector - 2D list (to give another vector) 
     * */
    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;
    	}
    	
    	ExpressionValue enX = list.getListElement(0).evaluate();
    	ExpressionValue enY = list.getListElement(1).evaluate();
    	
    	if (!enX.isNumberValue() || !enY.isNumberValue()) {
    		c.x = Double.NaN;
    		c.y = Double.NaN;
    		return;    		
    	}
    	
    	if (reverse) {
	    	c.x = a.x - ((NumberValue)enX).getDouble();
	    	c.y = a.y - ((NumberValue)enY).getDouble();
    	} else {
	    	c.x = ((NumberValue)enX).getDouble() - a.x;
	    	c.y = ((NumberValue)enY).getDouble() - a.y;
    	}
    }
    
    /** (xc,yc) = (b - xa, -yx)  ie real - complex 
     * or (xc,yc) = (b - xa, b - yx)  for Vectors/Points
     * */
    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
     * */
    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 */
    final public GeoVec2D sub(GeoVec2D a) {
        GeoVec2D res = new GeoVec2D(kernel, 0,0);
        sub(this, a, res);
        return res;
    }
    
    /** c = a - b */
    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);
    }       
        
    final public void mult(double b) {
        x = b*x;
        y = b*y;
    }
    
    /** c = a * b */
    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 
     * 
     * */
    final public static void complexDivide(GeoVec2D a, GeoVec2D b, GeoVec2D c) {                                       
    	// NB temporary variables *crucial*: a and c can be the same variable
    	//double x1=a.x,y1=a.y,x2=b.x,y2=b.y;
    	// complex division
      //c.x = (x1 * x2 + y1 * y2)/(x2 * x2 + y2 * b.y);
      //c.y = (y1 * x2 - x1 * y2)/(x2 * x2 + y2 * b.y);
      
      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 
     * 
     * */
    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 */
    final public static void complexMultiply(GeoVec2D a, GeoVec2D b, GeoVec2D c) {                                       
    	// NB temporary variables *crucial*: a and c can be the same variable
    	//double x1=a.x,y1=a.y,x2=b.x,y2=b.y;
    	//  do multiply
      //c.x = (x1 * x2 - y1 * y2);
      //c.y = (y2 * x1 + x2 * y1);
    	
    	
      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 */
    final public static void complexPower(GeoVec2D a, NumberValue b, GeoVec2D c) {                                       
        Complex out = new Complex(a.x, a.y);     
        out = out.pow(new Complex(b.getDouble(), 0));
        c.x = out.getReal();
        c.y = out.getImaginary();
      	c.setMode(Kernel.COORD_COMPLEX);
    }

    /** c = sqrt(a) Michael Borcherds 2010-02-07 */
    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 = sqrt(a) Michael Borcherds 2010-02-07 */
    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 = sqrt(a) Michael Borcherds 2010-02-07 */
    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 */
    final public static double arg(GeoVec2D a) {                                       
        return Math.atan2(a.y, a.x);
    }

    /** c = a ^ b Michael Borcherds 2009-03-10 */
    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 */
    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 */
    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 */
    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 */
    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 */
    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);
    }

    final public static void inner(GeoVec2D a, GeoVec2D b, double c) {
        c = a.x * b.x + a.y * b.y;        
    }   

    /*
     * see also GeoVec3D.vectorProduct()
     */
    final public static void vectorProduct(GeoVec2D a, GeoVec2D b, MyDouble c) {
        c.set(a.x * b.y - a.y * b.x);        
    }           
    
    
    final public static void inner(GeoVec2D a, GeoVec2D b, MyDouble c) {
        c.set(a.x * b.x + a.y * b.y);        
    }           
    
    /** c = a / b */
    final public static void div(GeoVec2D a, double b, GeoVec2D c) {
        c.x = a.x / b;
        c.y = a.y / b;
    }        
    
    final public boolean isDefined() {		
		return !(Double.isNaN(x) || Double.isNaN( y));
	}
    
    final public String toString() {
    	if (isImaginaryUnit()){
    		switch (kernel.getCASPrintForm()){
    			case ExpressionNode.STRING_TYPE_MPREDUCE:
    				return "i";
    				
    			default:
//    			case ExpressionNode.STRING_TYPE_GEOGEBRA:
//    			case ExpressionNode.STRING_TYPE_GEOGEBRA_XML:
//    			case ExpressionNode.STRING_TYPE_LATEX:
    				return Unicode.IMAGINARY;
    		}
    	}
    	
		sbToString.setLength(0);
		sbToString.append('(');
		sbToString.append(kernel.format(x));
		sbToString.append(", ");
		sbToString.append(kernel.format(y));
		sbToString.append(')');         
        return sbToString.toString();
    }         
	private StringBuilder sbToString = new StringBuilder(50);
    
    /**
     * interface VectorValue implementation
     */           
    final public GeoVec2D getVector() {
    	if (this.isImaginaryUnit()) 
    		return new GeoVec2D(this);
    	else 
    		return this;
    }        
        
    final public boolean isConstant() {
        return true;
    }
    
    final public boolean isLeaf() {
        return true;
    }             
        
    final public int getMode() {
        return  mode;
    }        
    
    final public ExpressionValue evaluate() { 
    	return getVector(); 
    }
    
    final public HashSet<GeoElement> getVariables() { return null; }
    
    final public void setMode(int mode) {
        this.mode = mode;
    }

	final public String toValueString() {
		return toString();
	}  
	
	public String toLaTeXString(boolean symbolic) {
		return toString();
	}    
    
    
    // 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;
	 }

	 final public boolean isVectorValue() {
		 return true;
	 }
	 
    final public boolean isBooleanValue() {
        return false;
    }

	 final public boolean isPolynomialInstance() {
		 return false;
	 }   
	 
	 final public boolean isTextValue() {
		 return false;
	 }
	 
	 final public boolean isExpressionNode() {
		 return false;
	 }	 	 
	 
    public boolean isListValue() {
        return false;
    }
	 
	 final public boolean contains(ExpressionValue ev) {
		 return ev == this;
	 }
	 
	 /** multiplies 2D vector by a 2x2 matrix
	  * 
	  * @param 2x2 matrix
	  */
	 public void multiplyMatrix(MyList list)
	 {
			if (list.getMatrixCols() != 2 || list.getMatrixRows() != 2) return;
		 
			double a,b,c,d,x1,y1;
			
			a = ((NumberValue)(MyList.getCell(list,0,0).evaluate())).getDouble();
			b = ((NumberValue)(MyList.getCell(list,1,0).evaluate())).getDouble();
			c = ((NumberValue)(MyList.getCell(list,0,1).evaluate())).getDouble();
			d = ((NumberValue)(MyList.getCell(list,1,1).evaluate())).getDouble();
	 
			matrixTransform(a,b,c,d);
	 }
	 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;		
	 }
	 public boolean isMatrixTransformable(){
		 return true;
	 }
	 public GeoElement toGeoElement(){
		 return null;
	 }
	 /** multiplies 2D vector by a 3x3 affine matrix
	  *  a b c
	  *  d e f
	  *  g h i
	  * @param 3x3 matrix
	  * @param 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,x1,y1,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.isVectorValue()) {
				GeoVec2D v = ((VectorValue)rt).getVector();
				xx = v.x;
				yy = v.y;
				
				// consistent with 3D vectors
				zz = 0; 
				vector = true;
				
			} else Application.debug("error in GeoVec2D");
			
			a = ((NumberValue)(MyList.getCell(list,0,0).evaluate())).getDouble();
			b = ((NumberValue)(MyList.getCell(list,1,0).evaluate())).getDouble();
			c = ((NumberValue)(MyList.getCell(list,2,0).evaluate())).getDouble();
			d = ((NumberValue)(MyList.getCell(list,0,1).evaluate())).getDouble();
			e = ((NumberValue)(MyList.getCell(list,1,1).evaluate())).getDouble();
			f = ((NumberValue)(MyList.getCell(list,2,1).evaluate())).getDouble();
			g = ((NumberValue)(MyList.getCell(list,0,2).evaluate())).getDouble();
			h = ((NumberValue)(MyList.getCell(list,1,2).evaluate())).getDouble();
			i = ((NumberValue)(MyList.getCell(list,2,2).evaluate())).getDouble();
			
			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 void setZero() {
			x=0;
			y=0;
		}

		public boolean isVector3DValue() {
			// TODO Auto-generated method stub
			return false;
		}
		
		public String toOutputValueString() {
			return toValueString();
		}

		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;
		}

		
}
