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.math4.legacy.analysis.interpolation;

  18. import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
  19. import org.apache.commons.math4.legacy.exception.NoDataException;
  20. import org.apache.commons.math4.legacy.exception.NonMonotonicSequenceException;
  21. import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
  22. import org.apache.commons.math4.legacy.core.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.     * Whether to initialize internal data used to compute the analytical
  44.     * derivatives of the splines.
  45.     */
  46.     private final boolean initializeDerivatives;

  47.     /**
  48.      * Default constructor.
  49.      * The argument {@link #BicubicInterpolator(boolean) initializeDerivatives}
  50.      * is set to {@code false}.
  51.      */
  52.     public BicubicInterpolator() {
  53.         this(false);
  54.     }

  55.     /**
  56.      * Creates an interpolator.
  57.      *
  58.      * @param initializeDerivatives Whether to initialize the internal data
  59.      * needed for calling any of the methods that compute the partial derivatives
  60.      * of the {@link BicubicInterpolatingFunction function} returned from
  61.      * the call to {@link #interpolate(double[],double[],double[][]) interpolate}.
  62.      */
  63.     public BicubicInterpolator(boolean initializeDerivatives) {
  64.         this.initializeDerivatives = initializeDerivatives;
  65.     }
  66.     /**
  67.      * {@inheritDoc}
  68.      */
  69.     @Override
  70.     public BicubicInterpolatingFunction interpolate(final double[] xval,
  71.                                                     final double[] yval,
  72.                                                     final double[][] fval)
  73.         throws NoDataException, DimensionMismatchException,
  74.                NonMonotonicSequenceException, NumberIsTooSmallException {
  75.         if (xval.length == 0 || yval.length == 0 || fval.length == 0) {
  76.             throw new NoDataException();
  77.         }
  78.         if (xval.length != fval.length) {
  79.             throw new DimensionMismatchException(xval.length, fval.length);
  80.         }

  81.         MathArrays.checkOrder(xval);
  82.         MathArrays.checkOrder(yval);

  83.         final int xLen = xval.length;
  84.         final int yLen = yval.length;

  85.         // Approximation to the partial derivatives using finite differences.
  86.         final double[][] dFdX = new double[xLen][yLen];
  87.         final double[][] dFdY = new double[xLen][yLen];
  88.         final double[][] d2FdXdY = new double[xLen][yLen];
  89.         for (int i = 1; i < xLen - 1; i++) {
  90.             final int nI = i + 1;
  91.             final int pI = i - 1;

  92.             final double nX = xval[nI];
  93.             final double pX = xval[pI];

  94.             final double deltaX = nX - pX;

  95.             for (int j = 1; j < yLen - 1; j++) {
  96.                 final int nJ = j + 1;
  97.                 final int pJ = j - 1;

  98.                 final double nY = yval[nJ];
  99.                 final double pY = yval[pJ];

  100.                 final double deltaY = nY - pY;

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

  103.                 final double deltaXY = deltaX * deltaY;

  104.                 d2FdXdY[i][j] = (fval[nI][nJ] - fval[nI][pJ] - fval[pI][nJ] + fval[pI][pJ]) / deltaXY;
  105.             }
  106.         }

  107.         // Create the interpolating function.
  108.         return new BicubicInterpolatingFunction(xval, yval, fval,
  109.                                                 dFdX, dFdY, d2FdXdY,
  110.                                                 initializeDerivatives) {
  111.             /** {@inheritDoc} */
  112.             @Override
  113.             public boolean isValidPoint(double x, double y) {
  114.                 return !(x < xval[1] ||
  115.                     x > xval[xval.length - 2] ||
  116.                     y < yval[1] ||
  117.                     y > yval[yval.length - 2]);
  118.             }
  119.         };
  120.     }
  121. }