Numerous bug fixes and updates
[debian/openrocket] / src / net / sf / openrocket / file / CSVExport.java
diff --git a/src/net/sf/openrocket/file/CSVExport.java b/src/net/sf/openrocket/file/CSVExport.java
new file mode 100644 (file)
index 0000000..c306462
--- /dev/null
@@ -0,0 +1,220 @@
+package net.sf.openrocket.file;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import net.sf.openrocket.aerodynamics.Warning;
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.simulation.FlightData;
+import net.sf.openrocket.simulation.FlightDataBranch;
+import net.sf.openrocket.simulation.FlightEvent;
+import net.sf.openrocket.simulation.FlightDataBranch.Type;
+import net.sf.openrocket.unit.Unit;
+import net.sf.openrocket.util.Pair;
+import net.sf.openrocket.util.TextUtil;
+
+public class CSVExport {
+
+       /**
+        * Exports the specified flight data branch into a CSV file.
+        * 
+        * @param stream                                the stream to write to.
+        * @param simulation                    the simulation being exported.
+        * @param branch                                the branch to export.
+        * @param fields                                the fields to export (in appropriate order).
+        * @param units                                 the units of the fields.
+        * @param fieldSeparator                the field separator string.
+        * @param commentStarter                the comment starting character(s).
+        * @param simulationComments    whether to output general simulation comments.
+        * @param fieldComments                 whether to output field comments.
+        * @param eventComments                 whether to output comments for the flight events.
+        * @throws IOException                  if an I/O exception occurs.
+        */
+       public static void exportCSV(OutputStream stream, Simulation simulation, 
+                       FlightDataBranch branch, FlightDataBranch.Type[] fields, Unit[] units, 
+                       String fieldSeparator,String commentStarter, boolean simulationComments, 
+                       boolean fieldComments, boolean eventComments) throws IOException {
+               
+               if (fields.length != units.length) {
+                       throw new IllegalArgumentException("fields and units lengths must be equal " +
+                                       "(" + fields.length + " vs " + units.length + ")");
+               }
+               
+               
+               PrintWriter writer = null;
+               try {
+                       
+                       writer = new PrintWriter(stream);
+                       
+                       // Write the initial comments
+                       if (simulationComments) {
+                               writeSimulationComments(writer, simulation, branch, fields, commentStarter);
+                       }
+                       
+                       if (simulationComments && fieldComments) {
+                               writer.println(commentStarter);
+                       }
+                       
+                       if (fieldComments) {
+                               writer.print(commentStarter + " ");
+                               for (int i=0; i < fields.length; i++) {
+                                       writer.print(fields[i].getName() + " (" + units[i].getUnit() + ")");
+                                       if (i < fields.length-1) {
+                                               writer.print(fieldSeparator);
+                                       }
+                               }
+                               writer.println();
+                       }
+                       
+                       writeData(writer, branch, fields, units, fieldSeparator, 
+                                       eventComments, commentStarter);
+                       
+                       
+               } finally {
+                       if (writer != null) {
+                               try {
+                                       writer.close();
+                               } catch (Exception e) {
+                                       e.printStackTrace();
+                               }
+                       }
+               }
+       }
+
+       private static void writeData(PrintWriter writer, FlightDataBranch branch,
+                       Type[] fields, Unit[] units, String fieldSeparator, boolean eventComments,
+                       String commentStarter) {
+               
+               // Number of data points
+               int n = branch.getLength();
+               
+               // Flight events in occurrance order
+               List<Pair<Double, FlightEvent>> events = branch.getEvents();
+               Collections.sort(events, new Comparator<Pair<Double, FlightEvent>>() {
+                       @Override
+                       public int compare(Pair<Double, FlightEvent> o1, Pair<Double, FlightEvent> o2) {
+                               return Double.compare(o1.getU(), o2.getU());
+                       }
+               });
+               int eventPosition = 0;
+               
+               // List of field values
+               List<List<Double>> fieldValues = new ArrayList<List<Double>>();
+               for (Type t: fields) {
+                       fieldValues.add(branch.get(t));
+               }
+               
+               // Time variable
+               List<Double> time = branch.get(FlightDataBranch.TYPE_TIME);
+               if (eventComments && time == null) {
+                       // If time information is not available, print events at beginning of file
+                       for (Pair<Double, FlightEvent> e: events) {
+                               printEvent(writer, e, commentStarter);
+                       }
+                       eventPosition = events.size();
+               }
+               
+               
+               // Loop over all data points
+               for (int pos=0; pos<n; pos++) {
+                       
+                       // Check for events to store
+                       if (eventComments && time != null) {
+                               double t = time.get(pos);
+                               
+                               while ((eventPosition < events.size()) && 
+                                               (events.get(eventPosition).getU() <= t)) {
+                                       printEvent(writer, events.get(eventPosition), commentStarter);
+                                       eventPosition++;
+                               }
+                       }
+                       
+                       // Store CSV line
+                       for (int i=0; i < fields.length; i++) {
+                               double value = fieldValues.get(i).get(pos);
+                               writer.print(TextUtil.doubleToString(units[i].toUnit(value)));
+                               if (i < fields.length-1) {
+                                       writer.print(fieldSeparator);
+                               }
+                       }
+                       writer.println();
+                       
+               }
+               
+               // Store any remaining events
+               if (eventComments && time != null) {
+                       while (eventPosition < events.size()) {
+                               printEvent(writer, events.get(eventPosition), commentStarter);
+                               eventPosition++;
+                       }
+               }
+               
+       }
+
+       
+       private static void printEvent(PrintWriter writer, Pair<Double, FlightEvent> e,
+                       String commentStarter) {
+               writer.println(commentStarter + " Event " + e.getV().getType().toString() + 
+                               " occurred at t=" + TextUtil.doubleToString(e.getU()) + " seconds");
+       }
+
+       private static void writeSimulationComments(PrintWriter writer,
+                       Simulation simulation, FlightDataBranch branch, Type[] fields, 
+                       String commentStarter) {
+               
+               String line;
+               
+               line = simulation.getName();
+
+               FlightData data = simulation.getSimulatedData();
+               
+               switch (simulation.getStatus()) {
+               case UPTODATE:
+                       line += " (Up to date)";
+                       break;
+                       
+               case LOADED:
+                       line += " (Data loaded from a file)";
+                       break;
+                       
+               case OUTDATED:
+                       line += " (Data is out of date)";
+                       break;
+                       
+               case EXTERNAL:
+                       line += " (Imported data)";
+                       break;
+                       
+               case NOT_SIMULATED:
+                       line += " (Not simulated yet)";
+                       break;
+               }
+               
+               writer.println(commentStarter + " " + line);
+               
+
+               writer.println(commentStarter + " " + branch.getLength() + " data points written for "
+                               + fields.length + " variables.");
+               
+               
+               if (data == null) {
+                       writer.println(commentStarter + " No simulation data available.");
+                       return;
+               }
+               WarningSet warnings = data.getWarningSet();
+               
+               if (!warnings.isEmpty()) {
+                       writer.println(commentStarter + " Simulation warnings:");
+                       for (Warning w: warnings) {
+                               writer.println(commentStarter + "   " + w.toString());
+                       }
+               }
+       }
+       
+}