create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / file / motor / AbstractMotorLoader.java
1 package net.sf.openrocket.file.motor;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.InputStreamReader;
6 import java.io.Reader;
7 import java.nio.charset.Charset;
8 import java.util.ArrayList;
9 import java.util.Collections;
10 import java.util.List;
11
12 import net.sf.openrocket.motor.Motor;
13 import net.sf.openrocket.util.ArrayUtils;
14 import net.sf.openrocket.util.MathUtil;
15
16 public abstract class AbstractMotorLoader implements MotorLoader {
17         
18
19         /**
20          * {@inheritDoc}
21          * <p>
22          * This method delegates the reading to the loaded from the Reader using the charset
23          * returned by {@link #getDefaultCharset()}.
24          */
25         public List<Motor> load(InputStream stream, String filename) throws IOException {
26                 return load(new InputStreamReader(stream, getDefaultCharset()), filename);
27         }
28         
29         
30         /**
31          * Load motors from the specified <code>Reader</code>.
32          * 
33          * @param reader                the source of the motor definitions.
34          * @param filename              the file name of the file, may be <code>null</code> if not 
35          *                                              applicable.
36          * @return                              a list of motors contained in the file.
37          * @throws IOException  if an I/O exception occurs of the file format is invalid.
38          */
39         protected abstract List<Motor> load(Reader reader, String filename) throws IOException;
40         
41         
42
43         /**
44          * Return the default charset to use when loading rocket files of this type.
45          * <p>
46          * If the method {@link #load(InputStream, String)} is overridden as well, this
47          * method may return <code>null</code>.
48          * 
49          * @return      the charset to use when loading the rocket file.
50          */
51         protected abstract Charset getDefaultCharset();
52         
53         
54
55
56         //////////  Helper methods  //////////
57         
58
59         /**
60          * Calculate the mass of a motor at distinct points in time based on the
61          * initial total mass, propellant weight and thrust.
62          * <p>
63          * This calculation assumes that the velocity of the exhaust remains constant
64          * during the burning.  This derives from the mass-flow and thrust relation
65          * <pre>F = m' * v</pre>
66          *  
67          * @param time    list of time points
68          * @param thrust  thrust at the discrete times
69          * @param total   total weight of the motor
70          * @param prop    propellant amount consumed during burning
71          * @return                a list of the mass at the specified time points
72          */
73         protected static List<Double> calculateMass(List<Double> time, List<Double> thrust,
74                         double total, double prop) {
75                 List<Double> mass = new ArrayList<Double>();
76                 List<Double> deltam = new ArrayList<Double>();
77                 
78                 double t0, f0;
79                 double totalMassChange = 0;
80                 double scale;
81                 
82                 // First calculate mass change between points
83                 t0 = time.get(0);
84                 f0 = thrust.get(0);
85                 for (int i = 1; i < time.size(); i++) {
86                         double t1 = time.get(i);
87                         double f1 = thrust.get(i);
88                         
89                         double dm = 0.5 * (f0 + f1) * (t1 - t0);
90                         deltam.add(dm);
91                         totalMassChange += dm;
92                         t0 = t1;
93                         f0 = f1;
94                 }
95                 
96                 // Scale mass change and calculate mass
97                 mass.add(total);
98                 scale = prop / totalMassChange;
99                 for (double dm : deltam) {
100                         total -= dm * scale;
101                         mass.add(total);
102                 }
103                 
104                 return mass;
105         }
106         
107         
108         /**
109          * Helper method to remove a delay (or plugged) from the end of a motor designation,
110          * if present.
111          * 
112          * @param designation   the motor designation.
113          * @return                              the designation with a possible delay removed.
114          */
115         protected static String removeDelay(String designation) {
116                 if (designation.matches(".*-([0-9]+|[pP])$")) {
117                         designation = designation.substring(0, designation.lastIndexOf('-'));
118                 }
119                 return designation;
120         }
121         
122         
123
124         /**
125          * Helper method to tokenize a string using whitespace as the delimiter.
126          */
127         protected static String[] split(String str) {
128                 return split(str, "\\s+");
129         }
130         
131         
132         /**
133          * Helper method to tokenize a string using the given delimiter.
134          */
135         protected static String[] split(String str, String delim) {
136                 String[] pieces = str.split(delim);
137                 if (pieces.length == 0 || !pieces[0].equals(""))
138                         return pieces;
139                 return ArrayUtils.copyOfRange(pieces, 1, pieces.length);
140         }
141         
142         
143         /**
144          * Sort the primary list and other lists in that order.
145          * 
146          * @param primary       the list to order.
147          * @param lists         lists to order in the same permutation.
148          */
149         protected static void sortLists(List<Double> primary, List<?>... lists) {
150                 
151                 // TODO: LOW: Very idiotic sort algorithm, but should be fast enough
152                 // since the time should be sorted already
153                 
154                 int index;
155                 
156                 do {
157                         for (index = 0; index < primary.size() - 1; index++) {
158                                 if (primary.get(index + 1) < primary.get(index)) {
159                                         Collections.swap(primary, index, index + 1);
160                                         for (List<?> l : lists) {
161                                                 Collections.swap(l, index, index + 1);
162                                         }
163                                         break;
164                                 }
165                         }
166                 } while (index < primary.size() - 1);
167         }
168         
169         
170
171         @SuppressWarnings("unchecked")
172         protected static void finalizeThrustCurve(List<Double> time, List<Double> thrust,
173                         List... lists) {
174                 
175                 if (time.size() == 0)
176                         return;
177                 
178                 // Start
179                 if (!MathUtil.equals(time.get(0), 0) || !MathUtil.equals(thrust.get(0), 0)) {
180                         time.add(0, 0.0);
181                         thrust.add(0, 0.0);
182                         for (List l : lists) {
183                                 Object o = l.get(0);
184                                 l.add(0, o);
185                         }
186                 }
187                 
188                 // End
189                 int n = time.size() - 1;
190                 if (!MathUtil.equals(thrust.get(n), 0)) {
191                         time.add(time.get(n));
192                         thrust.add(0.0);
193                         for (List l : lists) {
194                                 Object o = l.get(n);
195                                 l.add(o);
196                         }
197                 }
198         }
199         
200 }