content: package edu.stanford.rsl.conrad.geometry.trajectories;
  
  import edu.stanford.rsl.conrad.geometry.Projection;
  import edu.stanford.rsl.conrad.numerics.SimpleMatrix;
  import edu.stanford.rsl.conrad.numerics.SimpleOperators;
  import edu.stanford.rsl.conrad.utils.DoubleArrayUtil;
  
  public class ExtrapolatedTrajectory extends
  		Trajectory {
  
  	/**
  	 * 
  	 */
  	private static final long serialVersionUID = 800597336777372574L;
  	private boolean debug = false;
  
  	
  	/**
  	 * @return the debug
  	 */
  	public boolean isDebug() {
  		return debug;
  	}
  
  	/**
  	 * @param debug the debug to set
  	 */
  	public void setDebug(boolean debug) {
  		this.debug = debug;
  	}
  
  	public ExtrapolatedTrajectory(){
  		super();
  	}
  	
  	public ExtrapolatedTrajectory (Trajectory source){
  		super(source);
  	}
  	
  	/**
  	 * Computes a rotation matrix around z axis in homogeneous coordinates. Angle is supposed to be in radians.
  	 * @param angularIncrement
  	 * @return the rotation matrix
  	 */
  	public static SimpleMatrix getHomogeneousRotationMatrixZ(double angularIncrement){
  		double [][] transitionLeft = new double [4][4];
  		double cos = Math.cos(angularIncrement);
  		double sin = Math.sin(angularIncrement);
  		// Rotation around z axis with increment of averageAngularIncrement in homogeneous coordinates:
  		transitionLeft[0][0]= cos;
  		transitionLeft[0][1]= -sin;
  		transitionLeft[1][0]= sin;
  		transitionLeft[1][1]= cos;
  		transitionLeft[2][2]= 1;
  		transitionLeft[3][3] =1;
  		return new SimpleMatrix(transitionLeft);
  	}
  	
  	public void extrapolateProjectionGeometry(){
  		double fanAngle = Math.atan(((this.detectorWidth * pixelDimensionX)) / sourceToDetectorDistance)  / Math.PI * 180;
  		double [] minmax = DoubleArrayUtil.minAndMaxOfArray(primaryAngles);
  		double range = minmax[1] - minmax[0];
  		double minimumRange = 180 + fanAngle;
  		double notCovered = minimumRange - range;
  		if (notCovered > 0) { // too bad. We have less projections than the minimal set. So we have to fix this!
  			// compute number of missing projections in each direction;
  			int numSteps = (int) (Math.ceil((notCovered / averageAngularIncrement) / 2))+1;
  			int newProjectionNumber = numProjectionMatrices + (numSteps *  2);
  			Projection [] newMatrices = new Projection[newProjectionNumber];
  			double [] newAngles = new double[newProjectionNumber];
  			double radIncrement = averageAngularIncrement / 180 * Math.PI;
  			SimpleMatrix transitionLeft = ExtrapolatedTrajectory.getHomogeneousRotationMatrixZ(radIncrement);
  			SimpleMatrix transitionRight = ExtrapolatedTrajectory.getHomogeneousRotationMatrixZ(-radIncrement);
  			// set references to the known area to the existing matrixes
  			for (int i = 0; i < numProjectionMatrices; i++){
  				newMatrices[i + numSteps] = projectionMatrices[i];
  				newAngles[i + numSteps] = primaryAngles[i];
  			}
  			// Move the matrices towards the unknown area on the left side
  			for (int i = 0; i < numSteps; i++){
  				newMatrices[numSteps - i -1] = new Projection(SimpleOperators.multiplyMatrixProd(newMatrices[numSteps - i].computeP(), transitionLeft));
  				newAngles[numSteps - i -1] = newAngles[numSteps - i] - averageAngularIncrement;
  			}
  			// Move the matrices toward the unknown area on the right side
  			for (int i = 0; i < numSteps; i++){
  				newMatrices[numSteps + i + numProjectionMatrices] = new Projection(SimpleOperators.multiplyMatrixProd(newMatrices[numSteps + i + numProjectionMatrices -1].computeP(),transitionRight));
  				newAngles[numSteps + i + numProjectionMatrices] = newAngles[numSteps + i + numProjectionMatrices -1] + averageAngularIncrement;
  			}
  			projectionMatrices = newMatrices;
  			numProjectionMatrices = newProjectionNumber;
  			primaryAngles = newAngles;
  		}
  	}
  
  
  
  	
  }
  /*
   * Copyright (C) 2010-2014 Andreas Maier
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */
  