6a9a308b6f11e3b8cde69e4a223080d8b11ea548
[debian/openrocket] / core / src / net / sf / openrocket / util / LinearInterpolator.java
1 package net.sf.openrocket.util;
2
3 import java.util.Iterator;
4 import java.util.SortedMap;
5 import java.util.TreeMap;
6
7 public class LinearInterpolator implements Cloneable {
8
9         private TreeMap<Double, Double> sortMap = new TreeMap<Double,Double>();
10
11         /**
12          * Construct a <code>LinearInterpolator</code> with no points.  Some points must be
13          * added using {@link #addPoints(double[], double[])} before using the interpolator.
14          */
15         public LinearInterpolator() {
16         }
17
18         /**
19          * Construct a <code>LinearInterpolator</code> with the given points.
20          * 
21          * @param x             the x-coordinates of the points.
22          * @param y             the y-coordinates of the points.
23          * @throws IllegalArgumentException             if the lengths of <code>x</code> and <code>y</code>
24          *                                                                              are not equal.
25          * @see #addPoints(double[], double[])
26          */
27         public LinearInterpolator(double[] x, double[] y) {
28                 addPoints(x,y);
29         }
30
31
32         /**
33          * Add the point to the linear interpolation.
34          * 
35          * @param x             the x-coordinate of the point.
36          * @param y             the y-coordinate of the point.
37          */
38         public void addPoint(double x, double y) {
39                 sortMap.put(x, y);
40         }
41
42         /**
43          * Add the points to the linear interpolation.
44          * 
45          * @param x             the x-coordinates of the points.
46          * @param y             the y-coordinates of the points.
47          * @throws IllegalArgumentException             if the lengths of <code>x</code> and <code>y</code>
48          *                                                                              are not equal.
49          */
50         public void addPoints(double[] x, double[] y) {
51                 if (x.length != y.length) {
52                         throw new IllegalArgumentException("Array lengths do not match, x="+x.length +
53                                         " y="+y.length);
54                 }
55                 for (int i=0; i < x.length; i++) {
56                         sortMap.put(x[i],y[i]);
57                 }
58         }
59
60
61
62         public double getValue(double x) {
63                 double x1, x2;
64                 Double y1, y2;
65                 // Froyo does not support floorEntry, firstEntry or higherEntry.  We instead have to
66                 // resort to using other more awkward methods.
67
68                 y1 = sortMap.get(x);
69
70                 if ( y1 != null ) {
71                         // Wow, x was a key in the map.  Such luck.
72                         return y1.doubleValue();
73                 }
74
75                 // we now know that x is not in the map, so we need to find the lower and higher keys.
76                 
77                 // let's just make certain that our map is not empty.
78                 if ( sortMap.isEmpty() ) {
79                         throw new IllegalStateException("No points added yet to the interpolator.");
80                 }
81                 
82                 // firstKey in the map - cannot be null since the map is not empty.
83                 Double firstKey = sortMap.firstKey();
84
85                 // x is smaller than the first entry in the map.
86                 if ( x < firstKey.doubleValue() ) {
87                         y1 = sortMap.get(firstKey);
88                         return y1.doubleValue();
89                 }
90                 
91                 // floor key is the largest key smaller than x - since we have at least one key,
92                 // and x>=firstKey, we know that floorKey != null.
93                 Double floorKey = sortMap.subMap(firstKey, x).lastKey();
94
95                 x1 = floorKey.doubleValue();
96                 y1 = sortMap.get(floorKey);
97
98                 // Now we need to find the key that is greater or equal to x
99                 SortedMap<Double,Double> tailMap = sortMap.tailMap(x);
100
101                 // Check if x is bigger than all the entries.
102                 if ( tailMap.isEmpty() ) {
103                         return y1.doubleValue();
104                 }
105                 Double ceilKey = tailMap.firstKey();
106                 
107                 // Check if x is bigger than all the entries.
108                 if ( ceilKey == null ) {
109                         return y1.doubleValue();
110                 }
111                 
112                 x2 = ceilKey.doubleValue();
113                 y2 = sortMap.get(ceilKey);
114
115                 return (x - x1)/(x2-x1) * (y2-y1) + y1;
116         }
117
118
119         public double[] getXPoints() {
120                 double[] x = new double[sortMap.size()];
121                 Iterator<Double> iter = sortMap.keySet().iterator();
122                 for (int i=0; iter.hasNext(); i++) {
123                         x[i] = iter.next();
124                 }
125                 return x;
126         }
127
128
129         @SuppressWarnings("unchecked")
130         @Override
131         public LinearInterpolator clone() {
132                 try {
133                         LinearInterpolator other = (LinearInterpolator)super.clone();
134                         other.sortMap = (TreeMap<Double,Double>)this.sortMap.clone();
135                         return other;
136                 } catch (CloneNotSupportedException e) {
137                         throw new BugException("CloneNotSupportedException?!",e);
138                 }
139         }
140
141 }