content: package edu.stanford.rsl.conrad.opencl;
  
  import java.util.ArrayList;
  
  import com.jogamp.opencl.CLMemory.Mem;
  
  import edu.stanford.rsl.apps.gui.Citeable;
  import edu.stanford.rsl.apps.gui.GUIConfigurable;
  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.numerics.SimpleVector;
  import edu.stanford.rsl.conrad.utils.FileUtil;
  import edu.stanford.rsl.conrad.utils.XmlUtils;
  
  //TODO: Use our own matrices instead of Jama.Matrix
  
  
  
  
  /**
   * Forward projection expects input of a volumetric phantom scaled to mass density. Projection result {@latex.inline $p(\\vec{x})$} is then the accumulated mass along the ray {@latex.inline $\\vec{x}$} which consists of the line segments {@latex.inline $x_i$} in {@latex.inline $[\\textnormal{cm}]$} with the mass densities {@latex.inline $\\mu_i$} in {@latex.inline $[\\frac{\\textnormal{g}}{\\textnormal{cm}^3}]$}.
   * The actual projection is then computed as:<br>
   * {@latex.inline $$p(\\vec{x}) = \\sum_{i} x_i \\cdot \\mu_i$$}<BR>
   * The projection values are then returned in {@latex.inline $[\\frac{\\textnormal{g}}{\\textnormal{cm}^2}]$}
   * @author akmaier, berger (refactored from CUDA)
   *
   */
  public class OpenCLForwardProjectorWithMotion extends OpenCLForwardProjector implements GUIConfigurable, Citeable {
  
  	/**
  	 * The XML filename where the rigid motion parameters are stored
  	 */
  	private String rotationTranslationFilename = null;
  	
  	@SuppressWarnings("unchecked")
  	public SimpleMatrix[] readInMotionMatrices() {
  
  		SimpleMatrix[] motion = new SimpleMatrix[nrProj];
  		// load data from XML file
  		ArrayList<double[][][]> RotTrans = null;
  		try {
  			if (rotationTranslationFilename == null)
  				rotationTranslationFilename = FileUtil.myFileChoose(".xml", false);
  			
  			RotTrans = (ArrayList<double[][][]>)XmlUtils.importFromXML(rotationTranslationFilename);
  		} catch (Exception e) {
  			e.printStackTrace();
  		}
  		
  		for (int i = 0; i < nrProj; i++) {
  			motion[i] = new SimpleMatrix(4,4);
  			SimpleMatrix rotation = new SimpleMatrix(RotTrans.get(0)[i]);
  			SimpleMatrix translation = new SimpleMatrix(RotTrans.get(1)[i]);
  			motion[i].setSubMatrixValue(0, 0, rotation.transposed());
  			motion[i].setSubMatrixValue(0, 3, translation.multipliedBy(-1));
  			motion[i].setRowValue(3, new SimpleVector(0,0,0,1));
  		}
  		
  		return motion;
  		
  	}
  	
  	
  	/**
  	 * First incorporate the rigid object motion into the projection matrices, then 
  	 * load the inverted projection matrices for all projections and reset the projection data.
  	 * @param projectionNumber
  	 */
  	@Override
  	protected void prepareAllProjections(){
  		if (gInvARmatrix == null)
  			gInvARmatrix = context.createFloatBuffer(3*3*nrProj, Mem.READ_ONLY);
  		if (gSrcPoint == null)
  			gSrcPoint = context.createFloatBuffer(3*nrProj, Mem.READ_ONLY);
  		
  		// load the motion transforms
  		// load data from XML file
  		SimpleMatrix[] motion = readInMotionMatrices();
  		
  		gInvARmatrix.getBuffer().rewind();
  		gSrcPoint.getBuffer().rewind();
  		for (int i=0; i < nrProj; ++i){
  			Projection proj = new Projection(projectionMatrices[i]);
  			proj.setRtValue(SimpleOperators.multiplyMatrixProd(proj.getRt(),motion[i]));
  			computeCanonicalProjectionMatrix(gInvARmatrix, gSrcPoint, proj);
  		}
  		gInvARmatrix.getBuffer().rewind();
  		gSrcPoint.getBuffer().rewind();
  		
  		commandQueue
  		.putWriteBuffer(gSrcPoint, true)
  		.putWriteBuffer(gInvARmatrix, true)
  		.finish();
  	}
  
  }
  /*
   * Copyright (C) 2010-2014 Andreas Maier, Martin Berger, Marco Bögel
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */