From 17540d160c7346571c2b737a971118dc3bbe8047 Mon Sep 17 00:00:00 2001 From: Kevin Ruland Date: Mon, 7 Dec 2015 22:29:51 -0600 Subject: [PATCH] Oops forgot the webservice. --- .../openrocket/thrustcurve/Base64Decoder.java | 122 +++++++ .../thrustcurve/DownloadRequest.java | 43 +++ .../thrustcurve/DownloadResponse.java | 41 +++ .../thrustcurve/DownloadResponseParser.java | 75 +++++ .../openrocket/thrustcurve/MotorBurnFile.java | 84 +++++ .../openrocket/thrustcurve/SearchRequest.java | 117 +++++++ .../thrustcurve/SearchResponse.java | 45 +++ .../thrustcurve/SearchResponseParser.java | 180 +++++++++++ .../SerializeThrustcurveMotors.java | 195 ++++++++++++ .../thrustcurve/SupportedFileTypes.java | 11 + .../sf/openrocket/thrustcurve/TCMotor.java | 298 ++++++++++++++++++ .../thrustcurve/ThrustCurveAPI.java | 83 +++++ 12 files changed, 1294 insertions(+) create mode 100644 core/src/net/sf/openrocket/thrustcurve/Base64Decoder.java create mode 100644 core/src/net/sf/openrocket/thrustcurve/DownloadRequest.java create mode 100644 core/src/net/sf/openrocket/thrustcurve/DownloadResponse.java create mode 100644 core/src/net/sf/openrocket/thrustcurve/DownloadResponseParser.java create mode 100644 core/src/net/sf/openrocket/thrustcurve/MotorBurnFile.java create mode 100644 core/src/net/sf/openrocket/thrustcurve/SearchRequest.java create mode 100644 core/src/net/sf/openrocket/thrustcurve/SearchResponse.java create mode 100644 core/src/net/sf/openrocket/thrustcurve/SearchResponseParser.java create mode 100644 core/src/net/sf/openrocket/thrustcurve/SerializeThrustcurveMotors.java create mode 100644 core/src/net/sf/openrocket/thrustcurve/SupportedFileTypes.java create mode 100644 core/src/net/sf/openrocket/thrustcurve/TCMotor.java create mode 100644 core/src/net/sf/openrocket/thrustcurve/ThrustCurveAPI.java diff --git a/core/src/net/sf/openrocket/thrustcurve/Base64Decoder.java b/core/src/net/sf/openrocket/thrustcurve/Base64Decoder.java new file mode 100644 index 000000000..dea1b3348 --- /dev/null +++ b/core/src/net/sf/openrocket/thrustcurve/Base64Decoder.java @@ -0,0 +1,122 @@ +package net.sf.openrocket.thrustcurve; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; + +public abstract class Base64Decoder { + + private static final String BASE64_CHARS = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + private static final char PAD_CHAR = '='; + + private final static short[] _charToBits = new short[128]; + + static { + + for (int i = 0; i < _charToBits.length; i++) + _charToBits[i] = -1; + + for (int i = 0; i < BASE64_CHARS.length(); i++) + _charToBits[BASE64_CHARS.charAt(i)] = (byte) i; + _charToBits[PAD_CHAR] = 0; + + } + + /** + * Decode the specified Base64 string and write binary data + * to the given stream. + * @param str Base64 encoded string + * @param w output stream + */ + public static String decodeData(String str) throws IOException + { + StringReader r; + int c1; + + if (str == null || str.length() < 1) + return null; + + r = new StringReader(str); + + StringWriter w = new StringWriter(); + + // spin through the input string + c1 = readToNonSpace(r); + while (c1 > 0) + { + int c2, c3, c4; + int p1, p2, p3, p4; + int pad, n; + + pad = 0; + + c2 = readToNonSpace(r); + c3 = readToNonSpace(r); + c4 = readToNonSpace(r); + if (c4 < 0) + throw new IllegalArgumentException("Encoded string ends prematurely."); + + p1 = charToBits(c1); + p2 = charToBits(c2); + + if (c3 == PAD_CHAR) + { + p3 = 0; + pad++; + } + else + p3 = charToBits(c3); + + if (c4 == PAD_CHAR) + { + p4 = 0; + pad++; + } + else + p4 = charToBits(c4); + + if (p1 < 0 || p2 < 0 || p3 < 0 || p4 < 0) + throw new IllegalArgumentException("Encoded string contains invalid characters."); + + n = (p1 << 18) | (p2 << 12) | (p3 << 6) | p4; + + w.write((byte) ((n & 0xFF0000) >> 16)); + if (pad < 2) + w.write((byte) ((n & 0x00FF00) >> 8)); + if (pad < 1) + w.write((byte) (n & 0x0000FF)); + + c1 = readToNonSpace(r); + if (c1 > 0 && pad > 0) + throw new IllegalArgumentException("Extra characters found after padding."); + } + + return w.toString(); + } + + + private static int readToNonSpace(Reader r) + throws IOException + { + int c; + + c = r.read(); + while (c >= 0 && Character.isWhitespace(c)) + c = r.read(); + + return c; + } + + private static int charToBits(int c) + { + // use it to look up the value + if (c < 0 || c >= _charToBits.length) + return -1; + else + return _charToBits[c]; + } + + +} diff --git a/core/src/net/sf/openrocket/thrustcurve/DownloadRequest.java b/core/src/net/sf/openrocket/thrustcurve/DownloadRequest.java new file mode 100644 index 000000000..d49d7d4a5 --- /dev/null +++ b/core/src/net/sf/openrocket/thrustcurve/DownloadRequest.java @@ -0,0 +1,43 @@ +package net.sf.openrocket.thrustcurve; + +import java.util.ArrayList; + +class DownloadRequest { + + private ArrayList motorIds = new ArrayList(); + + private String format = null; + + public void add(Integer motorId) { + this.motorIds.add(motorId); + } + + public void setFormat(String format) { + this.format = format; + } + + @Override + public String toString() { + StringBuilder w = new StringBuilder(); + + w.append("\n"); + w.append("\n"); + + if (format != null) { + w.append(" ").append(format).append("\n"); + } + + w.append(" \n"); + for (Integer i : motorIds) { + w.append(" ").append(i).append("\n"); + } + w.append(" \n"); + w.append("\n"); + return w.toString(); + } + + +} diff --git a/core/src/net/sf/openrocket/thrustcurve/DownloadResponse.java b/core/src/net/sf/openrocket/thrustcurve/DownloadResponse.java new file mode 100644 index 000000000..c7a49239e --- /dev/null +++ b/core/src/net/sf/openrocket/thrustcurve/DownloadResponse.java @@ -0,0 +1,41 @@ +package net.sf.openrocket.thrustcurve; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +public class DownloadResponse { + + private Map> data = new HashMap>(); + + private String error = null; + + public void add( MotorBurnFile mbd ) { + List currentData = data.get(mbd.getMotorId()); + if ( currentData == null ) { + currentData = new ArrayList(); + data.put(mbd.getMotorId(), currentData); + } + currentData.add(mbd); + } + + public List getData(Integer motor_id) { + return data.get(motor_id); + } + + public void setError(String error) { + this.error = error; + } + + public String getError() { + return error; + } + + @Override + public String toString() { + return "DownloadResponse [error=" + error + ", data=" + data + "]"; + } + +} diff --git a/core/src/net/sf/openrocket/thrustcurve/DownloadResponseParser.java b/core/src/net/sf/openrocket/thrustcurve/DownloadResponseParser.java new file mode 100644 index 000000000..3941afad2 --- /dev/null +++ b/core/src/net/sf/openrocket/thrustcurve/DownloadResponseParser.java @@ -0,0 +1,75 @@ +package net.sf.openrocket.thrustcurve; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; + +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.file.simplesax.ElementHandler; +import net.sf.openrocket.file.simplesax.SimpleSAX; + +public class DownloadResponseParser implements ElementHandler { + + private static final String thrustcurveURI = "http://www.thrustcurve.org/2009/DownloadResponse"; + + private static final String root_tag = "download-response"; + private static final String results_tag = "results"; + private static final String result_tag = "result"; + private static final String motor_id_tag = "motor-id"; + private static final String simfile_id_tag = "simfile-id"; + private static final String format_tag = "format"; + private static final String source_tag = "source"; + private static final String license_tag = "license"; + private static final String data_tag = "data"; + private static final String error_tag = "error"; + + private DownloadResponse response = new DownloadResponse(); + + private MotorBurnFile motorBurnFile; + + private DownloadResponseParser() { + }; + + public static DownloadResponse parse(InputStream in) throws IOException, SAXException { + + DownloadResponseParser handler = new DownloadResponseParser(); + WarningSet warnings = new WarningSet(); + SimpleSAX.readXML(new InputSource(in), handler, warnings); + + return handler.response; + + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) throws SAXException { + if (result_tag.equals(element)) { + motorBurnFile = new MotorBurnFile(); + } + return this; + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { + if (result_tag.equals(element)) { + response.add(motorBurnFile); + } else if (motor_id_tag.equals(element)) { + motorBurnFile.setMotorId(Integer.parseInt(content)); + } else if (format_tag.equals(element)) { + motorBurnFile.setFiletype(content); + } else if (data_tag.equals(element)) { + try { + motorBurnFile.decodeFile(content); + } catch (IOException e) { + throw new SAXException(e); + } + } + } + + @Override + public void endHandler(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { + } + +} \ No newline at end of file diff --git a/core/src/net/sf/openrocket/thrustcurve/MotorBurnFile.java b/core/src/net/sf/openrocket/thrustcurve/MotorBurnFile.java new file mode 100644 index 000000000..b20afe939 --- /dev/null +++ b/core/src/net/sf/openrocket/thrustcurve/MotorBurnFile.java @@ -0,0 +1,84 @@ +package net.sf.openrocket.thrustcurve; + +import java.io.IOException; +import java.io.StringReader; +import java.util.List; + +import net.sf.openrocket.file.motor.RASPMotorLoader; +import net.sf.openrocket.file.motor.RockSimMotorLoader; +import net.sf.openrocket.motor.ThrustCurveMotor; + +public class MotorBurnFile { + + private Integer motorId; + private String filetype; + private ThrustCurveMotor.Builder thrustCurveMotor; + + public void init() { + this.motorId = null; + this.filetype = null; + this.thrustCurveMotor = null; + } + + @Override + public MotorBurnFile clone() { + MotorBurnFile clone = new MotorBurnFile(); + clone.motorId = this.motorId; + clone.filetype = this.filetype; + clone.thrustCurveMotor = this.thrustCurveMotor; + return clone; + } + + public void decodeFile(String data) throws IOException { + data = Base64Decoder.decodeData(data); + try { + if (SupportedFileTypes.RASP_FORMAT.equals(filetype)) { + RASPMotorLoader loader = new RASPMotorLoader(); + List motors = loader.load(new StringReader(data), "download"); + this.thrustCurveMotor = motors.get(0); + } else if (SupportedFileTypes.ROCKSIM_FORMAT.equals(filetype)) { + RockSimMotorLoader loader = new RockSimMotorLoader(); + List motors = loader.load(new StringReader(data), "download"); + this.thrustCurveMotor = motors.get(0); + } + } catch (IOException ex) { + this.thrustCurveMotor = null; + } + } + + /** + * @return the motor_id + */ + public Integer getMotorId() { + return motorId; + } + + /** + * @param motor_id the motor_id to set + */ + public void setMotorId(Integer motorId) { + this.motorId = motorId; + } + + /** + * @return the filetype + */ + public String getFiletype() { + return filetype; + } + + /** + * @param filetype the filetype to set + */ + public void setFiletype(String filetype) { + this.filetype = filetype; + } + + /** + * @return the thrustCurveMotor + */ + public ThrustCurveMotor.Builder getThrustCurveMotor() { + return thrustCurveMotor; + } + +} diff --git a/core/src/net/sf/openrocket/thrustcurve/SearchRequest.java b/core/src/net/sf/openrocket/thrustcurve/SearchRequest.java new file mode 100644 index 000000000..a39cf4da0 --- /dev/null +++ b/core/src/net/sf/openrocket/thrustcurve/SearchRequest.java @@ -0,0 +1,117 @@ +package net.sf.openrocket.thrustcurve; + +public class SearchRequest { + + private String manufacturer; + private String designation; + private String brand_name; + + private String common_name; + private String impulse_class; + private Integer diameter; + + /* + public enum Type { + "SU"; + "reload"; + "hybrid" + }; + */ + private String type; + + public void setManufacturer(String manufacturer) { + this.manufacturer = null; + if (manufacturer != null) { + manufacturer = manufacturer.trim(); + if (!"".equals(manufacturer)) { + this.manufacturer = manufacturer; + } + } + } + + public void setDesignation(String designation) { + this.designation = designation; + } + + public void setBrand_name(String brand_name) { + this.brand_name = brand_name; + } + + public void setCommon_name(String common_name) { + if (common_name == null) { + this.common_name = null; + return; + } + this.common_name = common_name.trim(); + if ("".equals(this.common_name)) { + this.common_name = null; + } + } + + public void setImpulse_class(String impulse_class) { + this.impulse_class = null; + if (impulse_class != null) { + this.impulse_class = impulse_class.trim(); + if ("".equals(impulse_class)) { + this.impulse_class = null; + } + } + } + + public void setDiameter(Integer diameter) { + this.diameter = diameter; + } + + public void setDiameter(String diameter) { + this.diameter = null; + if (diameter == null) { + return; + } + try { + this.diameter = Integer.decode(diameter); + } catch (NumberFormatException ex) { + this.diameter = null; + } + } + + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + StringBuilder w = new StringBuilder(); + + w.append("\n"); + w.append("\n"); + + if (manufacturer != null) { + w.append(" ").append(manufacturer).append("\n"); + } + if (designation != null) { + w.append(" ").append(designation).append("\n"); + } + if (brand_name != null) { + w.append(" ").append(brand_name).append("\n"); + } + if (common_name != null) { + w.append(" ").append(common_name).append("\n"); + } + if (impulse_class != null) { + w.append(" ").append(impulse_class).append("\n"); + } + if (diameter != null) { + w.append(" ").append(diameter).append("\n"); + } + if (type != null) { + w.append(" ").append(type).append("\n"); + } + w.append("*"); + w.append("0"); + w.append("\n"); + return w.toString(); + } +} diff --git a/core/src/net/sf/openrocket/thrustcurve/SearchResponse.java b/core/src/net/sf/openrocket/thrustcurve/SearchResponse.java new file mode 100644 index 000000000..a15d06feb --- /dev/null +++ b/core/src/net/sf/openrocket/thrustcurve/SearchResponse.java @@ -0,0 +1,45 @@ +package net.sf.openrocket.thrustcurve; + +import java.util.ArrayList; +import java.util.List; + + +public class SearchResponse { + + private List results = new ArrayList(); + + private int matches; + + private String error; + + public List getResults() { + return results; + } + + void addMotor(TCMotor motor) { + results.add(motor); + } + + public int getMatches() { + return matches; + } + + public void setMatches(int matches) { + this.matches = matches; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + @Override + public String toString() { + return "SearchResult [results=" + results + ", matches=" + matches + + ", error=" + error + "]"; + } + +} diff --git a/core/src/net/sf/openrocket/thrustcurve/SearchResponseParser.java b/core/src/net/sf/openrocket/thrustcurve/SearchResponseParser.java new file mode 100644 index 000000000..9d589cebe --- /dev/null +++ b/core/src/net/sf/openrocket/thrustcurve/SearchResponseParser.java @@ -0,0 +1,180 @@ +package net.sf.openrocket.thrustcurve; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; + +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.file.simplesax.ElementHandler; +import net.sf.openrocket.file.simplesax.SimpleSAX; + +public class SearchResponseParser implements ElementHandler { + + private static final String thrustcurveURI = "http://www.thrustcurve.org/2008/SearchResponse"; + /* + * XML Tags in SearchResult xsd + */ + private static final String root_tag = "search-response"; + private static final String criteria = "criteria"; + private static final String criterion = "criterion"; + private static final String name = "name"; + private static final String value = "value"; + private static final String matches = "matches"; + private static final String results = "results"; + private static final String result = "result"; + + private static final String motor_id = "motor-id"; + private static final String manufacturer = "manufacturer"; + private static final String manufacturer_abbr = "manufacturer-abbrev"; + private static final String designation = "designation"; + private static final String brand_name = "brand-name"; + private static final String common_name = "common-name"; + private static final String impulse_class = "impulse-class"; + private static final String diameter = "diameter"; + private static final String length = "length"; + private static final String type = "type"; + private static final String cert_org = "cert-org"; + private static final String avg_thrust_n = "avg-thrust-n"; + private static final String max_thrust_n = "max-thrust-n"; + private static final String tot_impulse_ns = "tot-impulse-ns"; + private static final String burn_time_s = "burn-time-s"; + private static final String data_files = "data-files"; + private static final String info_url = "info-url"; + private static final String total_weight_g = "total-weight-g"; + private static final String prop_weight_g = "prop-weight-g"; + private static final String delays = "delays"; + private static final String case_info = "case-info"; + private static final String prop_info = "prop-info"; + private static final String updated_on = "updated-on"; + private static final String availability = "availability"; + + private SearchResponse response = new SearchResponse(); + + private TCMotor currentMotor; + + private SearchResponseParser() { + } + + public static SearchResponse parse(InputStream in) throws IOException, SAXException { + + SearchResponseParser handler = new SearchResponseParser(); + WarningSet warnings = new WarningSet(); + SimpleSAX.readXML(new InputSource(in), handler, warnings); + + return handler.response; + + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) throws SAXException { + if (result.equals(element)) { + currentMotor = new TCMotor(); + } + return this; + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { + + switch (element) { + case result: + // Convert impulse class. ThrustCurve puts mmx, 1/4a and 1/2a as A. + if ("a".equalsIgnoreCase(currentMotor.getImpulse_class())) { + if (currentMotor.getCommon_name().startsWith("1/2A")) { + currentMotor.setImpulse_class("1/2A"); + } else if (currentMotor.getCommon_name().startsWith("1/4A")) { + currentMotor.setImpulse_class("1/4A"); + } else if (currentMotor.getCommon_name().startsWith("Micro")) { + currentMotor.setImpulse_class("1/8A"); + } + } + + // Convert Case Info. + if (currentMotor.getCase_info() == null + || "single use".equalsIgnoreCase(currentMotor.getCase_info()) + || "single-use".equalsIgnoreCase(currentMotor.getCase_info())) { + currentMotor.setCase_info(currentMotor.getType() + " " + currentMotor.getDiameter() + "x" + currentMotor.getLength()); + } + response.addMotor(currentMotor); + break; + case motor_id: + currentMotor.setMotor_id(Integer.parseInt(content)); + break; + case manufacturer: + currentMotor.setManufacturer(content); + break; + case manufacturer_abbr: + currentMotor.setManufacturer_abbr(content); + break; + case designation: + currentMotor.setDesignation(content); + break; + case brand_name: + currentMotor.setBrand_name(content); + break; + case common_name: + currentMotor.setCommon_name(content); + break; + case impulse_class: + currentMotor.setImpulse_class(content); + break; + case diameter: + currentMotor.setDiameter(Float.parseFloat(content)); + break; + case length: + currentMotor.setLength(Float.parseFloat(content)); + break; + case type: + currentMotor.setType(content); + break; + case cert_org: + currentMotor.setCert_org(content); + break; + case avg_thrust_n: + currentMotor.setAvg_thrust_n(Float.parseFloat(content)); + break; + case max_thrust_n: + currentMotor.setMax_thrust_n(Float.parseFloat(content)); + break; + case tot_impulse_ns: + currentMotor.setTot_impulse_ns(Float.parseFloat(content)); + break; + case burn_time_s: + currentMotor.setBurn_time_s(Float.parseFloat(content)); + break; + case data_files: + currentMotor.setData_files(Integer.parseInt(content)); + break; + case info_url: + currentMotor.setInfo_url(content); + break; + case total_weight_g: + currentMotor.setTot_mass_g(Double.parseDouble(content)); + break; + case prop_weight_g: + currentMotor.setProp_mass_g(Double.parseDouble(content)); + break; + case delays: + currentMotor.setDelays(content); + break; + case case_info: + currentMotor.setCase_info(content); + break; + case prop_info: + currentMotor.setProp_info(content); + break; + case availability: + currentMotor.setAvailability(content); + break; + } + + } + + @Override + public void endHandler(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { + } + +} diff --git a/core/src/net/sf/openrocket/thrustcurve/SerializeThrustcurveMotors.java b/core/src/net/sf/openrocket/thrustcurve/SerializeThrustcurveMotors.java new file mode 100644 index 000000000..94dedc08b --- /dev/null +++ b/core/src/net/sf/openrocket/thrustcurve/SerializeThrustcurveMotors.java @@ -0,0 +1,195 @@ +package net.sf.openrocket.thrustcurve; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectOutputStream; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.List; + +import org.xml.sax.SAXException; + +import net.sf.openrocket.file.iterator.DirectoryIterator; +import net.sf.openrocket.file.iterator.FileIterator; +import net.sf.openrocket.file.motor.GeneralMotorLoader; +import net.sf.openrocket.gui.util.SimpleFileFilter; +import net.sf.openrocket.motor.Motor; +import net.sf.openrocket.motor.ThrustCurveMotor; +import net.sf.openrocket.motor.ThrustCurveMotor.Builder; +import net.sf.openrocket.util.Pair; + +public class SerializeThrustcurveMotors { + + private static String[] manufacturers = { + "AeroTech", + "Alpha", + "AMW", + "Apogee", + "Cesaroni", + "Contrail", + "Ellis", + "Estes", + "GR", + "Hypertek", + "KBA", + "Kosdon", + "Loki", + "PP", + "PML", + "Quest", + "RATT", + "Roadrunner", + "RV", + "SkyR", + "SCR", + "WCH" + }; + + public static void main(String[] args) throws Exception { + + if (args.length != 2) { + System.out.println("Usage: java " + SerializeThrustcurveMotors.class.getCanonicalName() + " "); + System.exit(1); + } + + String inputDir = args[0]; + String outputFile = args[1]; + + final List allMotors = new ArrayList(); + + loadFromLocalMotorFiles(allMotors, inputDir); + + loadFromThrustCurve(allMotors); + + File outFile = new File(outputFile); + + FileOutputStream ofs = new FileOutputStream(outFile); + final ObjectOutputStream oos = new ObjectOutputStream(ofs); + + oos.writeObject(allMotors); + + oos.flush(); + ofs.flush(); + ofs.close(); + + } + + public static void loadFromThrustCurve(List allMotors) throws SAXException, MalformedURLException, IOException { + + SearchRequest searchRequest = new SearchRequest(); + for (String m : manufacturers) { + searchRequest.setManufacturer(m); + System.out.println("Motors for : " + m); + + SearchResponse res = ThrustCurveAPI.doSearch(searchRequest); + + for (TCMotor mi : res.getResults()) { + StringBuilder message = new StringBuilder(); + message.append(mi.getManufacturer_abbr()); + message.append(" "); + message.append(mi.getCommon_name()); + message.append(" "); + message.append(mi.getMotor_id()); + + if (mi.getData_files() == null || mi.getData_files().intValue() == 0) { + continue; + } + + final Motor.Type type; + switch (mi.getType()) { + case "SU": + type = Motor.Type.SINGLE; + break; + case "reload": + type = Motor.Type.RELOAD; + break; + case "hybrid": + type = Motor.Type.HYBRID; + break; + default: + type = Motor.Type.UNKNOWN; + break; + } + + System.out.println(message); + + List b = getThrustCurvesForMotorId(mi.getMotor_id()); + + for (MotorBurnFile burnFile : b) { + + ThrustCurveMotor.Builder builder = burnFile.getThrustCurveMotor(); + if (builder == null) { + continue; + } + if (mi.getTot_mass_g() != null) { + builder.setInitialMass(mi.getTot_mass_g() / 1000.0); + } + if (mi.getProp_mass_g() != null) { + builder.setPropellantMass(mi.getProp_mass_g() / 1000.0); + } + + builder.setCaseInfo(mi.getCase_info()) + .setPropellantInfo(mi.getProp_info()) + .setDiameter(mi.getDiameter() / 1000.0) + .setLength(mi.getLength() / 1000.0) + .setMotorType(type); + + if ("OOP".equals(mi.getAvailiability())) { + builder.setDesignation(mi.getDesignation()); + builder.setAvailablity(false); + } else if (mi.getDesignation().startsWith("Micro")) { + builder.setDesignation(mi.getDesignation()); + } else { + builder.setDesignation(mi.getCommon_name()); + } + + allMotors.add(builder.build()); + + } + + System.out.println("\t curves: " + b.size()); + + } + } + + } + + private static List getThrustCurvesForMotorId(int motorId) { + List b = new ArrayList<>(); + try { + b.addAll(ThrustCurveAPI.downloadData(motorId, "RockSim")); + } catch (Exception ex) { + System.out.println("\tError downloading RockSim"); + } + try { + b.addAll(ThrustCurveAPI.downloadData(motorId, "RASP")); + } catch (Exception ex) { + System.out.println("\tError downloading RASP"); + } + return b; + } + + private static void loadFromLocalMotorFiles(List allMotors, String inputDir) throws IOException { + GeneralMotorLoader loader = new GeneralMotorLoader(); + FileIterator iterator = DirectoryIterator.findDirectory(inputDir, new SimpleFileFilter("", false, loader.getSupportedExtensions())); + if (iterator == null) { + System.out.println("Can't find " + inputDir + " directory"); + System.exit(1); + } else { + while (iterator.hasNext()) { + Pair f = iterator.next(); + String fileName = f.getU(); + InputStream is = f.getV(); + + List motors = loader.load(is, fileName); + + for (Builder builder : motors) { + allMotors.add(builder.build()); + } + } + } + + } +} diff --git a/core/src/net/sf/openrocket/thrustcurve/SupportedFileTypes.java b/core/src/net/sf/openrocket/thrustcurve/SupportedFileTypes.java new file mode 100644 index 000000000..37d486f06 --- /dev/null +++ b/core/src/net/sf/openrocket/thrustcurve/SupportedFileTypes.java @@ -0,0 +1,11 @@ +package net.sf.openrocket.thrustcurve; + +public abstract class SupportedFileTypes { + + public final static String ROCKSIM_FORMAT = "RockSim"; + public final static String RASP_FORMAT = "RASP"; + + public static boolean isSupportedFileType( String arg0 ) { + return (ROCKSIM_FORMAT.equals(arg0) || RASP_FORMAT.equals(arg0)); + } +} diff --git a/core/src/net/sf/openrocket/thrustcurve/TCMotor.java b/core/src/net/sf/openrocket/thrustcurve/TCMotor.java new file mode 100644 index 000000000..e9e645fca --- /dev/null +++ b/core/src/net/sf/openrocket/thrustcurve/TCMotor.java @@ -0,0 +1,298 @@ +package net.sf.openrocket.thrustcurve; + +import java.util.Date; + +public class TCMotor implements Cloneable { + + private Integer motor_id; + private String manufacturer; + private String manufacturer_abbr; + private String designation; + private String brand_name; + private String common_name; + private String impulse_class; + private Float diameter; + private Float length; + private String type; + private String cert_org; + private Float avg_thrust_n; + private Float max_thrust_n; + private Float tot_impulse_ns; + private Float burn_time_s; + private Integer data_files; + private String info_url; + private Double tot_mass_g; + private Double prop_mass_g; + private String delays; + private String case_info; + private String prop_info; + private Date updated_on; + private String availability; + + public void init() { + motor_id = null; + manufacturer = null; + manufacturer_abbr = null; + designation = null; + brand_name = null; + common_name = null; + impulse_class = null; + diameter = null; + length = null; + type = null; + cert_org = null; + avg_thrust_n = null; + max_thrust_n = null; + tot_impulse_ns = null; + burn_time_s = null; + data_files = null; + info_url = null; + tot_mass_g = null; + prop_mass_g = null; + delays = null; + case_info = null; + prop_info = null; + updated_on = null; + availability = null; + } + + @Override + public TCMotor clone() { + TCMotor clone = new TCMotor(); + clone.motor_id = this.motor_id; + clone.manufacturer = this.manufacturer; + clone.manufacturer_abbr = this.manufacturer_abbr; + clone.designation = this.designation; + clone.brand_name = this.brand_name; + clone.common_name = this.common_name; + clone.impulse_class = this.impulse_class; + clone.diameter = this.diameter; + clone.length = this.length; + clone.type = this.type; + clone.cert_org = this.cert_org; + clone.avg_thrust_n = this.avg_thrust_n; + clone.max_thrust_n = this.max_thrust_n; + clone.tot_impulse_ns = this.tot_impulse_ns; + clone.burn_time_s = this.burn_time_s; + clone.data_files = this.data_files; + clone.info_url = this.info_url; + clone.tot_mass_g = this.tot_mass_g; + clone.prop_mass_g = this.prop_mass_g; + clone.delays = this.delays; + clone.case_info = this.case_info; + clone.prop_info = this.prop_info; + clone.updated_on = this.updated_on; + clone.availability = this.availability; + return clone; + } + + public Integer getMotor_id() { + return motor_id; + } + + public void setMotor_id(Integer motor_id) { + this.motor_id = motor_id; + } + + public String getManufacturer() { + return manufacturer; + } + + public void setManufacturer(String manufacturer) { + this.manufacturer = manufacturer; + } + + public String getManufacturer_abbr() { + return manufacturer_abbr; + } + + public void setManufacturer_abbr(String manufacturer_abbr) { + this.manufacturer_abbr = manufacturer_abbr; + } + + public String getDesignation() { + return designation; + } + + public void setDesignation(String designation) { + this.designation = designation; + } + + public String getBrand_name() { + return brand_name; + } + + public void setBrand_name(String brand_name) { + this.brand_name = brand_name; + } + + public String getCommon_name() { + return common_name; + } + + public void setCommon_name(String common_name) { + this.common_name = common_name; + } + + public String getImpulse_class() { + return impulse_class; + } + + public void setImpulse_class(String impulse_class) { + this.impulse_class = impulse_class; + } + + public Float getDiameter() { + return diameter; + } + + public void setDiameter(Float diameter) { + this.diameter = diameter; + } + + public Float getLength() { + return length; + } + + public void setLength(Float length) { + this.length = length; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getCert_org() { + return cert_org; + } + + public void setCert_org(String cert_org) { + this.cert_org = cert_org; + } + + public Float getAvg_thrust_n() { + return avg_thrust_n; + } + + public void setAvg_thrust_n(Float avg_thrust_n) { + this.avg_thrust_n = avg_thrust_n; + } + + public Float getMax_thrust_n() { + return max_thrust_n; + } + + public void setMax_thrust_n(Float max_thrust_n) { + this.max_thrust_n = max_thrust_n; + } + + public Float getTot_impulse_ns() { + return tot_impulse_ns; + } + + public void setTot_impulse_ns(Float tot_impulse_ns) { + this.tot_impulse_ns = tot_impulse_ns; + } + + public Float getBurn_time_s() { + return burn_time_s; + } + + public void setBurn_time_s(Float burn_time_s) { + this.burn_time_s = burn_time_s; + } + + public Integer getData_files() { + return data_files; + } + + public void setData_files(Integer data_files) { + this.data_files = data_files; + } + + public String getInfo_url() { + return info_url; + } + + public void setInfo_url(String info_url) { + this.info_url = info_url; + } + + public Double getTot_mass_g() { + return tot_mass_g; + } + + public void setTot_mass_g(Double tot_mass_g) { + this.tot_mass_g = tot_mass_g; + } + + public Double getProp_mass_g() { + return prop_mass_g; + } + + public void setProp_mass_g(Double prop_mass_g) { + this.prop_mass_g = prop_mass_g; + } + + public String getDelays() { + return delays; + } + + public void setDelays(String delays) { + this.delays = delays; + } + + public String getCase_info() { + return case_info; + } + + public void setCase_info(String case_info) { + this.case_info = case_info; + } + + public String getProp_info() { + return prop_info; + } + + public void setProp_info(String prop_info) { + this.prop_info = prop_info; + } + + public Date getUpdated_on() { + return updated_on; + } + + public void setUpdated_on(Date updated_on) { + this.updated_on = updated_on; + } + + public String getAvailiability() { + return availability; + } + + public void setAvailability(String avail) { + this.availability = avail; + } + + @Override + public String toString() { + return "TCMotor [motor_id=" + motor_id + ", manufacturer=" + + manufacturer + ", manufacturer_abbr=" + manufacturer_abbr + + ", designation=" + designation + ", brand_name=" + brand_name + + ", common_name=" + common_name + ", impulse_class=" + + impulse_class + ", diameter=" + diameter + ", length=" + + length + ", type=" + type + ", cert_org=" + cert_org + + ", avg_thrust_n=" + avg_thrust_n + ", max_thrust_n=" + + max_thrust_n + ", tot_impulse_ns=" + tot_impulse_ns + + ", burn_time_s=" + burn_time_s + ", data_files=" + data_files + + ", info_url=" + info_url + ", tot_mass_g=" + tot_mass_g + + ", prop_mass_g=" + prop_mass_g + ", delays=" + delays + + ", case_info=" + case_info + ", prop_info=" + prop_info + + ", updated_on=" + updated_on + "]"; + } + +} diff --git a/core/src/net/sf/openrocket/thrustcurve/ThrustCurveAPI.java b/core/src/net/sf/openrocket/thrustcurve/ThrustCurveAPI.java new file mode 100644 index 000000000..8b810855c --- /dev/null +++ b/core/src/net/sf/openrocket/thrustcurve/ThrustCurveAPI.java @@ -0,0 +1,83 @@ +package net.sf.openrocket.thrustcurve; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Collections; +import java.util.List; + +import org.xml.sax.SAXException; + + +public abstract class ThrustCurveAPI { + + public static SearchResponse doSearch(SearchRequest request) throws MalformedURLException, IOException, SAXException { + + String requestString = request.toString(); + + // Froyo has troubles resolving URLS constructed with protocols. Because of this + // we need to do it in parts. + URL url = new URL("http", "www.thrustcurve.org", "/servlets/search"); + + OutputStream stream; + + URLConnection conn = url.openConnection(); + conn.setConnectTimeout(2000); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setUseCaches(false); + + stream = conn.getOutputStream(); + + stream.write(requestString.getBytes()); + + InputStream is = conn.getInputStream(); + + SearchResponse result = SearchResponseParser.parse(is); + + return result; + } + + public static List downloadData(Integer motor_id, String format) throws MalformedURLException, IOException, SAXException { + + if (motor_id == null) { + return null; + } + DownloadRequest dr = new DownloadRequest(); + dr.add(motor_id); + dr.setFormat(format); + + String requestString = dr.toString(); + + // Froyo has troubles resolving URLS constructed with protocols. Because of this + // we need to do it in parts. + URL url = new URL("http", "www.thrustcurve.org", "/servlets/download"); + + OutputStream stream; + + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setUseCaches(false); + conn.connect(); + + stream = conn.getOutputStream(); + + stream.write(requestString.getBytes()); + + if (conn.getResponseCode() == HttpURLConnection.HTTP_BAD_REQUEST) { + return Collections. emptyList(); + } + InputStream is = conn.getInputStream(); + + DownloadResponse downloadResponse = DownloadResponseParser.parse(is); + + return downloadResponse.getData(motor_id); + + } + +}