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).
*/