All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boofcv.alg.interpolate.array.Interpolate1D_F32 Maven / Gradle / Ivy

/*
 * Copyright (c) 2011-2015, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package boofcv.alg.interpolate.array;


/**
 * Provides much of the basic house keeping needed for interpolating 1D data.  Interpolation
 * is done using sample points y[i] = f(x[i]) where x is a monotonically increasing or decreasing
 * function.
 *
 * @author Peter Abeles
 */
public abstract class Interpolate1D_F32 {

	// the sample data
	// both axises must be monotonic increasing or decreasing
	protected int size;
	protected float x[];
	protected float y[];

	// how many points should the interpolation use
	// this is equal to the degree + 1
	protected int M;

	// this is an index that the sample point is between
	private int center;
	// this is the first index that the interpolation algorithm will use
	// 0 <= index0 <= size - M
	protected int index0;

	// should it hunt next time instead of searching?
	private boolean doHunt;

	// used to help it decide to hunt or search
	private int dj;
	// true if the data is increasing
	protected boolean ascend;

	/**
	 * @param degree The number of points used in the interpolation minus one
	 */
	public Interpolate1D_F32(int degree) {
		changeDegree(degree);
	}

	/**
	 * @param degree The number of points used in the interpolation minus one
	 * @param x	  Where the points are sample at. Not modifed. Reference saved.
	 * @param y	  The value at the sample points. Not modifed. Reference saved.
	 * @param size   The number of points used.
	 */
	public Interpolate1D_F32(int degree, float x[], float y[], int size) {
		this(degree);
		setInput(x, y, size);
	}

	/**
	 * Sets the data that is being interpolated.
	 *
	 * @param x	Where the points are sample at. Not modifed. Reference saved.
	 * @param y	The value at the sample points. Not modifed. Reference saved.
	 * @param size The number of points used.
	 */
	public void setInput(float x[], float y[], int size) {
		if (x.length < size || y.length < size) {
			throw new IllegalArgumentException("Arrays too small for size.");
		}
		if (size < M) {
			throw new IllegalArgumentException("Not enough data points for M");
		}

		this.x = x;
		this.y = y;
		this.size = size;
		this.dj = Math.min(1, (int) Math.pow(size, 0.25));
		ascend = x[size - 1] >= x[0];
	}

	/**
	 * Performs interpolation at the sample point.
	 *
	 * @param testX Where the interpolated value is done at.
	 * @return The interpolated value at sampleX.
	 */
	public float process(float testX) {
		if (doHunt) {
			hunt(testX);
		} else {
			bisectionSearch(testX, 0, size - 1);
		}

		return compute(testX);
	}

	/**
	 * Performs an interpolation using sample data starting at index0.  Little checking
	 * is done and it is assumed the user knows what he is doing.  Interpolation is done
	 * using points from index0 to index0 + M - 1
	 *
	 * @param index0 first sample point used in the interpolation.
	 * @param testX  Where the interpolated value is done at.
	 * @return The interpolated value at sampleX.
	 */
	public float process(int index0, float testX) {
		this.index0 = index0;
		return compute(testX);
	}

	/**
	 * This is where the specific implementation of the interpolation is done.  It should
	 * use points index0 to index0 + M - 1 in its interpolation
	 *
	 * @param testX Where the interpolated value is done at.
	 * @return The interpolated value at sampleX.
	 */
	protected abstract float compute(float testX);

	/**
	 * Changes the number of points used in the interpolation.
	 *
	 * @param degree Number of points used minus one.
	 */
	public void changeDegree(int degree) {
		this.M = degree + 1;
		doHunt = false;
	}

	/**
	 * To speed up finding the appropriate indexes to use in the interpolation it can use its
	 * previous results to search a smaller region than it would otherwise.
	 *
	 * @param val The value that is to be interpolated.
	 */
	protected void hunt(float val) {
		int lowerLimit = center;
		int upperLimit;
		int inc = 1;

		if (val >= x[lowerLimit] && ascend) {
			// hunt up
			for (; ; ) {
				upperLimit = lowerLimit + inc;
				// see if it is outside the table
				if (upperLimit >= size - 1) {
					upperLimit = size - 1;
					break;
				} else if (val < x[upperLimit] && ascend) {
					break;
				} else {
					lowerLimit = upperLimit;
					inc += inc;
				}
			}
		} else {
			// hunt down
			upperLimit = lowerLimit;
			for (; ; ) {
				lowerLimit = lowerLimit - inc;
				if (lowerLimit <= 0) {
					lowerLimit = 0;
					break;
				} else if (val >= x[lowerLimit] && ascend) {
					break;
				} else {
					upperLimit = lowerLimit;
					inc += inc;
				}
			}
		}

		bisectionSearch(val, lowerLimit, upperLimit);
	}

	/**
	 * Searches the x array by bisecting it.  This takes advantage of the data being
	 * monotonic.  This finds a center index which has the following property:
	 * x[center] ≤ val < x[center+1]
	 * From that it selects index0 which is center - M/2.
	 *
	 * @param val		The value that is to be interpolated.
	 * @param lowerLimit Lower limit for x index.
	 * @param upperLimit The largest possible index of x
	 */
	protected void bisectionSearch(float val, int lowerLimit, int upperLimit) {
		while (upperLimit - lowerLimit > 1) {
			int middle = (upperLimit + lowerLimit) / 2;
			if (val >= x[middle] && ascend) {
				lowerLimit = middle;
			} else {
				upperLimit = middle;
			}
		}

		// decide if it should hunt or locate next time
		doHunt = Math.abs(lowerLimit - center) > dj;

		// make sure the points sampled for the polynomial are all within bounds
		center = lowerLimit;
		index0 = center - M / 2;
		if (index0 + M > size) {
			index0 = size - M;
		} else if (index0 < 0) {
			index0 = 0;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy