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