create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / file / motor / RASPMotorLoader.java
1 package net.sf.openrocket.file.motor;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.Reader;
6 import java.nio.charset.Charset;
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.List;
10
11 import net.sf.openrocket.motor.Manufacturer;
12 import net.sf.openrocket.motor.Motor;
13 import net.sf.openrocket.motor.MotorDigest;
14 import net.sf.openrocket.motor.MotorDigest.DataType;
15 import net.sf.openrocket.motor.ThrustCurveMotor;
16 import net.sf.openrocket.util.Coordinate;
17
18 public class RASPMotorLoader extends AbstractMotorLoader {
19         
20         public static final String CHARSET_NAME = "ISO-8859-1";
21         
22         public static final Charset CHARSET = Charset.forName(CHARSET_NAME);
23         
24         
25         
26         
27         @Override
28         protected Charset getDefaultCharset() {
29                 return CHARSET;
30         }
31         
32         
33         /**
34          * Load a <code>Motor</code> from a RASP file specified by the <code>Reader</code>.
35          * The <code>Reader</code> is responsible for using the correct charset.
36          * <p>
37          * The CG is assumed to be located at the center of the motor casing and the mass
38          * is calculated from the thrust curve by assuming a constant exhaust velocity.
39          * 
40          * @param reader  the source of the file.
41          * @return                a list of the {@link Motor} objects defined in the file.
42          * @throws IOException  if an I/O error occurs or if the file format is illegal.
43          */
44         @Override
45         public List<Motor> load(Reader reader, String filename) throws IOException {
46                 List<Motor> motors = new ArrayList<Motor>();
47                 BufferedReader in = new BufferedReader(reader);
48                 
49                 String manufacturer = "";
50                 String designation = "";
51                 String comment = "";
52                 
53                 double length = 0;
54                 double diameter = 0;
55                 ArrayList<Double> delays = null;
56                 
57                 List<Double> time = new ArrayList<Double>();
58                 List<Double> thrust = new ArrayList<Double>();
59                 
60                 double propW = 0;
61                 double totalW = 0;
62                 
63                 try {
64                         String line;
65                         String[] pieces, buf;
66                         
67                         line = in.readLine();
68                         main: while (line != null) { // Until EOF
69                         
70                                 manufacturer = "";
71                                 designation = "";
72                                 comment = "";
73                                 length = 0;
74                                 diameter = 0;
75                                 delays = new ArrayList<Double>();
76                                 propW = 0;
77                                 totalW = 0;
78                                 time.clear();
79                                 thrust.clear();
80                                 
81                                 // Read comment
82                                 while (line.length() == 0 || line.charAt(0) == ';') {
83                                         if (line.length() > 0) {
84                                                 comment += line.substring(1).trim() + "\n";
85                                         }
86                                         line = in.readLine();
87                                         if (line == null)
88                                                 break main;
89                                 }
90                                 comment = comment.trim();
91                                 
92                                 // Parse header line, example:
93                                 // F32 24 124 5-10-15-P .0377 .0695 RV
94                                 // desig diam len delays prop.w tot.w manufacturer
95                                 pieces = split(line);
96                                 if (pieces.length != 7) {
97                                         throw new IOException("Illegal file format.");
98                                 }
99                                 
100                                 designation = pieces[0];
101                                 diameter = Double.parseDouble(pieces[1]) / 1000.0;
102                                 length = Double.parseDouble(pieces[2]) / 1000.0;
103                                 
104                                 if (pieces[3].equalsIgnoreCase("None")) {
105                                         
106                                 } else {
107                                         buf = split(pieces[3], "[-,]+");
108                                         for (int i = 0; i < buf.length; i++) {
109                                                 if (buf[i].equalsIgnoreCase("P") ||
110                                                                 buf[i].equalsIgnoreCase("plugged")) {
111                                                         delays.add(Motor.PLUGGED);
112                                                 } else {
113                                                         // Many RASP files have "100" as an only delay
114                                                         double d = Double.parseDouble(buf[i]);
115                                                         if (d < 99)
116                                                                 delays.add(d);
117                                                 }
118                                         }
119                                         Collections.sort(delays);
120                                 }
121                                 
122                                 propW = Double.parseDouble(pieces[4]);
123                                 totalW = Double.parseDouble(pieces[5]);
124                                 manufacturer = pieces[6];
125                                 
126                                 if (propW > totalW) {
127                                         throw new IOException("Propellant weight exceeds total weight in " +
128                                                         "RASP file " + filename);
129                                 }
130                                 
131                                 // Read the data
132                                 for (line = in.readLine(); (line != null) && (line.length() == 0 || line.charAt(0) != ';'); line = in.readLine()) {
133                                         
134                                         buf = split(line);
135                                         if (buf.length == 0) {
136                                                 continue;
137                                         } else if (buf.length == 2) {
138                                                 
139                                                 time.add(Double.parseDouble(buf[0]));
140                                                 thrust.add(Double.parseDouble(buf[1]));
141                                                 
142                                         } else {
143                                                 throw new IOException("Illegal file format.");
144                                         }
145                                 }
146                                 
147                                 // Comment of EOF encountered, marks the start of the next motor
148                                 if (time.size() < 2) {
149                                         throw new IOException("Illegal file format, too short thrust-curve.");
150                                 }
151                                 double[] delayArray = new double[delays.size()];
152                                 for (int i = 0; i < delays.size(); i++) {
153                                         delayArray[i] = delays.get(i);
154                                 }
155                                 motors.add(createRASPMotor(manufacturer, designation, comment,
156                                                 length, diameter, delayArray, propW, totalW, time, thrust));
157                         }
158                         
159                 } catch (NumberFormatException e) {
160                         
161                         throw new IOException("Illegal file format.");
162                         
163                 }
164                 
165                 return motors;
166         }
167         
168         
169         /**
170          * Create a motor from RASP file data.
171          * @throws IOException  if the data is illegal for a thrust curve
172          */
173         private static Motor createRASPMotor(String manufacturer, String designation,
174                         String comment, double length, double diameter, double[] delays,
175                         double propW, double totalW, List<Double> time, List<Double> thrust)
176                         throws IOException {
177                 
178                 // Add zero time/thrust if necessary
179                 sortLists(time, thrust);
180                 finalizeThrustCurve(time, thrust);
181                 List<Double> mass = calculateMass(time, thrust, totalW, propW);
182                 
183                 double[] timeArray = new double[time.size()];
184                 double[] thrustArray = new double[time.size()];
185                 Coordinate[] cgArray = new Coordinate[time.size()];
186                 for (int i = 0; i < time.size(); i++) {
187                         timeArray[i] = time.get(i);
188                         thrustArray[i] = thrust.get(i);
189                         cgArray[i] = new Coordinate(length / 2, 0, 0, mass.get(i));
190                 }
191                 
192                 designation = removeDelay(designation);
193                 
194                 // Create the motor digest from data available in RASP files
195                 MotorDigest motorDigest = new MotorDigest();
196                 motorDigest.update(DataType.TIME_ARRAY, timeArray);
197                 motorDigest.update(DataType.MASS_SPECIFIC, totalW, totalW - propW);
198                 motorDigest.update(DataType.FORCE_PER_TIME, thrustArray);
199                 final String digest = motorDigest.getDigest();
200                 
201                 try {
202                         
203                         Manufacturer m = Manufacturer.getManufacturer(manufacturer);
204                         return new ThrustCurveMotor(m, designation, comment, m.getMotorType(),
205                                         delays, diameter, length, timeArray, thrustArray, cgArray, digest);
206                         
207                 } catch (IllegalArgumentException e) {
208                         
209                         // Bad data read from file.
210                         throw new IOException("Illegal file format.", e);
211                         
212                 }
213         }
214 }