content: /*
   * Copyright (C) 2010-2014 - Andreas Maier, Andreas Keil 
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
   */
  package edu.stanford.rsl.conrad.data.numeric;
  
  
  /** The collection of all interpolation operators for Grids. */
  public abstract class InterpolationOperators {
  
  
  	///////////////////////////////////////////////////////////////////////
  	// Linear interpolation of Grids                                     //
  	///////////////////////////////////////////////////////////////////////
  
  	public static enum boundaryHandling {
  		ZEROPAD, REPLICATE
  	}
  	
  	private static Integer correctBoundsOfIndex(int idx, int gridSize, boundaryHandling bounds){
  		Integer retVal = idx;
  		switch (bounds) {
  		case ZEROPAD:
  			if (idx < 0 || idx > gridSize-1)
  				retVal = null;
  			break;
  		case REPLICATE:
  			if (idx < 0)
  				retVal = 0;
  			if (idx > gridSize-1)
  				retVal = gridSize-1;
  			break;
  		default:
  			if (idx < 0 || idx > gridSize-1)
  				retVal = null;
  			break;
  		}
  		return retVal;
  	}
  
  	/** Linear interpolation of a 1D Grid */
  	public static float interpolateLinear(final Grid1D grid, double i){
  		return interpolateLinear(grid, i, boundaryHandling.ZEROPAD);
  	}
  
  	/** Linear interpolation of a 1D Grid */
  	public static float interpolateLinear(final Grid1D grid, double i, boundaryHandling bounds) {
  		Integer lower = (int) Math.floor(i);
  		double d = i - lower; // d is in [0, 1)
  		Integer lowerPlusOne = lower+1;
  		
  		lower = correctBoundsOfIndex(lower, grid.getSize()[0], bounds);
  		lowerPlusOne = correctBoundsOfIndex(lowerPlusOne, grid.getSize()[0], bounds);
  
  		return (float) (
  				(1.0-d)*((lower!=null) ? grid.getAtIndex(lower) : 0.0)
  				+ ((d != 0.0) ? d*((lowerPlusOne != null) ? grid.getAtIndex(lowerPlusOne): 0.0) : 0.0)
  				);
  	}
  	
  	
  	/** Linear interpolation of a 2D Grid */
  	public static float interpolateLinear(final Grid2D grid, double x, double y){
  		return interpolateLinear(grid, x, y, boundaryHandling.ZEROPAD);
  	}
  	
  	/** Linear interpolation of a 2D Grid */
  	public static float interpolateLinear(final Grid2D grid, double x, double y, boundaryHandling bounds) {
  		if (grid == null) return 0;
  		
  		Integer lower = (int) Math.floor(y);
  		double d = y - lower; // d is in [0, 1)
  		Integer lowerPlusOne = lower+1;
  		
  		lower = correctBoundsOfIndex(lower, grid.getSize()[1], bounds);
  		lowerPlusOne = correctBoundsOfIndex(lowerPlusOne, grid.getSize()[1], bounds);
  			
  		return (float) (
  				(1.0-d)*((lower!=null) ? interpolateLinear(grid.getSubGrid(lower), x, bounds) : 0.0)
  				+ ((d != 0.0) ? d*((lowerPlusOne != null) ? interpolateLinear(grid.getSubGrid(lowerPlusOne), x, bounds) : 0.0) : 0.0)
  				);
  	}
  
  	
  	/** Linear interpolation of a 3D Grid */
  	public static float interpolateLinear(final Grid3D grid, double z, double x, double y){
  		return interpolateLinear(grid, z, x, y, boundaryHandling.ZEROPAD);
  	}
  	
  	/** Linear interpolation of a 3D Grid */
  	public static float interpolateLinear(final Grid3D grid, double z, double x, double y, boundaryHandling bounds) {
  		Integer lower = (int) Math.floor(z);
  		double d = z - lower; // d is in [0, 1)
  		Integer lowerPlusOne = lower+1;
  		
  		lower = correctBoundsOfIndex(lower, grid.getSize()[2], bounds);
  		lowerPlusOne = correctBoundsOfIndex(lowerPlusOne, grid.getSize()[2], bounds);
  		
  		return (float) (
  				(1.0-d)*((lower!=null) ? interpolateLinear(grid.getSubGrid(lower), x, y, bounds) : 0.0)
  				+ ((d != 0.0) ? d*((lowerPlusOne != null) ? interpolateLinear(grid.getSubGrid(lowerPlusOne), x, y, bounds) : 0.0) : 0.0)
  				);
  	}
  	
  	/** Linear interpolation of a 4D Grid */
  	public static float interpolateLinear(final Grid4D grid,double t, double z, double x, double y){
  		return interpolateLinear(grid, t, z, x, y, boundaryHandling.ZEROPAD);
  	}
  	
  	/** Linear interpolation of a 4D Grid */
  	public static float interpolateLinear(final Grid4D grid, double t, double z, double x, double y, boundaryHandling bounds) {
  		Integer lower = (int) Math.floor(t);
  		double d = t - lower; // d is in [0, 1)
  		Integer lowerPlusOne = lower+1;
  		
  		lower = correctBoundsOfIndex(lower, grid.getSize()[3], bounds);
  		lowerPlusOne = correctBoundsOfIndex(lowerPlusOne, grid.getSize()[3], bounds);
  		
  		return (float) (
  				(1.0-d)*((lower!=null) ? interpolateLinear(grid.getSubGrid(lower),z, x, y, bounds) : 0.0)
  				+ ((d != 0.0) ? d*((lowerPlusOne != null) ? interpolateLinear(grid.getSubGrid(lowerPlusOne), z, x, y, bounds) : 0.0) : 0.0)
  				);
  	}
  
  
  	///////////////////////////////////////////////////////////////////////
  	// Interpolated updates into Grids                                   //
  	// (These methods "spread out" an additive update to a grid using    //
  	// the same weighting factors as for interpolation.)                 //
  	///////////////////////////////////////////////////////////////////////
  
  	/** Linear extrapolation into a 1D Grid */
  	public static void addInterpolateLinear(final Grid1D grid, double x, float val) {
  		int lower = (int) Math.floor(x);
  		double d = x - lower;
  		grid.setAtIndex(lower, grid.getAtIndex(lower) + (float) ((1.0-d)*val));
  		if (d != 0.0) grid.setAtIndex(lower+1, grid.getAtIndex(lower+1) + (float) (d*val));
  	}
  
  	/** Linear extrapolation into a 2D Grid */
  	public static void addInterpolateLinear(final Grid2D grid, double x, double y, float val) {
  		int lower = (int) Math.floor(y);
  		double d = y - lower;
  		addInterpolateLinear(grid.getSubGrid(lower), x, (float) ((1.0-d)*val));
  		if (d != 0.0) addInterpolateLinear(grid.getSubGrid(lower+1), x, (float) (d*val));
  	}
  
  	/** Linear extrapolation into a 3D Grid */
  	public static void addInterpolateLinear(final Grid3D grid, double x, double y, double z, float val) {
  		int lower = (int) Math.floor(z);
  		double d = z - lower;
  		addInterpolateLinear(grid.getSubGrid(lower), x, y, (float) ((1.0-d)*val));
  		if (d != 0.0) addInterpolateLinear(grid.getSubGrid(lower+1), x, y, (float) (d*val));
  	}
  }
  
  