package net.sourceforge.gpstools.math;
/* gpsdings
* Copyright (C) 2007 Moritz Ringler
* $Id: LinearFunction.java 358 2008-11-24 19:06:17Z ringler $
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.analysis.UnivariateRealInterpolator;
import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.MathException;
public final class LinearInterpolator implements UnivariateRealInterpolator {
/** @throws MathException if xx[i + 1] <= xx[i] for any i **/
@Override
public UnivariateRealFunction interpolate(double[] xx, double[] yy) throws MathException{
final int n = xx.length - 1;
for(int i=0; i<n; i++){
if(xx[i + 1] <= xx[i]){
throw new MathException("xx must be strictly increasing.");
}
}
return new LinearInterpolation(xx, yy);
}
public static class LinearInterpolation implements UnivariateRealFunction{
private final double[] x;
private final double[] y;
private final int n;
private transient int lastindex;
/** Expects strictly increasing xx. */
public LinearInterpolation(double[] xx, double[] yy){
x = xx;
y = yy;
n = x.length - 1;
}
@Override
public double value(double xx) throws FunctionEvaluationException{
if (xx < x[0] || xx > x[n]){
throw new FunctionEvaluationException(xx, "Argument " + xx + " is not in the domain of this function.");
}
// This speeds things up if the function is sampled at several
// closely spaced x-values
int i = lastindex;
if (x[i] < xx && x[i+1] > xx){
return y[i] + (xx - x[i])/(x[i+1] - x[0])*(y[i+1] - y[i]);
}
for(i = 0; i < n; i++){
if (x[i] == xx){
lastindex = i;
return y[i];
} else if (x[i + 1] == xx){
lastindex = i + 1;
return y[i + 1];
} else if (x[i] < xx && x[i+1] > xx){
lastindex = i;
return y[i] + (xx - x[i])/(x[i+1] - x[0])*(y[i+1] - y[i]);
}
}
throw new Error("We should not have got here. This is a bug.");
}
public double[] getKnots(){
return x.clone();
}
}
}