content: package edu.stanford.rsl.conrad.reconstruction;
  
  import edu.stanford.rsl.conrad.data.numeric.Grid2D;
  import edu.stanford.rsl.conrad.geometry.Projection;
  import edu.stanford.rsl.conrad.numerics.SimpleOperators;
  import edu.stanford.rsl.conrad.numerics.SimpleVector;
  import ij.process.FloatProcessor;
  
  
  /**
   * The most simple implementation of the backprojection using no speed-up methods. The name is derived from the example given at <a href="http://www.rabbitct.com/">RabbitCT</a>.
   * Does not include the computation of a volume of interest.
   * @author akmaier
   *
   */
  public class LolaBunnyBackprojector extends VOIBasedReconstructionFilter {
  	/**
  	 * 
  	 */
  	private static final long serialVersionUID = 4887607829631536252L;
  	
  	public LolaBunnyBackprojector(){
  		super();
  		useVOImap = false;
  	}
  
  	@Override
  	public void backproject(Grid2D projection, int projectionNumber) {
  		boolean debug = false;
  		int count = 0;
  		initialize(projection);
  		FloatProcessor currentProjection = new FloatProcessor(projection.getWidth(), projection.getHeight(), projection.getBuffer(), null);
  		
  		// Constant part of distance weighting (D^2) + additional weighting for arbitrary scan ranges
  		double D =  getGeometry().getSourceToDetectorDistance();
  		currentProjection.multiply(10* D*D * 2* Math.PI * getGeometry().getPixelDimensionX() / getGeometry().getNumProjectionMatrices());
  		
  		int p = projectionNumber;
  		double[] voxel = new double [4];
  		voxel[3] = 1;
  		for (int k = 0; k < maxK ; k++){ // for all slices
  			voxel[2] = (this.getGeometry().getVoxelSpacingZ() * k) - offsetZ;
  			for (int i=0; i < maxI; i++){ // for all lines
  				voxel[0] = (this.getGeometry().getVoxelSpacingX() * i) - offsetX;
  				for (int j = 0; j < maxJ; j++){ // for all voxels
  					// compute real world coordinates in homogenious coordinates;
  					//if (voiMap[i][j][k]){
  						voxel[1] = (this.getGeometry().getVoxelSpacingY() * j) - offsetY;
  						SimpleVector point3d = new SimpleVector(voxel);
  						//Compute coordinates in projection data.
  						Projection Pcurr = getGeometry().getProjectionMatrix(p);
  						SimpleVector point2d = SimpleOperators.multiply(Pcurr.computeP(), point3d);
  						double coordX = point2d.getElement(0) / point2d.getElement(2);
  						double coordY = point2d.getElement(1) / point2d.getElement(2);
  						
  						// back project						
  						double distanceWeight = point2d.getElement(2);
  						double increment = currentProjection.getInterpolatedValue(coordX + lineOffset, coordY)/(distanceWeight*distanceWeight);
  						if (Double.isNaN(increment)){
  							debug = true;
  							if (count < 10) System.out.println("NAN Happened at i = " + i + " j = " + j + " k = " + k + " projection = " + projectionNumber + " x = " + coordX + " y = " + coordY  );
  							increment = 1;
  							count ++;
  						}
  						updateVolume(i, j, k, increment);
  					//}
  				}
  			}
  		}
  		if (debug) {
  			throw new RuntimeException("Encountered NaN in projection!");
  		}
  	}
  	
  
  	@Override
  	public String getMedlineCitation(){
  		return "Rohkohl C, Keck B, Hofmann H, Hornegger J. RabbitCT - an open platform for benchmarking 3D cone-beam reconstruction algorithms. Med Phys 2009 36(9):3940-4.";
  	}
  	
  	@Override
  	public String getToolName(){
  		return "Lola Bunny CPU-based Backprojector";
  	}
  	
  }
  /*
   * Copyright (C) 2010-2014 Andreas Maier
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */