content: package edu.stanford.rsl.conrad.geometry.trajectories;
  
  //TODO: Use our own matrices instead of Jama.Matrix
  
  import java.io.BufferedReader;
  import java.io.FileReader;
  import java.io.IOException;
  import java.util.ArrayList;
  
  import edu.stanford.rsl.conrad.geometry.Projection;
  import edu.stanford.rsl.conrad.io.ConfigFileParser;
  import edu.stanford.rsl.conrad.numerics.SimpleMatrix;
  import edu.stanford.rsl.conrad.numerics.SimpleOperators;
  import edu.stanford.rsl.conrad.utils.Configuration;
  import edu.stanford.rsl.conrad.utils.ConfigurationUpdater;
  
  
  
  public class SystemGeometryConfigFileTrajectory extends ConfigFileBasedTrajectory implements ConfigurationUpdater, ConfigFileParser {
  
  	private static final long serialVersionUID = 2773005628961913345L;
  	
  	private double [] volumeSize = null;
  	private double [] volumeResolution = null;
  	private double [] detectorResolution = null;
  	private double [] detectorPixels = null;
  	private double averageAngularIncrement = -1;
  	private int numProjections = -1;
  	private SimpleMatrix transformToNextProjection;
  	private double SID = -1;
  	private double SAD = -1;
  	private boolean success = false;
  	
  	private Configuration config = null;
  	
  	
  	public SystemGeometryConfigFileTrajectory(String filename, Trajectory model) throws IOException{
  		super(model);
  		readProjectionMatrices(filename);
  	}
  	
  	public SystemGeometryConfigFileTrajectory(Trajectory model) {
  		super(model);
  	}
  
  	private double [] readDoubleArrayLine(String line){
  		String [] values = line.split("\\s+");
  		ArrayList<String> list = new ArrayList<String>();
  		for(int i = 0; i < values.length; i++){
  			if (! values[i].equals("")) list.add(values[i]);
  		}
  		double [] revan = new double[list.size()];
  		for(int i = 0; i < list.size(); i++){
  			revan[i] = Double.parseDouble(list.get(i));
  		}
  		return revan;
  	}
  	
  	private Projection newProjection (double [][] matrix){
  		return new Projection(new SimpleMatrix(matrix));
  	}
  
  	private void readProjectionMatrices(String projectionConfig) throws IOException{
  		FileReader read = new FileReader(projectionConfig);
  		BufferedReader bufferedReader = new BufferedReader(read);
  		String line = "";
  		//skip first comment line;
  		line = bufferedReader.readLine();
  		// readVolumeInformation
  		volumeResolution = readDoubleArrayLine(bufferedReader.readLine());
  		volumeSize = readDoubleArrayLine(bufferedReader.readLine());
  		// Comment line
  		line = bufferedReader.readLine();
  		// Detector info
  		double [] detectorx = readDoubleArrayLine(bufferedReader.readLine());
  		double [] detectory = readDoubleArrayLine(bufferedReader.readLine());
  		detectorResolution = new double [2];
  		detectorResolution[0] = detectorx[0];
  		pixelDimensionX = detectorx[0];
  		detectorResolution[1] = detectory[1];
  		detectorPixels = readDoubleArrayLine(bufferedReader.readLine());
  		// Comment line
  		line = bufferedReader.readLine();
  		//read number of matrices
  		numProjectionMatrices = Integer.parseInt(bufferedReader.readLine());
  		projectionMatrices = new Projection[numProjectionMatrices];
  		int count = 0;
  		while (count < numProjectionMatrices){ 
  			//read one matrix;
  			double [][] projectionMatrix = readMatrix(bufferedReader, 4, 3);
  			projectionMatrices[count++] = newProjection(projectionMatrix);
  		}
  		if (count != numProjectionMatrices){
  			throw new IOException("Number of Matrices in projection table file does not match the actual number in the file. Please check consistency.");
  		}
  		//read number of projections
  		numProjections = Integer.parseInt(bufferedReader.readLine());
  		transformToNextProjection = new SimpleMatrix(readMatrix(bufferedReader, 4, 4));
  		if (numProjectionMatrices < numProjections){
  			Projection [] newMatrices = new Projection[numProjections];
  			newMatrices[0] = projectionMatrices[0];
  			for (int i = 1; i < numProjections; i++){
  				newMatrices[i] = new Projection(SimpleOperators.multiplyMatrixProd(newMatrices[i-1].computeP(), transformToNextProjection));
  			}
  			projectionMatrices = newMatrices;
  			numProjectionMatrices = numProjections;
  		}
  		double [] [] scaleProjectionCoordinates = new double [3][3];
  		scaleProjectionCoordinates[0][0] = 1.0 / detectorResolution[0];
  		scaleProjectionCoordinates[1][1] = 1.0 / detectorResolution[1];
  		scaleProjectionCoordinates[2][2] = 1.0;
  		Jama.Matrix scale = new Jama.Matrix(scaleProjectionCoordinates);
  		for (int i = 0; i < projectionMatrices.length; i++){
  			projectionMatrices[i] = new Projection(SimpleOperators.multiplyMatrixProd(projectionMatrices[i].computeP().transposed(), new SimpleMatrix(scale)).transposed());
  		}
  		while ((line = bufferedReader.readLine()) != null){
  			String [] elements = line.split("\\s+");
  			if (line.contains("SID")){
  				String target = elements[3];
  				target = target.substring(0, target.length()-2);
  				SID = Double.parseDouble(target);
  			}
  			if (line.contains("Rotation angle per view")){
  				String target = elements[6];
  				target = target.substring(0, target.length());
  				averageAngularIncrement = Double.parseDouble(target);
  			}
  			if (line.contains("SAD")){
  				String target = elements[3];
  				target = target.substring(0, target.length()-2);
  				SAD = Double.parseDouble(target);
  			}
  		}
  		if (averageAngularIncrement != -1){
  			primaryAngles = new double [projectionMatrices.length];
  			double current =0;
  			for (int i = 0; i < primaryAngles.length; i++){
  				primaryAngles[i] = current;
  				current += averageAngularIncrement;
  			}
  			System.out.println(current + " " + averageAngularIncrement);
  		}
  		
  		success = true;
  		bufferedReader.close();
  	}
  
  	private double [][] readMatrix(BufferedReader bufferedReader, int width, int height) throws IOException{
  		double [][] projectionMatrix = new double[height][width];
  		for (int i =0; i<height;i++){
  			String line = bufferedReader.readLine();
  			projectionMatrix[i] = readDoubleArrayLine(line);
  		}
  		return projectionMatrix;
  	}
  	
  	@Override
  	public Configuration getConfiguration() {
  		return config;
  	}
  
  	@Override
  	public void readConfiguration() {
  		super.setReconDimensions(volumeSize);
  		super.setReconVoxelSizes(volumeResolution);
  		super.setDetectorWidth((int) detectorPixels[0]);
  		super.setDetectorHeight((int) detectorPixels[1]);
  		super.setPixelDimensionX(detectorResolution[0]);
  		super.setPixelDimensionY(detectorResolution[1]);
  		super.setProjectionStackSize(numProjections);
  		super.setSourceToAxisDistance(SAD);
  		super.setSourceToDetectorDistance(SID);
  		super.setPrimaryAngleArray(primaryAngles);
  		super.setAverageAngularIncrement(averageAngularIncrement);
  		config.setVolumeOfInterestFileName(null);
  		//System.out.println("Projections " + super.getProjectionStackSize());
  	}
  
  	@Override
  	public void setConfiguration(Configuration config) {
  		this.config = config;
  	}
  
  	@Override
  	public void readConfigFile(String filename) throws IOException {
  		readProjectionMatrices(filename);
  	}
  
  	@Override
  	public boolean getSuccess() {
  		return success;
  	}
  	
  }
  /*
   * Copyright (C) 2010-2014 Andreas Maier
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */