content: package edu.stanford.rsl.tutorial.modelObserver;
  
  import edu.stanford.rsl.conrad.data.numeric.Grid2D;
  import edu.stanford.rsl.conrad.numerics.SimpleMatrix;
  import edu.stanford.rsl.conrad.numerics.SimpleVector;
  
  /**
   * @author Iris Kellermann
   */
  
  public class Channels 
  {	
  	/**
  	 * Calculates the result of the Laguerre-Gauß function for the given input values.  
  	 * @param r The radial value.
  	 * @param degree The degree of the LG function.
  	 * @return  The result value.
  	 */
  	public static double GetLGFunctionValue(double r, int degree, double gaussValue)
  	{
  		double result = (Math.sqrt(2) / gaussValue) * Math.exp( (- Math.PI * r * r ) / (gaussValue * gaussValue) ) * Laguerre( ( (2 * Math.PI * r * r) / ( gaussValue * gaussValue) ), degree );
  		
  		return result;
  	}
  	
  	/**
  	 * Calculates the result of the Laguerre function for the given input values.  
  	 * @param value The input value.
  	 * @param degree The degree of the Laguerre function.
  	 * @return  The result value.
  	 */
  	public static double Laguerre(double value, int degree)
  	{
  		double result = 0.0;
  		
  		for(int i = 0; i < degree + 1; ++i)
  		{
  			result += Math.pow(-1, i) * ( Factorial(degree) / (Factorial(i) * Factorial(degree - i) ) ) * (Math.pow(value, i) / Factorial(i) );
  		}
  		
  		return result;
  	}
  	
  	/**
  	 * Calculates the factorial of the input value.  
  	 * @param value The input value.
  	 * @return  The result value.
  	 */
  	public static double Factorial(int value)
  	{
  		if(value <= 1)
  		{
  			return 1;
  		}
  		
  		return value * Factorial(value - 1);
  	}
  	
  	/**
  	 * Creates a Laguerre-Gauß channel image.  
  	 * @param width The width of the image.
  	 * @param height The height of the image.
  	 * @param degree The degree of the LG function.
  	 * @return  The result image.
  	 */
  	public static Grid2D CreateLGChannelImage(int width, int height, int degree, double gaussValue)
  	{
  		Grid2D resultImage = new Grid2D(width, height);
  		
  		for(int x = 0; x < width; ++x)
  		{
  			int xValue = - width / 2 + x;
  					
  			for(int y = 0; y < height; ++y)
  			{
  				int yValue = - height / 2 + y;
  				
  				double r = Math.hypot(xValue, yValue);
  				
  				resultImage.putPixelValue(x, y, GetLGFunctionValue(r, degree, gaussValue));
  			}
  		}
  		
  		return resultImage;
  	}
  
  	/**
  	 * Creates a matrix of concatenated channel image vectors.  
  	 * @param channelCount The number of channels.
  	 * @param imageSize The size of the images.
  	 * @return  The SimpleMatrix containing the channel image vectors.
  	 */
  	public static SimpleMatrix CreateChannelMatrix(int channelCount, int imageSize, double gaussValue)
  	{		
  		SimpleVector[] channelColumns = new SimpleVector[channelCount];
  		for(int i = 0; i < channelCount; ++i)
  		{
  			channelColumns[i] = ImageHelper.ConvertSimpleMatrixToVector(ImageHelper.ConvertGrid2DToSimpleMatrix(Channels.CreateLGChannelImage(imageSize, imageSize, i, gaussValue)));
  		}
  		
  		//TODO - wrong operator in conrad/numerics/SimpleOperators?
  		//SimpleMatrix channelMatrix = SimpleOperators.concatenateHorizontally(channelColumns);
  		
  		SimpleMatrix channelMatrix = ImageHelper.concatenateHorizontally(channelColumns);
  		
  		return channelMatrix;
  		
  	}
  }
  
  /*
   * Copyright (C) 2010-2014 - Iris Kellermann 
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */