content: package edu.stanford.rsl.tutorial.fan.dynamicCollimation;
  
  import ij.ImageJ;
  import edu.stanford.rsl.conrad.data.numeric.Grid2D;
  import edu.stanford.rsl.conrad.data.numeric.Grid3D;
  import edu.stanford.rsl.conrad.data.numeric.InterpolationOperators;
  import edu.stanford.rsl.conrad.data.numeric.NumericPointwiseOperators;
  import edu.stanford.rsl.tutorial.fan.FanBeamProjector2D;
  import edu.stanford.rsl.tutorial.fan.redundancy.BinaryWeights;
  import edu.stanford.rsl.tutorial.phantoms.Phantom;
  import edu.stanford.rsl.tutorial.phantoms.SheppLogan;
  
  
  
  public class copyRedundantData extends Grid2D {
  	
  	private final double focalLength;
  	private final double maxT;
  	private final double deltaT, deltax, dLambda;
  	private final int maxTIndex, maxLambdaIndex;
  	
  
  	public copyRedundantData(final double focalLength, final double maxT,
  			final double deltaT, double maxLambda, double dLambda) {
  		// Call constructor from superclass
  		super((int) Math.round(maxT / deltaT), (int)(Math.round(maxLambda / dLambda)) + 1);
  		// Initialize parameters
  		this.focalLength = focalLength;
  		this.maxT = maxT;
  		this.deltaT = deltaT;
  		this.dLambda = dLambda;
  		this.maxLambdaIndex = (int)(Math.round(maxLambda / dLambda)) + 1;
  		this.maxTIndex = (int) Math.round(maxT / deltaT);
  
  		this.deltax = maxLambda - Math.PI; 
  		
  		// Correct for scaling due to varying angle lambda
  		NumericPointwiseOperators.multiplyBy(this, (float)( maxLambda / (Math.PI)));
  		
  	}
  	
  	
  	private void createFullSinogram(Grid2D OneSidedSinogram)
  	{
  		double lambda, delta;
  		
  		// iterate over the detector elements
  		for (int t = 0; t < maxTIndex; ++t) {
  			// compute delta of the current ray (detector element)
  			delta = Math.atan((t * deltaT - maxT / 2.d + 0.5*deltaT) / focalLength);
  
  			// iterate over the projection angles
  			for (int b = 0; b < maxLambdaIndex; ++b) {
  				// compute the current lambda angle
  				lambda = b * dLambda;
  				
  				// First case: Handles values for redundancies at the end of the scan
  				// Copy values from redundancies at the beginning of the scan
  				if (lambda >= ( Math.PI + 2*delta) && lambda <= (Math.PI + deltax) + 1e-12)
  				{
  					//double delta2 = -1.0*delta;
  					double lambda2 = -2.0*delta - Math.PI + lambda;
  					double b2 = lambda2 / dLambda;
  					//b2 = (b2 < 0) ? (0.0) : b2;
  					int t2 = maxTIndex - t -1;//(int) Math.round(delta2 / deltaT);
  					
  					OneSidedSinogram.setAtIndex(maxTIndex - t - 1, b, InterpolationOperators.interpolateLinear(OneSidedSinogram, b2, maxTIndex - t2 - 1));
  				}
  			}
  		}
  	}
  	
  	
  	
  	public void applyToGrid(Grid2D OneSidedSinogram) {
  		createFullSinogram(OneSidedSinogram);
  	}
  
  	
  	public static void main (String [] args){
  		//fan beam bp parameters
  		
  		double maxT = 100;
  		double deltaT = 1.d;
  		// set focal length according to the fan angle
  		double focalLength = (maxT/2.0-0.5)/Math.tan(20.0*Math.PI/180.0);
  		
  		Phantom ph = new SheppLogan(64);
  		new ImageJ();
  		
  		int startBeta = 100;
  		int endBeta = 260;
  		
  		Grid3D g  = new Grid3D((int)maxT, 133, endBeta-startBeta +1, false);
  		
  		for (int i = startBeta; i < endBeta+1; ++i)
  		{
  			double maxBeta =  (double)(i+1) * Math.PI * 2.0 / 360.0;
  			double deltaBeta = maxBeta / 132;
  			
  			FanBeamProjector2D fbp_forward = new FanBeamProjector2D(focalLength, maxBeta, deltaBeta, maxT, deltaT);
  			Grid2D halfSino = fbp_forward.projectRayDriven(ph);
  			
  			BinaryWeights BW = new BinaryWeights(focalLength, maxT, deltaT, maxBeta, deltaBeta);
  			//BW.show();
  			BW.applyToGrid(halfSino);
  			//halfSino.show();
  			
  			copyRedundantData p = new copyRedundantData(focalLength, maxT, deltaT, maxBeta, deltaBeta);
  			p.applyToGrid(halfSino);
  			Grid2D dummy = new Grid2D(halfSino);
  			g.setSubGrid(i-startBeta, dummy);
  			//g.setSliceLabel("MaxBeta: " + Double.toString(maxBeta*180/Math.PI), i+1 - startBeta);
  		}
  		
  		g.show();
  		
  	}
  
  }
  /*
   * Copyright (C) 2010-2014 Andreas Maier
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */