BilinearInterpolatingFunction.java

  1. /*
  2.  * Licensed to the Hipparchus project 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 Hipparchus project 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.  *      https://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.hipparchus.analysis.interpolation;

  18. import java.io.Serializable;

  19. import org.hipparchus.CalculusFieldElement;
  20. import org.hipparchus.analysis.BivariateFunction;
  21. import org.hipparchus.analysis.FieldBivariateFunction;
  22. import org.hipparchus.exception.MathIllegalArgumentException;

  23. /**
  24.  * Interpolate grid data using bi-linear interpolation.
  25.  * <p>
  26.  * This interpolator is thread-safe.
  27.  * </p>
  28.  * @since 1.4
  29.  */
  30. public class BilinearInterpolatingFunction implements BivariateFunction, FieldBivariateFunction, Serializable {

  31.     /** Serializable UID. */
  32.     private static final long serialVersionUID = 20180926L;

  33.     /** Grid along the x axis. */
  34.     private final GridAxis xGrid;

  35.     /** Grid along the y axis. */
  36.     private final GridAxis yGrid;

  37.     /** Grid size along the y axis. */
  38.     private final int ySize;

  39.     /** Values of the interpolation points on all the grid knots (in a flatten array). */
  40.     private final double[] fVal;

  41.     /** Simple constructor.
  42.      * @param xVal All the x-coordinates of the interpolation points, sorted
  43.      * in increasing order.
  44.      * @param yVal All the y-coordinates of the interpolation points, sorted
  45.      * in increasing order.
  46.      * @param fVal The values of the interpolation points on all the grid knots:
  47.      * {@code fVal[i][j] = f(xVal[i], yVal[j])}.
  48.      * @exception MathIllegalArgumentException if grid size is smaller than 2
  49.      * or if the grid is not sorted in strict increasing order
  50.      */
  51.     public BilinearInterpolatingFunction(final double[] xVal, final double[] yVal,
  52.                                          final double[][] fVal)
  53.         throws MathIllegalArgumentException {
  54.         this.xGrid = new GridAxis(xVal, 2);
  55.         this.yGrid = new GridAxis(yVal, 2);
  56.         this.ySize = yVal.length;
  57.         this.fVal  = new double[xVal.length * ySize];
  58.         int k = 0;
  59.         for (int i = 0; i < xVal.length; ++i) {
  60.             final double[] fi = fVal[i];
  61.             for (int j = 0; j < ySize; ++j) {
  62.                 this.fVal[k++] = fi[j];
  63.             }
  64.         }
  65.     }

  66.     /** Get the lowest grid x coordinate.
  67.      * @return lowest grid x coordinate
  68.      */
  69.     public double getXInf() {
  70.         return xGrid.node(0);
  71.     }

  72.     /** Get the highest grid x coordinate.
  73.      * @return highest grid x coordinate
  74.      */
  75.     public double getXSup() {
  76.         return xGrid.node(xGrid.size() - 1);
  77.     }

  78.     /** Get the lowest grid y coordinate.
  79.      * @return lowest grid y coordinate
  80.      */
  81.     public double getYInf() {
  82.         return yGrid.node(0);
  83.     }

  84.     /** Get the highest grid y coordinate.
  85.      * @return highest grid y coordinate
  86.      */
  87.     public double getYSup() {
  88.         return yGrid.node(yGrid.size() - 1);
  89.     }

  90.     /** {@inheritDoc} */
  91.     @Override
  92.     public double value(final double x, final double y) {

  93.         // get the interpolation nodes
  94.         final int    i   = xGrid.interpolationIndex(x);
  95.         final int    j   = yGrid.interpolationIndex(y);
  96.         final double x0  = xGrid.node(i);
  97.         final double x1  = xGrid.node(i + 1);
  98.         final double y0  = yGrid.node(j);
  99.         final double y1  = yGrid.node(j + 1);

  100.         // get the function values at interpolation nodes
  101.         final int    k0  = i * ySize + j;
  102.         final int    k1  = k0 + ySize;
  103.         final double z00 = fVal[k0];
  104.         final double z01 = fVal[k0 + 1];
  105.         final double z10 = fVal[k1];
  106.         final double z11 = fVal[k1 + 1];

  107.         // interpolate
  108.         final double dx0  = x  - x0;
  109.         final double dx1  = x1 - x;
  110.         final double dx10 = x1 - x0;
  111.         final double dy0  = y  - y0;
  112.         final double dy1  = y1 - y;
  113.         final double dy10 = y1 - y0;
  114.         return (dx0 * (dy0 * z11 + dy1 * z10) + dx1 * (dy0 * z01 + dy1 * z00)) /
  115.                (dx10 * dy10);

  116.     }

  117.     /** {@inheritDoc}
  118.      * @since 1.5
  119.      */
  120.     @Override
  121.     public <T extends CalculusFieldElement<T>> T value(T x, T y) {

  122.         // get the interpolation nodes
  123.         final int    i   = xGrid.interpolationIndex(x.getReal());
  124.         final int    j   = yGrid.interpolationIndex(y.getReal());
  125.         final double x0  = xGrid.node(i);
  126.         final double x1  = xGrid.node(i + 1);
  127.         final double y0  = yGrid.node(j);
  128.         final double y1  = yGrid.node(j + 1);

  129.         // get the function values at interpolation nodes
  130.         final int    k0  = i * ySize + j;
  131.         final int    k1  = k0 + ySize;
  132.         final double z00 = fVal[k0];
  133.         final double z01 = fVal[k0 + 1];
  134.         final double z10 = fVal[k1];
  135.         final double z11 = fVal[k1 + 1];

  136.         // interpolate
  137.         final T      dx0   = x.subtract(x0);
  138.         final T      mdx1  = x.subtract(x1);
  139.         final double dx10  = x1 - x0;
  140.         final T      dy0   = y.subtract(y0);
  141.         final T      mdy1  = y.subtract(y1);
  142.         final double dy10  = y1 - y0;
  143.         return          dy0.multiply(z11).subtract(mdy1.multiply(z10)).multiply(dx0).
  144.                subtract(dy0.multiply(z01).subtract(mdy1.multiply(z00)).multiply(mdx1)).
  145.                divide(dx10 * dy10);

  146.     }

  147. }