create changelog entry
[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                 
110                 if (list == null) {
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                 if (list.size() > 0){
122                         list.set(list.size() - 1, value);
123                 }
124                 
125                 double min = minValues.get(type);
126                 double max = maxValues.get(type);
127                 
128                 if (Double.isNaN(min) || (value < min)) {
129                         minValues.put(type, value);
130                 }
131                 if (Double.isNaN(max) || (value > max)) {
132                         maxValues.put(type, value);
133                 }
134                 modID++;
135         }
136         
137         
138         /**
139          * Return the branch name.
140          */
141         public String getBranchName() {
142                 return branchName;
143         }
144         
145         /**
146          * Return the variable types included in this branch.  The types are sorted in their
147          * natural order.
148          */
149         public FlightDataType[] getTypes() {
150                 FlightDataType[] array = values.keySet().toArray(new FlightDataType[0]);
151                 Arrays.sort(array);
152                 return array;
153         }
154         
155         /**
156          * Return the number of data points in this branch.
157          */
158         public int getLength() {
159                 for (FlightDataType t : values.keySet()) {
160                         return values.get(t).size();
161                 }
162                 return 0;
163         }
164         
165         /**
166          * Return an array of values for the specified variable type.
167          * 
168          * @param type  the variable type.
169          * @return              a list of the variable values, or <code>null</code> if
170          *                              the variable type hasn't been added to this branch.
171          */
172         public List<Double> get(FlightDataType type) {
173                 ArrayList<Double> list = values.get(type);
174                 if (list == null)
175                         return null;
176                 return list.clone();
177         }
178         
179         /**
180          * Return the last value of the specified type in the branch, or NaN if the type is
181          * unavailable.
182          * 
183          * @param type  the parameter type.
184          * @return              the last value in this branch, or NaN.
185          */
186         public double getLast(FlightDataType type) {
187                 ArrayList<Double> list = values.get(type);
188                 if (list == null || list.isEmpty())
189                         return Double.NaN;
190                 return list.get(list.size() - 1);
191         }
192         
193         /**
194          * Return the minimum value of the specified type in the branch, or NaN if the type
195          * is unavailable.
196          * 
197          * @param type  the parameter type.
198          * @return              the minimum value in this branch, or NaN.
199          */
200         public double getMinimum(FlightDataType type) {
201                 Double v = minValues.get(type);
202                 if (v == null)
203                         return Double.NaN;
204                 return v;
205         }
206         
207         /**
208          * Return the maximum value of the specified type in the branch, or NaN if the type
209          * is unavailable.
210          * 
211          * @param type  the parameter type.
212          * @return              the maximum value in this branch, or NaN.
213          */
214         public double getMaximum(FlightDataType type) {
215                 Double v = maxValues.get(type);
216                 if (v == null)
217                         return Double.NaN;
218                 return v;
219         }
220         
221         
222         /**
223          * Add a flight event to this branch.
224          * 
225          * @param event         the event to add.
226          * @throws IllegalStateException        if this branch has been made immutable.
227          */
228         public void addEvent(FlightEvent event) {
229                 mutable.check();
230                 events.add(event.resetSourceAndData());
231                 modID++;
232         }
233         
234         
235         /**
236          * Return the list of events.
237          * 
238          * @return      the list of events during the flight.
239          */
240         public List<FlightEvent> getEvents() {
241                 return events.clone();
242         }
243         
244         
245         /**
246          * Make this FlightDataBranch immutable.  Any calls to the set methods that would
247          * modify this object will after this call throw an <code>IllegalStateException</code>.
248          */
249         public void immute() {
250                 mutable.immute();
251         }
252         
253         
254         /**
255          * Return whether this branch is still mutable.
256          */
257         public boolean isMutable() {
258                 return mutable.isMutable();
259         }
260         
261         
262         @Override
263         public int getModID() {
264                 return modID;
265         }
266         
267 }