bug fixes
[debian/openrocket] / src / net / sf / openrocket / simulation / FlightData.java
1 package net.sf.openrocket.simulation;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import net.sf.openrocket.aerodynamics.WarningSet;
7 import net.sf.openrocket.util.MathUtil;
8 import net.sf.openrocket.util.Pair;
9
10
11 public class FlightData {
12         
13         /**
14          * An immutable FlightData object with NaN data.
15          */
16         public static final FlightData NaN_DATA;
17         static {
18                 FlightData data = new FlightData();
19                 data.immute();
20                 NaN_DATA = data;
21         }
22
23         private boolean mutable = true;
24         private final ArrayList<FlightDataBranch> branches = new ArrayList<FlightDataBranch>();
25         
26         private final WarningSet warnings = new WarningSet();
27         
28         private double maxAltitude = Double.NaN;
29         private double maxVelocity = Double.NaN;
30         private double maxAcceleration = Double.NaN;
31         private double maxMachNumber = Double.NaN;
32         private double timeToApogee = Double.NaN;
33         private double flightTime = Double.NaN;
34         private double groundHitVelocity = Double.NaN;
35
36         
37         /**
38          * Create a FlightData object with no content.  The resulting object is mutable.
39          */
40         public FlightData() {
41                 
42         }
43         
44         
45         /**
46          * Construct an immutable FlightData object with no data branches but the specified
47          * summary information.
48          * 
49          * @param maxAltitude                   maximum altitude.
50          * @param maxVelocity                   maximum velocity.
51          * @param maxAcceleration               maximum acceleration.
52          * @param maxMachNumber                 maximum Mach number.
53          * @param timeToApogee                  time to apogee.
54          * @param flightTime                    total flight time.
55          * @param groundHitVelocity             ground hit velocity.
56          */
57         public FlightData(double maxAltitude, double maxVelocity, double maxAcceleration,
58                         double maxMachNumber, double timeToApogee, double flightTime,
59                         double groundHitVelocity) {
60                 this.maxAltitude = maxAltitude;
61                 this.maxVelocity = maxVelocity;
62                 this.maxAcceleration = maxAcceleration;
63                 this.maxMachNumber = maxMachNumber;
64                 this.timeToApogee = timeToApogee;
65                 this.flightTime = flightTime;
66                 this.groundHitVelocity = groundHitVelocity;
67                 
68                 this.immute();
69         }
70
71
72         /**
73          * Create an immutable FlightData object with the specified branches.
74          * 
75          * @param branches      the branches.
76          */
77         public FlightData(FlightDataBranch ... branches) {
78                 this();
79                 
80                 for (FlightDataBranch b: branches)
81                         this.addBranch(b);
82                 
83                 calculateIntrestingValues();
84                 this.immute();
85         }
86         
87         
88         
89         
90         /**
91          * Returns the warning set associated with this object.  This WarningSet cannot be
92          * set, so simulations must use this warning set to store their warnings.
93          * The returned WarningSet should not be modified otherwise.
94          * 
95          * @return      the warnings generated during this simulation.
96          */
97         public WarningSet getWarningSet() {
98                 return warnings;
99         }
100         
101         
102         public void addBranch(FlightDataBranch branch) {
103                 if (!mutable)
104                         throw new IllegalStateException("FlightData has been made immutable");
105
106                 branch.immute();
107                 branches.add(branch);
108                 
109                 if (branches.size() == 1) {
110                         calculateIntrestingValues();
111                 }
112         }
113
114         public int getBranchCount() {
115                 return branches.size();
116         }
117         
118         public FlightDataBranch getBranch(int n) {
119                 return branches.get(n);
120         }
121         
122         
123         
124         public double getMaxAltitude() {
125                 return maxAltitude;
126         }
127         
128         public double getMaxVelocity() {
129                 return maxVelocity;
130         }
131         
132         /**
133          * NOTE:  This value will also contain any possible acceleration peak when opening a parachute!
134          */
135         public double getMaxAcceleration() {
136                 return maxAcceleration;
137         }
138         
139         public double getMaxMachNumber() {
140                 return maxMachNumber;
141         }
142         
143         public double getTimeToApogee() {
144                 return timeToApogee;
145         }
146         
147         public double getFlightTime() {
148                 return flightTime;
149         }
150         
151         public double getGroundHitVelocity() {
152                 return groundHitVelocity;
153         }
154         
155         
156         
157         /**
158          * Calculate the max. altitude/velocity/acceleration, time to apogee, flight time
159          * and ground hit velocity.
160          */
161         private void calculateIntrestingValues() {
162                 if (branches.isEmpty())
163                         return;
164                 
165                 FlightDataBranch branch = branches.get(0);
166                 maxAltitude = branch.getMaximum(FlightDataBranch.TYPE_ALTITUDE);
167                 maxVelocity = branch.getMaximum(FlightDataBranch.TYPE_VELOCITY_TOTAL);
168                 maxMachNumber = branch.getMaximum(FlightDataBranch.TYPE_MACH_NUMBER);
169
170                 flightTime = branch.getLast(FlightDataBranch.TYPE_TIME);
171                 if (branch.getLast(FlightDataBranch.TYPE_ALTITUDE) < 10) {
172                         groundHitVelocity = branch.getLast(FlightDataBranch.TYPE_VELOCITY_TOTAL);
173                 } else {
174                         groundHitVelocity = Double.NaN;
175                 }
176                 
177                 // Time to apogee
178                 List<Double> time = branch.get(FlightDataBranch.TYPE_TIME);
179                 List<Double> altitude = branch.get(FlightDataBranch.TYPE_ALTITUDE);
180                 
181                 if (time == null || altitude == null) {
182                         timeToApogee = Double.NaN;
183                         maxAcceleration = Double.NaN;
184                         return;
185                 }
186                 int index = 0;
187                 for (Double alt: altitude) {
188                         if (alt != null) {
189                                 if (MathUtil.equals(alt, maxAltitude))
190                                         break;
191                         }
192
193                         index++;
194                 }
195                 if (index < time.size())
196                         timeToApogee = time.get(index);
197                 else
198                         timeToApogee = Double.NaN;
199
200                 // Max. acceleration (must be after apogee time)
201                 if (branch.get(FlightDataBranch.TYPE_ACCELERATION_TOTAL) != null) {
202                         maxAcceleration = calculateMaxAcceleration();
203                 } else {
204                         maxAcceleration = Double.NaN;
205                 }
206         }
207
208
209         public void immute() {
210                 mutable = false;
211         }
212         public boolean isMutable() {
213                 return mutable;
214         }
215         
216         
217
218         /**
219          * Find the maximum acceleration before apogee.
220          */
221         private double calculateMaxAcceleration() {
222                 
223                 // End check at first recovery device deployment
224                 double endTime = Double.MAX_VALUE;
225                 FlightDataBranch branch = this.getBranch(0);
226                 for (Pair<Double, FlightEvent> event: branch.getEvents()) {
227                         if (event.getV().getType() == FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT) {
228                                 if (event.getV().getTime() < endTime) {
229                                         endTime = event.getV().getTime();
230                                 }
231                         }
232                 }
233                 
234                 List<Double> time = branch.get(FlightDataBranch.TYPE_TIME);
235                 List<Double> acceleration = branch.get(FlightDataBranch.TYPE_ACCELERATION_TOTAL);
236                 
237                 if (time == null || acceleration == null) {
238                         return Double.NaN;
239                 }
240                 
241                 double max = 0;
242                 
243                 for (int i=0; i<time.size(); i++) {
244                         if (time.get(i) >= endTime) {
245                                 break;
246                         }
247                         double a = acceleration.get(i);
248                         if (a > max)
249                                 max = a;
250                 }
251
252                 return max;
253         }
254 }