1 package net.sf.openrocket.simulation;
3 import java.util.ArrayList;
6 import net.sf.openrocket.aerodynamics.WarningSet;
7 import net.sf.openrocket.util.MathUtil;
8 import net.sf.openrocket.util.Pair;
11 public class FlightData {
14 * An immutable FlightData object with NaN data.
16 public static final FlightData NaN_DATA;
18 FlightData data = new FlightData();
23 private boolean mutable = true;
24 private final ArrayList<FlightDataBranch> branches = new ArrayList<FlightDataBranch>();
26 private final WarningSet warnings = new WarningSet();
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;
38 * Create a FlightData object with no content. The resulting object is mutable.
46 * Construct an immutable FlightData object with no data branches but the specified
47 * summary information.
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.
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;
73 * Create an immutable FlightData object with the specified branches.
75 * @param branches the branches.
77 public FlightData(FlightDataBranch ... branches) {
80 for (FlightDataBranch b: branches)
83 calculateIntrestingValues();
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.
95 * @return the warnings generated during this simulation.
97 public WarningSet getWarningSet() {
102 public void addBranch(FlightDataBranch branch) {
104 throw new IllegalStateException("FlightData has been made immutable");
107 branches.add(branch);
109 if (branches.size() == 1) {
110 calculateIntrestingValues();
114 public int getBranchCount() {
115 return branches.size();
118 public FlightDataBranch getBranch(int n) {
119 return branches.get(n);
124 public double getMaxAltitude() {
128 public double getMaxVelocity() {
133 * NOTE: This value will also contain any possible acceleration peak when opening a parachute!
135 public double getMaxAcceleration() {
136 return maxAcceleration;
139 public double getMaxMachNumber() {
140 return maxMachNumber;
143 public double getTimeToApogee() {
147 public double getFlightTime() {
151 public double getGroundHitVelocity() {
152 return groundHitVelocity;
158 * Calculate the max. altitude/velocity/acceleration, time to apogee, flight time
159 * and ground hit velocity.
161 private void calculateIntrestingValues() {
162 if (branches.isEmpty())
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);
170 flightTime = branch.getLast(FlightDataBranch.TYPE_TIME);
171 if (branch.getLast(FlightDataBranch.TYPE_ALTITUDE) < 10) {
172 groundHitVelocity = branch.getLast(FlightDataBranch.TYPE_VELOCITY_TOTAL);
174 groundHitVelocity = Double.NaN;
178 List<Double> time = branch.get(FlightDataBranch.TYPE_TIME);
179 List<Double> altitude = branch.get(FlightDataBranch.TYPE_ALTITUDE);
181 if (time == null || altitude == null) {
182 timeToApogee = Double.NaN;
183 maxAcceleration = Double.NaN;
187 for (Double alt: altitude) {
189 if (MathUtil.equals(alt, maxAltitude))
195 if (index < time.size())
196 timeToApogee = time.get(index);
198 timeToApogee = Double.NaN;
200 // Max. acceleration (must be after apogee time)
201 if (branch.get(FlightDataBranch.TYPE_ACCELERATION_TOTAL) != null) {
202 maxAcceleration = calculateMaxAcceleration();
204 maxAcceleration = Double.NaN;
209 public void immute() {
212 public boolean isMutable() {
219 * Find the maximum acceleration before apogee.
221 private double calculateMaxAcceleration() {
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();
234 List<Double> time = branch.get(FlightDataBranch.TYPE_TIME);
235 List<Double> acceleration = branch.get(FlightDataBranch.TYPE_ACCELERATION_TOTAL);
237 if (time == null || acceleration == null) {
243 for (int i=0; i<time.size(); i++) {
244 if (time.get(i) >= endTime) {
247 double a = acceleration.get(i);