content: package edu.stanford.rsl.conrad.fitting;
  
  import edu.stanford.rsl.conrad.numerics.SimpleMatrix;
  import edu.stanford.rsl.conrad.numerics.SimpleOperators;
  import edu.stanford.rsl.conrad.numerics.SimpleVector;
  
  public class Quadric extends Surface {
  
  	/**
  	 * 
  	 */
  	private static final long serialVersionUID = 6104784792939859900L;
  	private int degree =3;
  	private double [] params;
  	
  	public Quadric (){
  		params = new double [degree*degree];
  	}
  	
  	/**
  	 * @return the degree
  	 */
  	public int getDegree() {
  		return degree;
  	}
  
  
  	@Override
  	public double[] getParametersAsDoubleArray() {
  		return params;
  	}
  
  	@Override
  	public void fitToPoints(double[] x, double[] y, double [] z) {
  		// setup observation vector
  		SimpleVector observations = new SimpleVector(x.length);
  		// setup measurement matrix:
  		SimpleMatrix measurements = new SimpleMatrix(x.length, degree*degree);
  		for (int i = 0; i < x.length; i++){
  				measurements.setElementValue(i, 0, Math.pow(x[i], 2));
  				measurements.setElementValue(i, 1, Math.pow(y[i], 2));
  				measurements.setElementValue(i, 2, Math.pow(z[i], 2));
  				measurements.setElementValue(i, 3, x[i]*y[i]);
  				measurements.setElementValue(i, 4, x[i]*z[i]);
  				measurements.setElementValue(i, 5, y[i]*z[i]);
  				measurements.setElementValue(i, 6, x[i]);
  				measurements.setElementValue(i, 7, y[i]);
  				measurements.setElementValue(i, 8, z[i]);
  				
  				observations.setElementValue(i, 1);
  				
  			
  		}
  		SimpleMatrix inverseMeasurements = measurements.inverse(SimpleMatrix.InversionType.INVERT_SVD);
  		SimpleVector parameters = SimpleOperators.multiply(inverseMeasurements, observations);
  		parameters.copyTo(params);
  	}
  	
  	public void fitEllipticParaboloidToPoints(float[] x, float[] y, float [] z) {
  		// setup observation vector
  		SimpleVector observations = new SimpleVector(x.length);
  		// setup measurement matrix:
  		SimpleMatrix measurements = new SimpleMatrix(x.length, degree*degree);
  		for (int i = 0; i < x.length; i++){
  			measurements.setElementValue(i, 0, Math.pow(x[i], 2));
  			measurements.setElementValue(i, 1, Math.pow(y[i], 2));
  			measurements.setElementValue(i, 2, Math.pow(z[i], 2));
  			measurements.setElementValue(i, 3, x[i]*y[i]);
  			measurements.setElementValue(i, 4, x[i]*z[i]);
  			measurements.setElementValue(i, 5, y[i]*z[i]);
  			measurements.setElementValue(i, 6, x[i]);
  			measurements.setElementValue(i, 7, y[i]);
  			measurements.setElementValue(i, 8, z[i]);
  			
  			observations.setElementValue(i, 1);
  				
  			
  		}
  		SimpleMatrix inverseMeasurements = measurements.inverse(SimpleMatrix.InversionType.INVERT_SVD);
  		SimpleVector parameters = SimpleOperators.multiply(inverseMeasurements, observations);
  		parameters.copyTo(params);
  	}
  
  	@Override
  	public double evaluate(double x, double y, double z) {
  		double revan = 0;
  		
  		revan = x*x*params[0] + y*y*params[1] + z*z*params[2] + x*y*params[3] + x*z*params[4] + y*z*params[5] +x*params[6] * y*params[7] + z*params[8] -1;
  		return revan;
  	}
  
  	@Override
  	public String toString() {
  		String revan = " ";
  		
  		return revan;
  	}
  
  	@Override
  	public int getMinimumNumberOfCorrespondences() {
  		return degree*degree;
  	}
  
  }