/* * 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 org.apache.sis.util.ArgumentChecks; import org.geotoolkit.image.iterator.PixelIterator; /** * Interpolation which interpolate in X direction and Y direction independently. * * @author Rémi Maréchal (Geomatys). */ abstract class SeparableInterpolation extends Interpolation { /** 2D Array storing row data of each band when an interpolation per pixel is performed. */ private final double[] rows; /** 2D Array storing row interpolated data for each band when an interpolation per pixel is performed. */ private final double[] cols; /** * {@link Rectangle} which represente pixel area needed to compute interpolation from projected source coordinate. */ protected final Rectangle interpolArea; /** * Array which contain all samples values needed to compute interpolation. * Moreover its length equals band number */ protected final Object[] buffer; /** * {@link DataBuffer} type of internal datas. */ private final int sourceDataType; /** * Build a bi-dimensional interpolation. * * @param pixelIterator iterator which travel source image samples. * @param windowSide length of samples in X and Y direction needed from interpolation type. * @param rbc enum which define interpolation comportement at the source image border. * @param fillValue define destination sample value in case where interpolation is out of source image boundary. */ public SeparableInterpolation(PixelIterator pixelIterator, int windowSide, ResampleBorderComportement rbc, double[] fillValue) { super(pixelIterator, windowSide, rbc, fillValue); rows = new double[windowSide]; cols = new double[windowSide]; interpolArea = new Rectangle(windowSide, windowSide); sourceDataType = pixelIterator.getSourceDatatype(); switch (sourceDataType) { case DataBuffer.TYPE_BYTE : { buffer = new byte[numBands][windowSide * windowSide]; break; } case DataBuffer.TYPE_SHORT : case DataBuffer.TYPE_USHORT : { buffer = new short[numBands][windowSide * windowSide]; break; } case DataBuffer.TYPE_INT : { buffer = new int[numBands][windowSide * windowSide]; break; } case DataBuffer.TYPE_FLOAT : { buffer = new float[numBands][windowSide * windowSide]; break; } case DataBuffer.TYPE_DOUBLE : { buffer = new double[numBands][windowSide * windowSide]; break; } default : throw new IllegalArgumentException("Unknow datatype"); } } /** * Returns interpolate value from x, y pixel coordinates and band index. * * @param x pixel x coordinate. * @param y pixel y coordinate. * @param b band index. * @return interpolate value from x, y pixel coordinates and band index. */ @Override public double interpolate(double x, double y, int b) { ArgumentChecks.ensureBetween("band index", 0, getNumBands(), b); // if (!checkInterpolate(x, y)) return fillValue[b]; setInterpolateMin(x, y); interpolArea.setLocation(minX, minY); pixelIterator.getArea(interpolArea, buffer[b], b); int bufferID = 0; for (int dy = 0; dy < windowSide; dy++) { WriteInInterpolArray(buffer[b], bufferID, rows, 0, windowSide); bufferID += windowSide; cols[dy] = interpolate1D(minX, x, rows); } return interpolate1D(minY, y, cols); } /** * Return interpolate value from x, y pixel coordinate. * * @param x pixel x coordinate. * @param y pixel y coordinate. * @return interpolate value from x, y pixel coordinate. */ @Override public double[] interpolate(double x, double y) { // if (!checkInterpolate(x, y)) return fillValue; setInterpolateMin(x, y); interpolArea.setLocation(minX, minY); pixelIterator.getArea(interpolArea, buffer); int bufferID; for (int b = 0; b < numBands; b++) { bufferID = 0; for (int dy = 0; dy < windowSide; dy++) { WriteInInterpolArray(buffer[b], bufferID, rows, 0, windowSide); bufferID += windowSide; cols[dy] = interpolate1D(minX, x, rows); } result[b] = interpolate1D(minY, y, cols); } return result; } /** * Fill double destination array from unknow type source array. * * @param src source array. * @param srcPos first copied source array element. * @param dest destination double array which will be filled. * @param destPos first copied destination element. * @param length length of the copy. */ private void WriteInInterpolArray (final Object src, int srcPos, final double[] dest, int destPos, final int length) { int l = -1; switch (sourceDataType) { case DataBuffer.TYPE_BYTE : { byte[] array = (byte[])src; while (++l < length) { dest[destPos++] = array[srcPos++] & 0xFF; } break; } case DataBuffer.TYPE_SHORT : { short[] array = (short[])src; while (++l < length) { dest[destPos++] = array[srcPos++]; } break; } case DataBuffer.TYPE_USHORT : { short[] array = (short[])src; while (++l < length) { dest[destPos++] = array[srcPos++] & 0xFFFF; } break; } case DataBuffer.TYPE_INT : { int[] array = (int[])src; while (++l < length) { dest[destPos++] = array[srcPos++]; } break; } case DataBuffer.TYPE_FLOAT : { float[] array = (float[])src; while (++l < length) { dest[destPos++] = array[srcPos++]; } break; } case DataBuffer.TYPE_DOUBLE : { double[] array = (double[])src; while (++l < length) { dest[destPos++] = array[srcPos++]; } break; } default : throw new IllegalArgumentException("Unknow datatype"); } } /** * Compute interpolation value define by interpolation type implementation. * * @param t0 f(t0) = f[0].Current position from first pixel interpolation. * @param t position of interpolation. * @param f pixel values from t = {0 ... n}. * @return interpolation value. */ protected abstract double interpolate1D(double t0, double t, double...f); }