package net.sf.openrocket.file.motor; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.List; import net.sf.openrocket.motor.Manufacturer; import net.sf.openrocket.motor.Motor; import net.sf.openrocket.motor.MotorDigest; import net.sf.openrocket.motor.MotorDigest.DataType; import net.sf.openrocket.motor.ThrustCurveMotor; import net.sf.openrocket.util.Coordinate; public class RASPMotorLoader extends AbstractMotorLoader { public static final String CHARSET_NAME = "ISO-8859-1"; public static final Charset CHARSET = Charset.forName(CHARSET_NAME); @Override protected Charset getDefaultCharset() { return CHARSET; } /** * Load a <code>Motor</code> from a RASP file specified by the <code>Reader</code>. * The <code>Reader</code> is responsible for using the correct charset. * <p> * The CG is assumed to be located at the center of the motor casing and the mass * is calculated from the thrust curve by assuming a constant exhaust velocity. * * @param reader the source of the file. * @return a list of the {@link Motor} objects defined in the file. * @throws IOException if an I/O error occurs or if the file format is illegal. */ @Override public List<Motor> load(Reader reader, String filename) throws IOException { List<Motor> motors = new ArrayList<Motor>(); BufferedReader in = new BufferedReader(reader); String manufacturer = ""; String designation = ""; String comment = ""; double length = 0; double diameter = 0; ArrayList<Double> delays = null; List<Double> time = new ArrayList<Double>(); List<Double> thrust = new ArrayList<Double>(); double propW = 0; double totalW = 0; try { String line; String[] pieces, buf; line = in.readLine(); main: while (line != null) { // Until EOF manufacturer = ""; designation = ""; comment = ""; length = 0; diameter = 0; delays = new ArrayList<Double>(); propW = 0; totalW = 0; time.clear(); thrust.clear(); // Read comment while (line.length() == 0 || line.charAt(0) == ';') { if (line.length() > 0) { comment += line.substring(1).trim() + "\n"; } line = in.readLine(); if (line == null) break main; } comment = comment.trim(); // Parse header line, example: // F32 24 124 5-10-15-P .0377 .0695 RV // desig diam len delays prop.w tot.w manufacturer pieces = split(line); if (pieces.length != 7) { throw new IOException("Illegal file format."); } designation = pieces[0]; diameter = Double.parseDouble(pieces[1]) / 1000.0; length = Double.parseDouble(pieces[2]) / 1000.0; if (pieces[3].equalsIgnoreCase("None")) { } else { buf = split(pieces[3], "[-,]+"); for (int i = 0; i < buf.length; i++) { if (buf[i].equalsIgnoreCase("P") || buf[i].equalsIgnoreCase("plugged")) { delays.add(Motor.PLUGGED); } else if (buf[i].matches("[0-9]+")) { // Many RASP files have "100" as an only delay double d = Double.parseDouble(buf[i]); if (d < 99) delays.add(d); } } Collections.sort(delays); } propW = Double.parseDouble(pieces[4]); totalW = Double.parseDouble(pieces[5]); manufacturer = pieces[6]; if (propW > totalW) { throw new IOException("Propellant weight exceeds total weight in " + "RASP file " + filename); } // Read the data for (line = in.readLine(); (line != null) && (line.length() == 0 || line.charAt(0) != ';'); line = in.readLine()) { buf = split(line); if (buf.length == 0) { continue; } else if (buf.length == 2) { time.add(Double.parseDouble(buf[0])); thrust.add(Double.parseDouble(buf[1])); } else { throw new IOException("Illegal file format."); } } // Comment of EOF encountered, marks the start of the next motor if (time.size() < 2) { throw new IOException("Illegal file format, too short thrust-curve."); } double[] delayArray = new double[delays.size()]; for (int i = 0; i < delays.size(); i++) { delayArray[i] = delays.get(i); } motors.add(createRASPMotor(manufacturer, designation, comment, length, diameter, delayArray, propW, totalW, time, thrust)); } } catch (NumberFormatException e) { throw new IOException("Illegal file format."); } return motors; } /** * Create a motor from RASP file data. * @throws IOException if the data is illegal for a thrust curve */ private static Motor createRASPMotor(String manufacturer, String designation, String comment, double length, double diameter, double[] delays, double propW, double totalW, List<Double> time, List<Double> thrust) throws IOException { // Add zero time/thrust if necessary sortLists(time, thrust); finalizeThrustCurve(time, thrust); List<Double> mass = calculateMass(time, thrust, totalW, propW); double[] timeArray = new double[time.size()]; double[] thrustArray = new double[time.size()]; Coordinate[] cgArray = new Coordinate[time.size()]; for (int i = 0; i < time.size(); i++) { timeArray[i] = time.get(i); thrustArray[i] = thrust.get(i); cgArray[i] = new Coordinate(length / 2, 0, 0, mass.get(i)); } designation = removeDelay(designation); // Create the motor digest from data available in RASP files MotorDigest motorDigest = new MotorDigest(); motorDigest.update(DataType.TIME_ARRAY, timeArray); motorDigest.update(DataType.MASS_SPECIFIC, totalW, totalW - propW); motorDigest.update(DataType.FORCE_PER_TIME, thrustArray); final String digest = motorDigest.getDigest(); try { Manufacturer m = Manufacturer.getManufacturer(manufacturer); return new ThrustCurveMotor(m, designation, comment, m.getMotorType(), delays, diameter, length, timeArray, thrustArray, cgArray, digest); } catch (IllegalArgumentException e) { // Bad data read from file. throw new IOException("Illegal file format.", e); } } }