1 package net.sf.openrocket.util;
3 import java.util.Iterator;
5 import java.util.SortedMap;
6 import java.util.TreeMap;
8 public class LinearInterpolator implements Cloneable {
10 private TreeMap<Double, Double> sortMap = new TreeMap<Double,Double>();
13 * Construct a <code>LinearInterpolator</code> with no points. Some points must be
14 * added using {@link #addPoints(double[], double[])} before using the interpolator.
16 public LinearInterpolator() {
20 * Construct a <code>LinearInterpolator</code> with the given points.
22 * @param x the x-coordinates of the points.
23 * @param y the y-coordinates of the points.
24 * @throws IllegalArgumentException if the lengths of <code>x</code> and <code>y</code>
26 * @see #addPoints(double[], double[])
28 public LinearInterpolator(double[] x, double[] y) {
32 public LinearInterpolator(List<Double> x, List<Double> y) {
37 * Add the point to the linear interpolation.
39 * @param x the x-coordinate of the point.
40 * @param y the y-coordinate of the point.
42 public void addPoint(double x, double y) {
47 * Add the points to the linear interpolation.
49 * @param x the x-coordinates of the points.
50 * @param y the y-coordinates of the points.
51 * @throws IllegalArgumentException if the lengths of <code>x</code> and <code>y</code>
54 public void addPoints(double[] x, double[] y) {
55 if (x.length != y.length) {
56 throw new IllegalArgumentException("Array lengths do not match, x="+x.length +
59 for (int i=0; i < x.length; i++) {
60 sortMap.put(x[i],y[i]);
64 public void addPoints(List<Double> x, List<Double> y){
65 if (x.size() != y.size()) {
66 throw new IllegalArgumentException("Array lengths do not match, x="+x.size() +
69 for (int i=0; i < x.size(); i++) {
70 sortMap.put( (Double) x.toArray()[i], (Double) y.toArray()[i]);
75 public double getValue(double x) {
78 // Froyo does not support floorEntry, firstEntry or higherEntry. We instead have to
79 // resort to using other more awkward methods.
84 // Wow, x was a key in the map. Such luck.
85 return y1.doubleValue();
88 // we now know that x is not in the map, so we need to find the lower and higher keys.
90 // let's just make certain that our map is not empty.
91 if ( sortMap.isEmpty() ) {
92 throw new IllegalStateException("No points added yet to the interpolator.");
95 // firstKey in the map - cannot be null since the map is not empty.
96 Double firstKey = sortMap.firstKey();
98 // x is smaller than the first entry in the map.
99 if ( x < firstKey.doubleValue() ) {
100 y1 = sortMap.get(firstKey);
101 return y1.doubleValue();
104 // floor key is the largest key smaller than x - since we have at least one key,
105 // and x>=firstKey, we know that floorKey != null.
106 Double floorKey = sortMap.subMap(firstKey, x).lastKey();
108 x1 = floorKey.doubleValue();
109 y1 = sortMap.get(floorKey);
111 // Now we need to find the key that is greater or equal to x
112 SortedMap<Double,Double> tailMap = sortMap.tailMap(x);
114 // Check if x is bigger than all the entries.
115 if ( tailMap.isEmpty() ) {
116 return y1.doubleValue();
118 Double ceilKey = tailMap.firstKey();
120 // Check if x is bigger than all the entries.
121 if ( ceilKey == null ) {
122 return y1.doubleValue();
125 x2 = ceilKey.doubleValue();
126 y2 = sortMap.get(ceilKey);
128 return (x - x1)/(x2-x1) * (y2-y1) + y1;
132 public double[] getXPoints() {
133 double[] x = new double[sortMap.size()];
134 Iterator<Double> iter = sortMap.keySet().iterator();
135 for (int i=0; iter.hasNext(); i++) {
142 @SuppressWarnings("unchecked")
144 public LinearInterpolator clone() {
146 LinearInterpolator other = (LinearInterpolator)super.clone();
147 other.sortMap = (TreeMap<Double,Double>)this.sortMap.clone();
149 } catch (CloneNotSupportedException e) {
150 throw new BugException("CloneNotSupportedException?!",e);