geodetic computation file storage
[debian/openrocket] / src / net / sf / openrocket / file / openrocket / OpenRocketSaver.java
index 6a13069b2fa1c85561ca82643159ff407b483da6..6554a5375446b6dd9e6fccff9510d347cff05d7b 100644 (file)
@@ -15,36 +15,42 @@ import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.document.StorageOptions;
 import net.sf.openrocket.file.RocketSaver;
+import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.FinSet;
+import net.sf.openrocket.rocketcomponent.MotorMount;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.TubeCoupler;
 import net.sf.openrocket.simulation.FlightData;
 import net.sf.openrocket.simulation.FlightDataBranch;
+import net.sf.openrocket.simulation.FlightDataType;
 import net.sf.openrocket.simulation.FlightEvent;
-import net.sf.openrocket.simulation.SimulationConditions;
+import net.sf.openrocket.simulation.SimulationOptions;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.MathUtil;
-import net.sf.openrocket.util.Pair;
 import net.sf.openrocket.util.Prefs;
 import net.sf.openrocket.util.Reflection;
 import net.sf.openrocket.util.TextUtil;
 
 public class OpenRocketSaver extends RocketSaver {
+       private static final LogHelper log = Application.getLogger();
        
+
        /**
         * Divisor used in converting an integer version to the point-represented version.
         * The integer version divided by this value is the major version and the remainder is
         * the minor version.  For example 101 corresponds to file version "1.1".
         */
        public static final int FILE_VERSION_DIVISOR = 100;
-
        
+
        private static final String OPENROCKET_CHARSET = "UTF-8";
        
        private static final String METHOD_PACKAGE = "net.sf.openrocket.file.openrocket.savers";
        private static final String METHOD_SUFFIX = "Saver";
        
-       
+
        // Estimated storage used by different portions
        // These have been hand-estimated from saved files
        private static final int BYTES_PER_COMPONENT_UNCOMPRESSED = 590;
@@ -54,29 +60,33 @@ public class OpenRocketSaver extends RocketSaver {
        private static final int BYTES_PER_DATAPOINT_UNCOMPRESSED = 350;
        private static final int BYTES_PER_DATAPOINT_COMPRESSED = 100;
        
-       
+
        private int indent;
        private Writer dest;
        
        @Override
        public void save(OutputStream output, OpenRocketDocument document, StorageOptions options)
-       throws IOException {
+                       throws IOException {
+               
+               log.info("Saving .ork file");
                
                if (options.isCompressionEnabled()) {
+                       log.debug("Enabling compression");
                        output = new GZIPOutputStream(output);
                }
                
-               dest = new BufferedWriter(new OutputStreamWriter(output, OPENROCKET_CHARSET)); 
+               dest = new BufferedWriter(new OutputStreamWriter(output, OPENROCKET_CHARSET));
                
+               // Select file version number
                final int fileVersion = calculateNecessaryFileVersion(document, options);
-               final String fileVersionString = 
-                       (fileVersion / FILE_VERSION_DIVISOR) + "." + (fileVersion % FILE_VERSION_DIVISOR); 
-               
+               final String fileVersionString =
+                               (fileVersion / FILE_VERSION_DIVISOR) + "." + (fileVersion % FILE_VERSION_DIVISOR);
+               log.debug("Storing file version " + fileVersionString);
                
+
                this.indent = 0;
                
-               System.out.println("Writing...");
-               
+
                writeln("<?xml version='1.0' encoding='utf-8'?>");
                writeln("<openrocket version=\"" + fileVersionString + "\" creator=\"OpenRocket "
                                + Prefs.getVersion() + "\">");
@@ -91,7 +101,7 @@ public class OpenRocketSaver extends RocketSaver {
                writeln("<simulations>");
                indent++;
                boolean first = true;
-               for (Simulation s: document.getSimulations()) {
+               for (Simulation s : document.getSimulations()) {
                        if (!first)
                                writeln("");
                        first = false;
@@ -103,14 +113,15 @@ public class OpenRocketSaver extends RocketSaver {
                indent--;
                writeln("</openrocket>");
                
+               log.debug("Writing complete, flushing buffers");
                dest.flush();
                if (options.isCompressionEnabled()) {
-                       ((GZIPOutputStream)output).finish();
+                       ((GZIPOutputStream) output).finish();
                }
        }
        
        
-       
+
        @Override
        public long estimateFileSize(OpenRocketDocument doc, StorageOptions options) {
                
@@ -119,7 +130,7 @@ public class OpenRocketSaver extends RocketSaver {
                // Size per component
                int componentCount = 0;
                Rocket rocket = doc.getRocket();
-               Iterator<RocketComponent> iterator = rocket.deepIterator(true);
+               Iterator<RocketComponent> iterator = rocket.iterator(true);
                while (iterator.hasNext()) {
                        iterator.next();
                        componentCount++;
@@ -130,22 +141,22 @@ public class OpenRocketSaver extends RocketSaver {
                else
                        size += componentCount * BYTES_PER_COMPONENT_UNCOMPRESSED;
                
-               
+
                // Size per simulation
                if (options.isCompressionEnabled())
                        size += doc.getSimulationCount() * BYTES_PER_SIMULATION_COMPRESSED;
                else
                        size += doc.getSimulationCount() * BYTES_PER_SIMULATION_UNCOMPRESSED;
                
-               
+
                // Size per flight data point
                int pointCount = 0;
                double timeSkip = options.getSimulationTimeSkip();
                if (timeSkip != StorageOptions.SIMULATION_DATA_NONE) {
-                       for (Simulation s: doc.getSimulations()) {
+                       for (Simulation s : doc.getSimulations()) {
                                FlightData data = s.getSimulatedData();
                                if (data != null) {
-                                       for (int i=0; i < data.getBranchCount(); i++) {
+                                       for (int i = 0; i < data.getBranchCount(); i++) {
                                                pointCount += countFlightDataBranchPoints(data.getBranch(i), timeSkip);
                                        }
                                }
@@ -160,7 +171,7 @@ public class OpenRocketSaver extends RocketSaver {
                return size;
        }
        
-
+       
        /**
         * Determine which file version is required in order to store all the features of the
         * current design.  By default the oldest version that supports all the necessary features
@@ -172,22 +183,45 @@ public class OpenRocketSaver extends RocketSaver {
         */
        private int calculateNecessaryFileVersion(OpenRocketDocument document, StorageOptions opts) {
                /*
+                * File version 1.2 is required for:
+                *  - saving motor data
+                * 
                 * File version 1.1 is required for:
                 *  - fin tabs
                 *  - components attached to tube coupler
                 * 
                 * Otherwise use version 1.0.
                 */
+
+               // Check if design has simulations defined (version 1.3)
+               if (document.getSimulationCount() > 0) {
+                       return FILE_VERSION_DIVISOR + 3;
+               }
+               
+               // Check for motor definitions (version 1.2)
+               Iterator<RocketComponent> iterator = document.getRocket().iterator();
+               while (iterator.hasNext()) {
+                       RocketComponent c = iterator.next();
+                       if (!(c instanceof MotorMount))
+                               continue;
+                       
+                       MotorMount mount = (MotorMount) c;
+                       for (String id : document.getRocket().getMotorConfigurationIDs()) {
+                               if (mount.getMotor(id) != null) {
+                                       return FILE_VERSION_DIVISOR + 2;
+                               }
+                       }
+               }
                
                // Check for fin tabs (version 1.1)
-               Iterator<RocketComponent> iterator = document.getRocket().deepIterator();
+               iterator = document.getRocket().iterator();
                while (iterator.hasNext()) {
                        RocketComponent c = iterator.next();
                        
                        // Check for fin tabs
                        if (c instanceof FinSet) {
-                               FinSet fin = (FinSet)c;
-                               if (!MathUtil.equals(fin.getTabHeight(),0) &&
+                               FinSet fin = (FinSet) c;
+                               if (!MathUtil.equals(fin.getTabHeight(), 0) &&
                                                !MathUtil.equals(fin.getTabLength(), 0)) {
                                        return FILE_VERSION_DIVISOR + 1;
                                }
@@ -206,24 +240,26 @@ public class OpenRocketSaver extends RocketSaver {
        }
        
        
-       
+
        @SuppressWarnings("unchecked")
        private void saveComponent(RocketComponent component) throws IOException {
                
+               log.debug("Saving component " + component.getComponentName());
+               
                Reflection.Method m = Reflection.findMethod(METHOD_PACKAGE, component, METHOD_SUFFIX,
                                "getElements", RocketComponent.class);
-               if (m==null) {
-                       throw new RuntimeException("Unable to find saving class for component "+
+               if (m == null) {
+                       throw new BugException("Unable to find saving class for component " +
                                        component.getComponentName());
                }
-
+               
                // Get the strings to save
                List<String> list = (List<String>) m.invokeStatic(component);
                int length = list.size();
                
-               if (length == 0)  // Nothing to do
+               if (length == 0) // Nothing to do
                        return;
-
+               
                if (length < 2) {
                        throw new RuntimeException("BUG, component data length less than two lines.");
                }
@@ -233,7 +269,7 @@ public class OpenRocketSaver extends RocketSaver {
                indent++;
                
                // Write parameters
-               for (int i=1; i<length-1; i++) {
+               for (int i = 1; i < length - 1; i++) {
                        writeln(list.get(i));
                }
                
@@ -243,7 +279,7 @@ public class OpenRocketSaver extends RocketSaver {
                        writeln("<subcomponents>");
                        indent++;
                        boolean emptyline = false;
-                       for (RocketComponent subcomponent: component) {
+                       for (RocketComponent subcomponent : component.getChildren()) {
                                if (emptyline)
                                        writeln("");
                                emptyline = true;
@@ -255,15 +291,14 @@ public class OpenRocketSaver extends RocketSaver {
                
                // Close element
                indent--;
-               writeln(list.get(length-1));
+               writeln(list.get(length - 1));
        }
-
        
        
        private void saveSimulation(Simulation simulation, double timeSkip) throws IOException {
-               SimulationConditions cond = simulation.getConditions();
+               SimulationOptions cond = simulation.getOptions();
                
-               writeln("<simulation status=\"" + enumToXMLName(simulation.getStatus()) +"\">");
+               writeln("<simulation status=\"" + enumToXMLName(simulation.getStatus()) + "\">");
                indent++;
                
                writeln("<name>" + escapeXML(simulation.getName()) + "</name>");
@@ -275,12 +310,14 @@ public class OpenRocketSaver extends RocketSaver {
                
                writeElement("configid", cond.getMotorConfigurationID());
                writeElement("launchrodlength", cond.getLaunchRodLength());
-               writeElement("launchrodangle", cond.getLaunchRodAngle() * 180.0/Math.PI); 
-               writeElement("launchroddirection", cond.getLaunchRodDirection() * 180.0/Math.PI);
+               writeElement("launchrodangle", cond.getLaunchRodAngle() * 180.0 / Math.PI);
+               writeElement("launchroddirection", cond.getLaunchRodDirection() * 180.0 / Math.PI);
                writeElement("windaverage", cond.getWindSpeedAverage());
                writeElement("windturbulence", cond.getWindTurbulenceIntensity());
                writeElement("launchaltitude", cond.getLaunchAltitude());
                writeElement("launchlatitude", cond.getLaunchLatitude());
+               writeElement("launchlongitude", cond.getLaunchLongitude());
+               writeElement("geodeticmethod", cond.getGeodeticComputation().name().toLowerCase());
                
                if (cond.isISAAtmosphere()) {
                        writeln("<atmosphere model=\"isa\"/>");
@@ -292,18 +329,18 @@ public class OpenRocketSaver extends RocketSaver {
                        indent--;
                        writeln("</atmosphere>");
                }
-
+               
                writeElement("timestep", cond.getTimeStep());
                
                indent--;
                writeln("</conditions>");
                
-               
-               for (String s: simulation.getSimulationListeners()) {
+
+               for (String s : simulation.getSimulationListeners()) {
                        writeElement("listener", escapeXML(s));
                }
                
-               
+
                // Write basic simulation data
                
                FlightData data = simulation.getSimulatedData();
@@ -327,7 +364,7 @@ public class OpenRocketSaver extends RocketSaver {
                        writeln(str);
                        indent++;
                        
-                       for (Warning w: data.getWarningSet()) {
+                       for (Warning w : data.getWarningSet()) {
                                writeElement("warning", escapeXML(w.toString()));
                        }
                        
@@ -336,7 +373,7 @@ public class OpenRocketSaver extends RocketSaver {
                                timeSkip = 0;
                        
                        if (timeSkip != StorageOptions.SIMULATION_DATA_NONE) {
-                               for (int i=0; i<data.getBranchCount(); i++) {
+                               for (int i = 0; i < data.getBranchCount(); i++) {
                                        FlightDataBranch branch = data.getBranch(i);
                                        saveFlightDataBranch(branch, timeSkip);
                                }
@@ -352,26 +389,26 @@ public class OpenRocketSaver extends RocketSaver {
        }
        
        
-       
-       private void saveFlightDataBranch(FlightDataBranch branch, double timeSkip) 
-       throws IOException {
+
+       private void saveFlightDataBranch(FlightDataBranch branch, double timeSkip)
+                       throws IOException {
                double previousTime = -100000;
                
                if (branch == null)
                        return;
                
                // Retrieve the types from the branch
-               FlightDataBranch.Type[] types = branch.getTypes();
+               FlightDataType[] types = branch.getTypes();
                
                if (types.length == 0)
                        return;
                
                // Retrieve the data from the branch
                List<List<Double>> data = new ArrayList<List<Double>>(types.length);
-               for (int i=0; i<types.length; i++) {
+               for (int i = 0; i < types.length; i++) {
                        data.add(branch.get(types[i]));
                }
-               List<Double> timeData = branch.get(FlightDataBranch.TYPE_TIME);
+               List<Double> timeData = branch.get(FlightDataType.TYPE_TIME);
                if (timeData == null) {
                        // TODO: MEDIUM: External data may not have time data
                        throw new IllegalArgumentException("Data did not contain time data");
@@ -382,7 +419,7 @@ public class OpenRocketSaver extends RocketSaver {
                sb.append("<databranch name=\"");
                sb.append(escapeXML(branch.getBranchName()));
                sb.append("\" types=\"");
-               for (int i=0; i<types.length; i++) {
+               for (int i = 0; i < types.length; i++) {
                        if (i > 0)
                                sb.append(",");
                        sb.append(escapeXML(types[i].getName()));
@@ -392,9 +429,9 @@ public class OpenRocketSaver extends RocketSaver {
                indent++;
                
                // Write events
-               for (Pair<Double,FlightEvent> p: branch.getEvents()) {
-                       writeln("<event time=\"" + TextUtil.doubleToString(p.getU())
-                                       + "\" type=\"" + enumToXMLName(p.getV().getType()) + "\"/>");
+               for (FlightEvent event : branch.getEvents()) {
+                       writeln("<event time=\"" + TextUtil.doubleToString(event.getTime())
+                                       + "\" type=\"" + enumToXMLName(event.getType()) + "\"/>");
                }
                
                // Write the data
@@ -404,16 +441,15 @@ public class OpenRocketSaver extends RocketSaver {
                        previousTime = timeData.get(0);
                }
                
-               for (int i=1; i < length-1; i++) {
-                       if (Math.abs(timeData.get(i) - previousTime - timeSkip) < 
-                                       Math.abs(timeData.get(i+1) - previousTime - timeSkip)) {
+               for (int i = 1; i < length - 1; i++) {
+                       if (Math.abs(timeData.get(i) - previousTime - timeSkip) < Math.abs(timeData.get(i + 1) - previousTime - timeSkip)) {
                                writeDataPointString(data, i, sb);
                                previousTime = timeData.get(i);
                        }
                }
                
                if (length > 1) {
-                       writeDataPointString(data, length-1, sb);
+                       writeDataPointString(data, length - 1, sb);
                }
                
                indent--;
@@ -421,23 +457,23 @@ public class OpenRocketSaver extends RocketSaver {
        }
        
        
-       
+
        /* TODO: LOW: This is largely duplicated from above! */
        private int countFlightDataBranchPoints(FlightDataBranch branch, double timeSkip) {
                int count = 0;
-
+               
                double previousTime = -100000;
                
                if (branch == null)
                        return 0;
                
                // Retrieve the types from the branch
-               FlightDataBranch.Type[] types = branch.getTypes();
+               FlightDataType[] types = branch.getTypes();
                
                if (types.length == 0)
                        return 0;
                
-               List<Double> timeData = branch.get(FlightDataBranch.TYPE_TIME);
+               List<Double> timeData = branch.get(FlightDataType.TYPE_TIME);
                if (timeData == null) {
                        // TODO: MEDIUM: External data may not have time data
                        throw new IllegalArgumentException("Data did not contain time data");
@@ -450,9 +486,8 @@ public class OpenRocketSaver extends RocketSaver {
                        previousTime = timeData.get(0);
                }
                
-               for (int i=1; i < length-1; i++) {
-                       if (Math.abs(timeData.get(i) - previousTime - timeSkip) < 
-                                       Math.abs(timeData.get(i+1) - previousTime - timeSkip)) {
+               for (int i = 1; i < length - 1; i++) {
+                       if (Math.abs(timeData.get(i) - previousTime - timeSkip) < Math.abs(timeData.get(i + 1) - previousTime - timeSkip)) {
                                count++;
                                previousTime = timeData.get(i);
                        }
@@ -461,17 +496,17 @@ public class OpenRocketSaver extends RocketSaver {
                if (length > 1) {
                        count++;
                }
-
+               
                return count;
        }
        
        
-       
+
        private void writeDataPointString(List<List<Double>> data, int index, StringBuilder sb)
-       throws IOException {
+                       throws IOException {
                sb.setLength(0);
                sb.append("<datapoint>");
-               for (int j=0; j < data.size(); j++) {
+               for (int j = 0; j < data.size(); j++) {
                        if (j > 0)
                                sb.append(",");
                        sb.append(TextUtil.doubleToString(data.get(j).get(index)));
@@ -481,44 +516,30 @@ public class OpenRocketSaver extends RocketSaver {
        }
        
        
-       
+
        private void writeElement(String element, Object content) throws IOException {
                if (content == null)
                        content = "";
-               writeln("<"+element+">"+content+"</"+element+">");
+               writeln("<" + element + ">" + content + "</" + element + ">");
        }
-
-
        
+       
+
        private void writeln(String str) throws IOException {
                if (str.length() == 0) {
                        dest.write("\n");
                        return;
                }
-               String s="";
-               for (int i=0; i<indent; i++)
-                       s=s+"  ";
-               s = s+str+"\n";
+               String s = "";
+               for (int i = 0; i < indent; i++)
+                       s = s + "  ";
+               s = s + str + "\n";
                dest.write(s);
        }
        
        
-       public static void main(String[] arg) {
-               double d = -0.000000123456789123;
-               
-               
-               for (int i=0; i< 20; i++) {
-                       String str = TextUtil.doubleToString(d);
-                       System.out.println(str + "   ->   " + Double.parseDouble(str));
-                       d *= 10;
-               }
-               
-               
-               System.out.println("Value: "+ Double.parseDouble("1.2345e9"));
-               
-       }
 
-       
+
        /**
         * Return the XML equivalent of an enum name.
         *