/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2012, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.image.interpolation;
import java.awt.Rectangle;
import java.awt.image.DataBuffer;
import static java.lang.Math.sin;
import org.geotoolkit.image.iterator.PixelIterator;
/**
* Define Lanczos interpolation.
*
* @author rémi Marechal (Geomatys).
*/
public class LanczosInterpolation extends Interpolation {
/**
* Pixels number use to interpolate before and after pixel coordinate on one dimension.
*/
private final int lanczosWindow;
private static double PI = Math.PI;
/**
* Minimum value authorized from type of data from source interpolation.
*/
private final double minValue;
/**
* maximum value authorized from type of data from source interpolation.
*/
private final double maxValue;
/**
* Create a Lanczos interpolation.
*
* The Lanczos window is the central lobe of a horizontally-stretched sinc,<br/>
* sinc(x/a) for |x| ≤ lanczos window.<br/>
* The normalized sinc function is commonly defined by sinc(x) = sin(PIx)/(PIx).<br/>
* Lanczos window define interpolate area boundary defined by square of side length 2*lanczos window.
*
* @param pixelIterator Iterator used to interpolation.
* @param lanczosWindow define pixel number use to interpolate.
* @param rbc border comportement.
* @param fillValue value(s) which will be filled when coordinate out of source boundary.
*/
public LanczosInterpolation(PixelIterator pixelIterator, int lanczosWindow, ResampleBorderComportement rbc, double[] fillValue) {
super(pixelIterator, lanczosWindow << 1, rbc, fillValue);
if (lanczosWindow > boundary.width || lanczosWindow > boundary.height)
throw new IllegalArgumentException("lanczosWindow more longer");
this.lanczosWindow = lanczosWindow;
switch (pixelIterator.getSourceDatatype()) {
case DataBuffer.TYPE_BYTE : {
minValue = 0;
maxValue = 255;
}break;
case DataBuffer.TYPE_SHORT : {
minValue = -32768;
maxValue = 32767;
}break;
case DataBuffer.TYPE_INT : {
minValue = -2147483648;
maxValue = 2147483647;
}break;
case DataBuffer.TYPE_FLOAT : {
minValue = -3.40282347E38;
maxValue = 3.40282347E38;
}break;
default : {//double limits
minValue = -1.79769313486231E308;
maxValue = 1.79769313486231E308;
}
}
}
/**
* Create a Lanczos interpolation.<br/><br/>
*
* Define border comportement at {@link ResampleBorderComportement#FILL_VALUE}
* and fillValue is an arrays of the same length than band number from source image and filled by {@link Double#NaN} value.<br/><br/>
*
* The Lanczos window is the central lobe of a horizontally-stretched sinc,<br/>
* sinc(x/a) for |x| ≤ lanczos window.<br/>
* The normalized sinc function is commonly defined by sinc(x) = sin(PIx)/(PIx).<br/>
* Lanczos window define interpolate area boundary defined by square of side length 2*lanczos window.
*
* @param pixelIterator Iterator used to interpolation.
* @param lanczosWindow define pixel number use to interpolate.
*/
public LanczosInterpolation(PixelIterator pixelIterator, int lanczosWindow) {
this(pixelIterator, lanczosWindow, ResampleBorderComportement.FILL_VALUE, null);
}
/**
* Return Lanczos kernel filter value.
*
* @param t0 interpolation position from first pixel use to interpolate.
* @param t interpolation instant.
* @return Lanczos kernel filter value.
*/
private double getLCZt(double t0, double t) {
double x = t-t0;
if (x == 0) return 1;
if (Math.abs(x) > lanczosWindow) return 0;
final double pix = PI*x;
return (lanczosWindow * sin(pix) * sin(pix/lanczosWindow))/(pix*pix);
}
/**
* {@inheritDoc }
*
* <p> In other words, interpolate result is compute from bounding box centered
* from pixel coordinates with side length equal to 2 * lanczos window.</p>
*
*/
@Override
public double interpolate(double x, double y, int b) {
// if (!checkInterpolate(x, y)) return fillValue[b];
setInterpolateMin(x, y);
final int hY = minY + windowSide;
final int wX = minX + windowSide;
int dy, dx;
double interpol = 0;
for (dy = minY; dy < hY; dy++) {
for (dx = minX; dx < wX; dx++) {
pixelIterator.moveTo(dx, dy, b);
interpol += pixelIterator.getSampleDouble() * getLCZt(dx, x) * getLCZt(dy, y);
}
}
if (interpol < minValue) {
interpol = minValue;
} else if (interpol > maxValue) {
interpol = maxValue;
}
return interpol;
}
/**
* {@inheritDoc }.
*/
@Override
public double[] getMinMaxValue(Rectangle area) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public double[] interpolate(double x, double y) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}