BicubicInterpolator.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.math3.analysis.interpolation;

  18. import org.apache.commons.math3.exception.DimensionMismatchException;
  19. import org.apache.commons.math3.exception.NoDataException;
  20. import org.apache.commons.math3.exception.NonMonotonicSequenceException;
  21. import org.apache.commons.math3.exception.NumberIsTooSmallException;
  22. import org.apache.commons.math3.util.MathArrays;

  23. /**
  24.  * Generates a {@link BicubicInterpolatingFunction bicubic interpolating
  25.  * function}.
  26.  * <p>
  27.  *  Caveat: Because the interpolation scheme requires that derivatives be
  28.  *  specified at the sample points, those are approximated with finite
  29.  *  differences (using the 2-points symmetric formulae).
  30.  *  Since their values are undefined at the borders of the provided
  31.  *  interpolation ranges, the interpolated values will be wrong at the
  32.  *  edges of the patch.
  33.  *  The {@code interpolate} method will return a function that overrides
  34.  *  {@link BicubicInterpolatingFunction#isValidPoint(double,double)} to
  35.  *  indicate points where the interpolation will be inaccurate.
  36.  * </p>
  37.  *
  38.  * @since 3.4
  39.  */
  40. public class BicubicInterpolator
  41.     implements BivariateGridInterpolator {
  42.     /**
  43.      * {@inheritDoc}
  44.      */
  45.     public BicubicInterpolatingFunction interpolate(final double[] xval,
  46.                                                     final double[] yval,
  47.                                                     final double[][] fval)
  48.         throws NoDataException, DimensionMismatchException,
  49.                NonMonotonicSequenceException, NumberIsTooSmallException {
  50.         if (xval.length == 0 || yval.length == 0 || fval.length == 0) {
  51.             throw new NoDataException();
  52.         }
  53.         if (xval.length != fval.length) {
  54.             throw new DimensionMismatchException(xval.length, fval.length);
  55.         }

  56.         MathArrays.checkOrder(xval);
  57.         MathArrays.checkOrder(yval);

  58.         final int xLen = xval.length;
  59.         final int yLen = yval.length;

  60.         // Approximation to the partial derivatives using finite differences.
  61.         final double[][] dFdX = new double[xLen][yLen];
  62.         final double[][] dFdY = new double[xLen][yLen];
  63.         final double[][] d2FdXdY = new double[xLen][yLen];
  64.         for (int i = 1; i < xLen - 1; i++) {
  65.             final int nI = i + 1;
  66.             final int pI = i - 1;

  67.             final double nX = xval[nI];
  68.             final double pX = xval[pI];

  69.             final double deltaX = nX - pX;

  70.             for (int j = 1; j < yLen - 1; j++) {
  71.                 final int nJ = j + 1;
  72.                 final int pJ = j - 1;

  73.                 final double nY = yval[nJ];
  74.                 final double pY = yval[pJ];

  75.                 final double deltaY = nY - pY;

  76.                 dFdX[i][j] = (fval[nI][j] - fval[pI][j]) / deltaX;
  77.                 dFdY[i][j] = (fval[i][nJ] - fval[i][pJ]) / deltaY;

  78.                 final double deltaXY = deltaX * deltaY;

  79.                 d2FdXdY[i][j] = (fval[nI][nJ] - fval[nI][pJ] - fval[pI][nJ] + fval[pI][pJ]) / deltaXY;
  80.             }
  81.         }

  82.         // Create the interpolating function.
  83.         return new BicubicInterpolatingFunction(xval, yval, fval,
  84.                                                 dFdX, dFdY, d2FdXdY) {
  85.             @Override
  86.             public boolean isValidPoint(double x, double y) {
  87.                 if (x < xval[1] ||
  88.                     x > xval[xval.length - 2] ||
  89.                     y < yval[1] ||
  90.                     y > yval[yval.length - 2]) {
  91.                     return false;
  92.                 } else {
  93.                     return true;
  94.                 }
  95.             }
  96.         };
  97.     }
  98. }