475a068eecf96faf20dda54dfffb7ef6da733596
[debian/openrocket] / core / src / net / sf / openrocket / simulation / FlightDataBranch.java
1 package net.sf.openrocket.simulation;
2
3 import java.util.Arrays;
4 import java.util.HashMap;
5 import java.util.LinkedHashMap;
6 import java.util.List;
7 import java.util.Map;
8
9 import net.sf.openrocket.util.ArrayList;
10 import net.sf.openrocket.util.Monitorable;
11 import net.sf.openrocket.util.Mutable;
12
13 /**
14  * A single branch of flight data.  The data is ordered based on some variable, typically time.
15  * It also contains flight events that have occurred during simulation.
16  * <p>
17  * After instantiating a FlightDataBranch data and new variable types can be added to the branch.
18  * A new data point (a value for each variable defined) is created using {@link #addPoint()} after
19  * which the value for each variable type can be set using {@link #setValue(FlightDataType, double)}.
20  * Each variable type does NOT have to be set, unset values will default to NaN.  New variable types
21  * not defined in the constructor can be added using {@link #setValue(FlightDataType, double)}, they
22  * will be created and all previous values will be set to NaN.
23  * <p>
24  * After populating a FlightDataBranch object it can be made immutable by calling {@link #immute()}.
25  * 
26  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
27  */
28 public class FlightDataBranch implements Monitorable {
29         
30         /** The name of this flight data branch. */
31         private final String branchName;
32         
33         private final Map<FlightDataType, ArrayList<Double>> values =
34                         new LinkedHashMap<FlightDataType, ArrayList<Double>>();
35         
36         private final Map<FlightDataType, Double> maxValues = new HashMap<FlightDataType, Double>();
37         private final Map<FlightDataType, Double> minValues = new HashMap<FlightDataType, Double>();
38         
39
40         private final ArrayList<FlightEvent> events = new ArrayList<FlightEvent>();
41         
42         private Mutable mutable = new Mutable();
43         
44         private int modID = 0;
45         
46         /**
47          * Sole constructor.  Defines the name of the FlightDataBranch and at least one variable type.
48          * 
49          * @param name          the name of this FlightDataBranch.
50          * @param types         data types to include (must include at least one type).
51          */
52         public FlightDataBranch(String name, FlightDataType... types) {
53                 if (types.length == 0) {
54                         throw new IllegalArgumentException("Must specify at least one data type.");
55                 }
56                 
57                 this.branchName = name;
58                 
59                 for (FlightDataType t : types) {
60                         if (values.containsKey(t)) {
61                                 throw new IllegalArgumentException("Value type " + t + " specified multiple " +
62                                                 "times in constructor.");
63                         }
64                         
65                         values.put(t, new ArrayList<Double>());
66                         minValues.put(t, Double.NaN);
67                         maxValues.put(t, Double.NaN);
68                 }
69         }
70         
71         /**
72          * Makes an 'empty' flight data branch which has no data but all built in data types are defined.
73          */
74         public FlightDataBranch() {
75                 branchName = "Empty branch";
76                 for (FlightDataType type : FlightDataType.ALL_TYPES){
77                         this.setValue(type, Double.NaN);
78                 }
79                 this.immute();
80         }
81
82         /**
83          * Adds a new point into the data branch.  The value for all types is set to NaN by default.
84          * 
85          * @throws IllegalStateException        if this object has been made immutable.
86          */
87         public void addPoint() {
88                 mutable.check();
89                 
90                 for (FlightDataType t : values.keySet()) {
91                         values.get(t).add(Double.NaN);
92                 }
93                 modID++;
94         }
95         
96         
97         /**
98          * Set the value for a specific data type at the latest point.  New variable types can be
99          * added to the FlightDataBranch transparently.
100          * 
101          * @param type          the variable to set.
102          * @param value         the value to set.
103          * @throws IllegalStateException        if this object has been made immutable.
104          */
105         public void setValue(FlightDataType type, double value) {
106                 mutable.check();
107                 
108                 ArrayList<Double> list = values.get(type);
109                 if (list == null) {
110                         
111                         list = new ArrayList<Double>();
112                         int n = getLength();
113                         for (int i = 0; i < n; i++) {
114                                 list.add(Double.NaN);
115                         }
116                         values.put(type, list);
117                         minValues.put(type, value);
118                         maxValues.put(type, value);
119                         
120                 }
121                 list.set(list.size() - 1, value);
122                 double min = minValues.get(type);
123                 double max = maxValues.get(type);
124                 
125                 if (Double.isNaN(min) || (value < min)) {
126                         minValues.put(type, value);
127                 }
128                 if (Double.isNaN(max) || (value > max)) {
129                         maxValues.put(type, value);
130                 }
131                 modID++;
132         }
133         
134         
135         /**
136          * Return the branch name.
137          */
138         public String getBranchName() {
139                 return branchName;
140         }
141         
142         /**
143          * Return the variable types included in this branch.  The types are sorted in their
144          * natural order.
145          */
146         public FlightDataType[] getTypes() {
147                 FlightDataType[] array = values.keySet().toArray(new FlightDataType[0]);
148                 Arrays.sort(array);
149                 return array;
150         }
151         
152         /**
153          * Return the number of data points in this branch.
154          */
155         public int getLength() {
156                 for (FlightDataType t : values.keySet()) {
157                         return values.get(t).size();
158                 }
159                 return 0;
160         }
161         
162         /**
163          * Return an array of values for the specified variable type.
164          * 
165          * @param type  the variable type.
166          * @return              a list of the variable values, or <code>null</code> if
167          *                              the variable type hasn't been added to this branch.
168          */
169         public List<Double> get(FlightDataType type) {
170                 ArrayList<Double> list = values.get(type);
171                 if (list == null)
172                         return null;
173                 return list.clone();
174         }
175         
176         /**
177          * Return the last value of the specified type in the branch, or NaN if the type is
178          * unavailable.
179          * 
180          * @param type  the parameter type.
181          * @return              the last value in this branch, or NaN.
182          */
183         public double getLast(FlightDataType type) {
184                 ArrayList<Double> list = values.get(type);
185                 if (list == null || list.isEmpty())
186                         return Double.NaN;
187                 return list.get(list.size() - 1);
188         }
189         
190         /**
191          * Return the minimum value of the specified type in the branch, or NaN if the type
192          * is unavailable.
193          * 
194          * @param type  the parameter type.
195          * @return              the minimum value in this branch, or NaN.
196          */
197         public double getMinimum(FlightDataType type) {
198                 Double v = minValues.get(type);
199                 if (v == null)
200                         return Double.NaN;
201                 return v;
202         }
203         
204         /**
205          * Return the maximum value of the specified type in the branch, or NaN if the type
206          * is unavailable.
207          * 
208          * @param type  the parameter type.
209          * @return              the maximum value in this branch, or NaN.
210          */
211         public double getMaximum(FlightDataType type) {
212                 Double v = maxValues.get(type);
213                 if (v == null)
214                         return Double.NaN;
215                 return v;
216         }
217         
218         
219         /**
220          * Add a flight event to this branch.
221          * 
222          * @param event         the event to add.
223          * @throws IllegalStateException        if this branch has been made immutable.
224          */
225         public void addEvent(FlightEvent event) {
226                 mutable.check();
227                 events.add(event.resetSourceAndData());
228                 modID++;
229         }
230         
231         
232         /**
233          * Return the list of events.
234          * 
235          * @return      the list of events during the flight.
236          */
237         public List<FlightEvent> getEvents() {
238                 return events.clone();
239         }
240         
241         
242         /**
243          * Make this FlightDataBranch immutable.  Any calls to the set methods that would
244          * modify this object will after this call throw an <code>IllegalStateException</code>.
245          */
246         public void immute() {
247                 mutable.immute();
248         }
249         
250         
251         /**
252          * Return whether this branch is still mutable.
253          */
254         public boolean isMutable() {
255                 return mutable.isMutable();
256         }
257         
258         
259         @Override
260         public int getModID() {
261                 return modID;
262         }
263         
264 }