Merge commit '46077ef99f953486550547c15bd60dd02bab9241' into upstream
[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
73         /**
74          * Adds a new point into the data branch.  The value for all types is set to NaN by default.
75          * 
76          * @throws IllegalStateException        if this object has been made immutable.
77          */
78         public void addPoint() {
79                 mutable.check();
80                 
81                 for (FlightDataType t : values.keySet()) {
82                         values.get(t).add(Double.NaN);
83                 }
84                 modID++;
85         }
86         
87         
88         /**
89          * Set the value for a specific data type at the latest point.  New variable types can be
90          * added to the FlightDataBranch transparently.
91          * 
92          * @param type          the variable to set.
93          * @param value         the value to set.
94          * @throws IllegalStateException        if this object has been made immutable.
95          */
96         public void setValue(FlightDataType type, double value) {
97                 mutable.check();
98                 
99                 ArrayList<Double> list = values.get(type);
100                 if (list == null) {
101                         
102                         list = new ArrayList<Double>();
103                         int n = getLength();
104                         for (int i = 0; i < n; i++) {
105                                 list.add(Double.NaN);
106                         }
107                         values.put(type, list);
108                         minValues.put(type, value);
109                         maxValues.put(type, value);
110                         
111                 }
112                 list.set(list.size() - 1, value);
113                 double min = minValues.get(type);
114                 double max = maxValues.get(type);
115                 
116                 if (Double.isNaN(min) || (value < min)) {
117                         minValues.put(type, value);
118                 }
119                 if (Double.isNaN(max) || (value > max)) {
120                         maxValues.put(type, value);
121                 }
122                 modID++;
123         }
124         
125         
126         /**
127          * Return the branch name.
128          */
129         public String getBranchName() {
130                 return branchName;
131         }
132         
133         /**
134          * Return the variable types included in this branch.  The types are sorted in their
135          * natural order.
136          */
137         public FlightDataType[] getTypes() {
138                 FlightDataType[] array = values.keySet().toArray(new FlightDataType[0]);
139                 Arrays.sort(array);
140                 return array;
141         }
142         
143         /**
144          * Return the number of data points in this branch.
145          */
146         public int getLength() {
147                 for (FlightDataType t : values.keySet()) {
148                         return values.get(t).size();
149                 }
150                 return 0;
151         }
152         
153         /**
154          * Return an array of values for the specified variable type.
155          * 
156          * @param type  the variable type.
157          * @return              a list of the variable values, or <code>null</code> if
158          *                              the variable type hasn't been added to this branch.
159          */
160         public List<Double> get(FlightDataType type) {
161                 ArrayList<Double> list = values.get(type);
162                 if (list == null)
163                         return null;
164                 return list.clone();
165         }
166         
167         /**
168          * Return the last value of the specified type in the branch, or NaN if the type is
169          * unavailable.
170          * 
171          * @param type  the parameter type.
172          * @return              the last value in this branch, or NaN.
173          */
174         public double getLast(FlightDataType type) {
175                 ArrayList<Double> list = values.get(type);
176                 if (list == null || list.isEmpty())
177                         return Double.NaN;
178                 return list.get(list.size() - 1);
179         }
180         
181         /**
182          * Return the minimum value of the specified type in the branch, or NaN if the type
183          * is unavailable.
184          * 
185          * @param type  the parameter type.
186          * @return              the minimum value in this branch, or NaN.
187          */
188         public double getMinimum(FlightDataType type) {
189                 Double v = minValues.get(type);
190                 if (v == null)
191                         return Double.NaN;
192                 return v;
193         }
194         
195         /**
196          * Return the maximum value of the specified type in the branch, or NaN if the type
197          * is unavailable.
198          * 
199          * @param type  the parameter type.
200          * @return              the maximum value in this branch, or NaN.
201          */
202         public double getMaximum(FlightDataType type) {
203                 Double v = maxValues.get(type);
204                 if (v == null)
205                         return Double.NaN;
206                 return v;
207         }
208         
209         
210         /**
211          * Add a flight event to this branch.
212          * 
213          * @param event         the event to add.
214          * @throws IllegalStateException        if this branch has been made immutable.
215          */
216         public void addEvent(FlightEvent event) {
217                 mutable.check();
218                 events.add(event.resetSourceAndData());
219                 modID++;
220         }
221         
222         
223         /**
224          * Return the list of events.
225          * 
226          * @return      the list of events during the flight.
227          */
228         public List<FlightEvent> getEvents() {
229                 return events.clone();
230         }
231         
232         
233         /**
234          * Make this FlightDataBranch immutable.  Any calls to the set methods that would
235          * modify this object will after this call throw an <code>IllegalStateException</code>.
236          */
237         public void immute() {
238                 mutable.immute();
239         }
240         
241         
242         /**
243          * Return whether this branch is still mutable.
244          */
245         public boolean isMutable() {
246                 return mutable.isMutable();
247         }
248         
249         
250         @Override
251         public int getModID() {
252                 return modID;
253         }
254         
255 }