Big update to custom expression feature.
[debian/openrocket] / core / src / net / sf / openrocket / util / LinearInterpolator.java
1 package net.sf.openrocket.util;
2
3 import java.util.Arrays;
4 import java.util.Iterator;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.TreeMap;
8
9 public class LinearInterpolator implements Cloneable {
10
11         private TreeMap<Double, Double> sortMap = new TreeMap<Double,Double>();
12
13         /**
14          * Construct a <code>LinearInterpolator</code> with no points.  Some points must be
15          * added using {@link #addPoints(double[], double[])} before using the interpolator.
16          */
17         public LinearInterpolator() {
18         }
19         
20         /**
21          * Construct a <code>LinearInterpolator</code> with the given points.
22          * 
23          * @param x             the x-coordinates of the points.
24          * @param y             the y-coordinates of the points.
25          * @throws IllegalArgumentException             if the lengths of <code>x</code> and <code>y</code>
26          *                                                                              are not equal.
27          * @see #addPoints(double[], double[])
28          */
29         public LinearInterpolator(double[] x, double[] y) {
30                 addPoints(x,y);
31         }
32         
33         public LinearInterpolator(List<Double> x, List<Double> y) {
34                 addPoints(x,y);
35         }
36         
37         /**
38          * Add the point to the linear interpolation.
39          * 
40          * @param x             the x-coordinate of the point.
41          * @param y             the y-coordinate of the point.
42          */
43         public void addPoint(double x, double y) {
44                 sortMap.put(x, y);
45         }
46         
47         /**
48          * Add the points to the linear interpolation.
49          * 
50          * @param x             the x-coordinates of the points.
51          * @param y             the y-coordinates of the points.
52          * @throws IllegalArgumentException             if the lengths of <code>x</code> and <code>y</code>
53          *                                                                              are not equal.
54          */
55         public void addPoints(double[] x, double[] y) {
56                 if (x.length != y.length) {
57                         throw new IllegalArgumentException("Array lengths do not match, x="+x.length +
58                                         " y="+y.length);
59                 }
60                 for (int i=0; i < x.length; i++) {
61                         sortMap.put(x[i],y[i]);
62                 }
63         }
64         
65         public void addPoints(List<Double> x, List<Double> y){
66                 if (x.size() != y.size()) {
67                         throw new IllegalArgumentException("Array lengths do not match, x="+x.size() +
68                                         " y="+y.size());
69                 }
70                 for (int i=0; i < x.size(); i++) {
71                         sortMap.put( (Double) x.toArray()[i], (Double) y.toArray()[i]);
72                 }
73         }
74         
75         
76         public double getValue(double x) {
77                 Map.Entry<Double,Double> e1, e2;
78                 double x1, x2;
79                 double y1, y2;
80                 
81                 e1 = sortMap.floorEntry(x);
82                 
83                 if (e1 == null) {
84                         // x smaller than any value in the set
85                         e1 = sortMap.firstEntry();
86                         if (e1 == null) {
87                                 throw new IllegalStateException("No points added yet to the interpolator.");
88                         }
89                         return e1.getValue();
90                 }
91                 
92                 x1 = e1.getKey();
93                 e2 = sortMap.higherEntry(x1);
94
95                 if (e2 == null) {
96                         // x larger than any value in the set
97                         return e1.getValue();
98                 }
99                 
100                 x2 = e2.getKey();
101                 y1 = e1.getValue();
102                 y2 = e2.getValue();
103                 
104                 return (x - x1)/(x2-x1) * (y2-y1) + y1;
105         }
106         
107         
108         public double[] getXPoints() {
109                 double[] x = new double[sortMap.size()];
110                 Iterator<Double> iter = sortMap.keySet().iterator();
111                 for (int i=0; iter.hasNext(); i++) {
112                         x[i] = iter.next();
113                 }
114                 return x;
115         }
116         
117         
118         @SuppressWarnings("unchecked")
119         @Override
120         public LinearInterpolator clone() {
121                 try {
122                         LinearInterpolator other = (LinearInterpolator)super.clone();
123                         other.sortMap = (TreeMap<Double,Double>)this.sortMap.clone();
124                         return other;
125                 } catch (CloneNotSupportedException e) {
126                         throw new BugException("CloneNotSupportedException?!",e);
127                 }
128         }
129
130         
131         public static void main(String[] args) {
132                 LinearInterpolator interpolator = new LinearInterpolator(
133                                 new double[] {1, 1.5, 2, 4, 5},
134                                 new double[] {0, 1,   0, 2, 2}
135                 );
136                 
137                 for (double x=0; x < 6; x+=0.1) {
138                         System.out.printf("%.1f:  %.2f\n", x, interpolator.getValue(x));
139                 }
140                 
141                 // Should be the same
142                 
143                 ArrayList<Double> time = new ArrayList<Double>( Arrays.asList( new Double[] {1.0, 1.5, 2.0, 4.0, 5.0} ));
144                 ArrayList<Double> y = new ArrayList<Double>( Arrays.asList( new Double[] {0.0, 1.0, 0.0, 2.0, 2.0} ));
145                 
146                 LinearInterpolator interpolator2 = new LinearInterpolator(time,y);
147                 for (double x=0; x < 6; x+=0.1) {
148                         System.out.printf("%.1f:  %.2f\n", x, interpolator2.getValue(x));
149                 }
150         }       
151 }