Merge pull request #1427 from SiboVG/issue-1354
[fixes #1354 & #1037] Add support for custom decimal places and exponential notation in simulation exports
This commit is contained in:
commit
c3a3df9db2
@ -552,10 +552,14 @@ SimExpPan.border.Vartoexport = Variables to export
|
||||
SimExpPan.border.Stage = Stage to export
|
||||
SimExpPan.but.Selectall = Select all
|
||||
SimExpPan.but.Selectnone = Select none
|
||||
SimExpPan.border.Fieldsep = Field separator
|
||||
SimExpPan.border.FormatSettings = Format settings
|
||||
SimExpPan.lbl.Fieldsepstr = Field separator string:
|
||||
SimExpPan.lbl.longA1 = <html>The string used to separate the fields in the exported file.<br>
|
||||
SimExpPan.lbl.longA2 = Use ',' for a Comma Separated Values (CSV) file.
|
||||
SimExpPan.lbl.DecimalPlaces = Decimal places:
|
||||
SimExpPan.lbl.DecimalPlaces.ttip = The number of decimal places to use for the variables in the exported file.
|
||||
SimExpPan.lbl.ExponentialNotation = Use exponential notation
|
||||
SimExpPan.lbl.ExponentialNotation.ttip = Whether to use exponential notation for the variables (e.g. 1.5e-4) or not (e.g. 0.00015).
|
||||
SimExpPan.checkbox.Includesimudesc = Include simulation description
|
||||
SimExpPan.checkbox.ttip.Includesimudesc = Include a comment at the beginning of the file describing the simulation.
|
||||
SimExpPan.border.Comments = Comments
|
||||
|
@ -29,6 +29,8 @@ public class CSVExport {
|
||||
* @param fields the fields to export (in appropriate order).
|
||||
* @param units the units of the fields.
|
||||
* @param fieldSeparator the field separator string.
|
||||
* @param decimalPlaces the number of decimal places to use.
|
||||
* @param isExponentialNotation whether to use exponential notation.
|
||||
* @param commentStarter the comment starting character(s).
|
||||
* @param simulationComments whether to output general simulation comments.
|
||||
* @param fieldComments whether to output field comments.
|
||||
@ -37,8 +39,9 @@ public class CSVExport {
|
||||
*/
|
||||
public static void exportCSV(OutputStream stream, Simulation simulation,
|
||||
FlightDataBranch branch, FlightDataType[] fields, Unit[] units,
|
||||
String fieldSeparator, String commentStarter, boolean simulationComments,
|
||||
boolean fieldComments, boolean eventComments) throws IOException {
|
||||
String fieldSeparator, int decimalPlaces, boolean isExponentialNotation,
|
||||
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 " +
|
||||
@ -71,7 +74,7 @@ public class CSVExport {
|
||||
writer.println();
|
||||
}
|
||||
|
||||
writeData(writer, branch, fields, units, fieldSeparator,
|
||||
writeData(writer, branch, fields, units, fieldSeparator, decimalPlaces, isExponentialNotation,
|
||||
eventComments, commentStarter);
|
||||
|
||||
|
||||
@ -87,8 +90,8 @@ public class CSVExport {
|
||||
}
|
||||
|
||||
private static void writeData(PrintWriter writer, FlightDataBranch branch,
|
||||
FlightDataType[] fields, Unit[] units, String fieldSeparator, boolean eventComments,
|
||||
String commentStarter) {
|
||||
FlightDataType[] fields, Unit[] units, String fieldSeparator, int decimalPlaces, boolean isExponentialNotation,
|
||||
boolean eventComments, String commentStarter) {
|
||||
|
||||
// Number of data points
|
||||
int n = branch.getLength();
|
||||
@ -132,7 +135,8 @@ public class CSVExport {
|
||||
// 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)));
|
||||
writer.print(TextUtil.doubleToString(units[i].toUnit(value), decimalPlaces, isExponentialNotation));
|
||||
|
||||
if (i < fields.length - 1) {
|
||||
writer.print(fieldSeparator);
|
||||
}
|
||||
|
@ -46,6 +46,8 @@ public abstract class Preferences implements ChangeSource {
|
||||
public static final String DEFAULT_MACH_NUMBER = "DefaultMachNumber";
|
||||
// Preferences related to data export
|
||||
public static final String EXPORT_FIELD_SEPARATOR = "ExportFieldSeparator";
|
||||
public static final String EXPORT_DECIMAL_PLACES = "ExportDecimalPlaces";
|
||||
public static final String EXPORT_EXPONENTIAL_NOTATION = "ExportExponentialNotation";
|
||||
public static final String EXPORT_SIMULATION_COMMENT = "ExportSimulationComment";
|
||||
public static final String EXPORT_FIELD_NAME_COMMENT = "ExportFieldDescriptionComment";
|
||||
public static final String EXPORT_EVENT_COMMENTS = "ExportEventComments";
|
||||
|
@ -40,50 +40,81 @@ public class TextUtil {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a string of the double value with suitable precision for storage.
|
||||
* The string is the shortest representation of the value including at least
|
||||
* 5 digits of precision.
|
||||
*
|
||||
*
|
||||
* @param d the value to present.
|
||||
* @param decimalPlaces the number of decimal places to save the value with.
|
||||
* @param isExponentialNotation if true, the value is presented in exponential notation.
|
||||
* @return a representation with suitable precision.
|
||||
*/
|
||||
public static final String doubleToString(double d) {
|
||||
|
||||
public static String doubleToString(double d, int decimalPlaces, boolean isExponentialNotation) {
|
||||
// Check for special cases
|
||||
if (MathUtil.equals(d, 0))
|
||||
return "0";
|
||||
|
||||
|
||||
if (Double.isNaN(d))
|
||||
return "NaN";
|
||||
|
||||
|
||||
if (Double.isInfinite(d)) {
|
||||
if (d < 0)
|
||||
return "-Inf";
|
||||
else
|
||||
return "Inf";
|
||||
}
|
||||
|
||||
|
||||
|
||||
final String sign = (d < 0) ? "-" : "";
|
||||
double abs = Math.abs(d);
|
||||
|
||||
|
||||
// Small and large values always in exponential notation
|
||||
if (abs < 0.001 || abs >= 100000000) {
|
||||
if (isExponentialNotation && (abs < 0.001 || abs >= 100000000)) {
|
||||
return sign + exponentialFormat(abs);
|
||||
}
|
||||
|
||||
|
||||
// Check whether decimal or exponential notation is shorter
|
||||
|
||||
String exp = exponentialFormat(abs);
|
||||
String dec = decimalFormat(abs);
|
||||
|
||||
if (dec.length() <= exp.length())
|
||||
String dec;
|
||||
if (decimalPlaces < 0) {
|
||||
dec = decimalFormat(abs);
|
||||
} else {
|
||||
dec = decimalFormat(abs, decimalPlaces);
|
||||
}
|
||||
|
||||
if (dec.length() <= exp.length() || !isExponentialNotation)
|
||||
return sign + dec;
|
||||
else
|
||||
return sign + exp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string of the double value with suitable precision for storage.
|
||||
* The string is the shortest representation of the value including at least
|
||||
* 5 digits of precision.
|
||||
* Saves with exponential notation by default.
|
||||
*
|
||||
* @param d the value to present.
|
||||
* @param decimalPlaces the number of decimal places to save the value with.
|
||||
* @return a representation with suitable precision.
|
||||
*/
|
||||
public static String doubleToString(double d, int decimalPlaces) {
|
||||
return doubleToString(d, decimalPlaces, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string of the double value with suitable precision for storage.
|
||||
* The string is the shortest representation of the value including at least
|
||||
* 5 digits of precision.
|
||||
* Saves with exponential notation by default & decimal places based on the value's size.
|
||||
*
|
||||
* @param d the value to present.
|
||||
* @return a representation with suitable precision.
|
||||
*/
|
||||
public static String doubleToString(double d) {
|
||||
return doubleToString(d, -1, true);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -122,6 +153,16 @@ public class TextUtil {
|
||||
|
||||
return shortDecimal(value, decimals);
|
||||
}
|
||||
|
||||
/*
|
||||
* value must be positive and not zero!
|
||||
*/
|
||||
private static String decimalFormat(double value, int decimals) {
|
||||
if (value >= 10000)
|
||||
return "" + (int) (value + 0.5);
|
||||
|
||||
return shortDecimal(value, decimals);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -5,8 +5,12 @@ import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.SpinnerModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sf.openrocket.gui.util.SaveCSVWorker;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.startup.Preferences;
|
||||
@ -27,6 +31,8 @@ public class CsvOptionPanel extends JPanel {
|
||||
private final String baseClassName;
|
||||
|
||||
private final JComboBox<String> fieldSeparator;
|
||||
private final JSpinner decimalPlacesSpinner;
|
||||
private final JCheckBox exponentialNotationCheckbox;
|
||||
private final JCheckBox[] options;
|
||||
private final JComboBox<String> commentCharacter;
|
||||
|
||||
@ -48,10 +54,11 @@ public class CsvOptionPanel extends JPanel {
|
||||
|
||||
// TODO: HIGH: Rename the translation keys
|
||||
|
||||
// Field separator panel
|
||||
// Format settings panel
|
||||
panel = new JPanel(new MigLayout("fill"));
|
||||
panel.setBorder(BorderFactory.createTitledBorder(trans.get("SimExpPan.border.Fieldsep")));
|
||||
|
||||
panel.setBorder(BorderFactory.createTitledBorder(trans.get("SimExpPan.border.FormatSettings")));
|
||||
|
||||
//// Field separation
|
||||
label = new JLabel(trans.get("SimExpPan.lbl.Fieldsepstr"));
|
||||
tip = trans.get("SimExpPan.lbl.longA1") +
|
||||
trans.get("SimExpPan.lbl.longA2");
|
||||
@ -62,8 +69,25 @@ public class CsvOptionPanel extends JPanel {
|
||||
fieldSeparator.setEditable(true);
|
||||
fieldSeparator.setSelectedItem(Application.getPreferences().getString(Preferences.EXPORT_FIELD_SEPARATOR, ","));
|
||||
fieldSeparator.setToolTipText(tip);
|
||||
panel.add(fieldSeparator, "growx");
|
||||
|
||||
panel.add(fieldSeparator, "growx, wrap");
|
||||
|
||||
//// Decimal places
|
||||
label = new JLabel(trans.get("SimExpPan.lbl.DecimalPlaces"));
|
||||
label.setToolTipText(trans.get("SimExpPan.lbl.DecimalPlaces.ttip"));
|
||||
panel.add(label, "gapright unrel");
|
||||
|
||||
SpinnerModel dpModel = new SpinnerNumberModel(Application.getPreferences().getInt(Preferences.EXPORT_DECIMAL_PLACES, SaveCSVWorker.DEFAULT_DECIMAL_PLACES),
|
||||
0, 15, 1);
|
||||
decimalPlacesSpinner = new JSpinner(dpModel);
|
||||
decimalPlacesSpinner.setToolTipText(trans.get("SimExpPan.lbl.DecimalPlaces.ttip"));
|
||||
panel.add(decimalPlacesSpinner, "growx, wrap");
|
||||
|
||||
//// Exponential notation
|
||||
exponentialNotationCheckbox = new JCheckBox(trans.get("SimExpPan.lbl.ExponentialNotation"));
|
||||
exponentialNotationCheckbox.setToolTipText(trans.get("SimExpPan.lbl.ExponentialNotation.ttip"));
|
||||
exponentialNotationCheckbox.setSelected(Application.getPreferences().getBoolean(Preferences.EXPORT_EXPONENTIAL_NOTATION, true));
|
||||
panel.add(exponentialNotationCheckbox);
|
||||
|
||||
this.add(panel, "growx, wrap unrel");
|
||||
|
||||
|
||||
@ -104,6 +128,14 @@ public class CsvOptionPanel extends JPanel {
|
||||
public String getFieldSeparator() {
|
||||
return fieldSeparator.getSelectedItem().toString();
|
||||
}
|
||||
|
||||
public int getDecimalPlaces() {
|
||||
return (Integer) decimalPlacesSpinner.getValue();
|
||||
}
|
||||
|
||||
public boolean isExponentialNotation() {
|
||||
return exponentialNotationCheckbox.isSelected();
|
||||
}
|
||||
|
||||
public String getCommentCharacter() {
|
||||
return commentCharacter.getSelectedItem().toString();
|
||||
@ -118,6 +150,8 @@ public class CsvOptionPanel extends JPanel {
|
||||
*/
|
||||
public void storePreferences() {
|
||||
Application.getPreferences().putString(Preferences.EXPORT_FIELD_SEPARATOR, getFieldSeparator());
|
||||
Application.getPreferences().putInt(Preferences.EXPORT_DECIMAL_PLACES, getDecimalPlaces());
|
||||
Application.getPreferences().putBoolean(Preferences.EXPORT_EXPONENTIAL_NOTATION, isExponentialNotation());
|
||||
Application.getPreferences().putString(Preferences.EXPORT_COMMENT_CHARACTER, getCommentCharacter());
|
||||
for (int i = 0; i < options.length; i++) {
|
||||
Application.getPreferences().putBoolean("csvOptions." + baseClassName + "." + i, options[i].isSelected());
|
||||
|
@ -212,6 +212,8 @@ public class SimulationExportPanel extends JPanel {
|
||||
|
||||
String commentChar = csvOptions.getCommentCharacter();
|
||||
String fieldSep = csvOptions.getFieldSeparator();
|
||||
int decimalPlaces = csvOptions.getDecimalPlaces();
|
||||
boolean isExponentialNotation = csvOptions.isExponentialNotation();
|
||||
boolean simulationComment = csvOptions.getSelectionOption(OPTION_SIMULATION_COMMENTS);
|
||||
boolean fieldComment = csvOptions.getSelectionOption(OPTION_FIELD_DESCRIPTIONS);
|
||||
boolean eventComment = csvOptions.getSelectionOption(OPTION_FLIGHT_EVENTS);
|
||||
@ -245,8 +247,8 @@ public class SimulationExportPanel extends JPanel {
|
||||
}
|
||||
|
||||
|
||||
SaveCSVWorker.export(file, simulation, branch, fieldTypes, fieldUnits, fieldSep,
|
||||
commentChar, simulationComment, fieldComment, eventComment,
|
||||
SaveCSVWorker.export(file, simulation, branch, fieldTypes, fieldUnits, fieldSep, decimalPlaces,
|
||||
isExponentialNotation, commentChar, simulationComment, fieldComment, eventComment,
|
||||
SwingUtilities.getWindowAncestor(this));
|
||||
}
|
||||
|
||||
|
@ -238,6 +238,8 @@ public class SimulationExportPanel extends JPanel {
|
||||
|
||||
String commentChar = csvOptions.getCommentCharacter();
|
||||
String fieldSep = csvOptions.getFieldSeparator();
|
||||
int decimalPlaces = csvOptions.getDecimalPlaces();
|
||||
boolean isExponentialNotation = csvOptions.isExponentialNotation();
|
||||
boolean simulationComment = csvOptions.getSelectionOption(OPTION_SIMULATION_COMMENTS);
|
||||
boolean fieldComment = csvOptions.getSelectionOption(OPTION_FIELD_DESCRIPTIONS);
|
||||
boolean eventComment = csvOptions.getSelectionOption(OPTION_FLIGHT_EVENTS);
|
||||
@ -269,10 +271,10 @@ public class SimulationExportPanel extends JPanel {
|
||||
} else if (fieldSep.equals(TAB)) {
|
||||
fieldSep = "\t";
|
||||
}
|
||||
|
||||
|
||||
SaveCSVWorker.export(file, simulation, branch, fieldTypes, fieldUnits, fieldSep,
|
||||
commentChar, simulationComment, fieldComment, eventComment,
|
||||
|
||||
|
||||
SaveCSVWorker.export(file, simulation, branch, fieldTypes, fieldUnits, fieldSep, decimalPlaces,
|
||||
isExponentialNotation, commentChar, simulationComment, fieldComment, eventComment,
|
||||
SwingUtilities.getWindowAncestor(this));
|
||||
|
||||
return true;
|
||||
|
@ -23,6 +23,7 @@ import net.sf.openrocket.util.BugException;
|
||||
public class SaveCSVWorker extends SwingWorker<Void, Void> {
|
||||
|
||||
private static final int BYTES_PER_FIELD_PER_POINT = 7;
|
||||
public static final int DEFAULT_DECIMAL_PLACES = 3;
|
||||
|
||||
private final File file;
|
||||
private final Simulation simulation;
|
||||
@ -30,6 +31,8 @@ public class SaveCSVWorker extends SwingWorker<Void, Void> {
|
||||
private final FlightDataType[] fields;
|
||||
private final Unit[] units;
|
||||
private final String fieldSeparator;
|
||||
private final int decimalPlaces;
|
||||
private final boolean isExponentialNotation;
|
||||
private final String commentStarter;
|
||||
private final boolean simulationComments;
|
||||
private final boolean fieldComments;
|
||||
@ -37,14 +40,17 @@ public class SaveCSVWorker extends SwingWorker<Void, Void> {
|
||||
|
||||
|
||||
public SaveCSVWorker(File file, Simulation simulation, FlightDataBranch branch,
|
||||
FlightDataType[] fields, Unit[] units, String fieldSeparator, String commentStarter,
|
||||
boolean simulationComments, boolean fieldComments, boolean eventComments) {
|
||||
FlightDataType[] fields, Unit[] units, String fieldSeparator, int decimalPlaces,
|
||||
boolean isExponentialNotation, String commentStarter, boolean simulationComments,
|
||||
boolean fieldComments, boolean eventComments) {
|
||||
this.file = file;
|
||||
this.simulation = simulation;
|
||||
this.branch = branch;
|
||||
this.fields = fields;
|
||||
this.units = units;
|
||||
this.fieldSeparator = fieldSeparator;
|
||||
this.decimalPlaces = decimalPlaces;
|
||||
this.isExponentialNotation = isExponentialNotation;
|
||||
this.commentStarter = commentStarter;
|
||||
this.simulationComments = simulationComments;
|
||||
this.fieldComments = fieldComments;
|
||||
@ -72,7 +78,7 @@ public class SaveCSVWorker extends SwingWorker<Void, Void> {
|
||||
};
|
||||
|
||||
try {
|
||||
CSVExport.exportCSV(os, simulation, branch, fields, units, fieldSeparator,
|
||||
CSVExport.exportCSV(os, simulation, branch, fields, units, fieldSeparator, decimalPlaces, isExponentialNotation,
|
||||
commentStarter, simulationComments, fieldComments, eventComments);
|
||||
} finally {
|
||||
try {
|
||||
@ -83,8 +89,14 @@ public class SaveCSVWorker extends SwingWorker<Void, Void> {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static boolean export(File file, Simulation simulation, FlightDataBranch branch,
|
||||
FlightDataType[] fields, Unit[] units, String fieldSeparator,
|
||||
String commentStarter, boolean simulationComments,
|
||||
boolean fieldComments, boolean eventComments, Window parent) {
|
||||
return export(file, simulation, branch, fields, units, fieldSeparator, DEFAULT_DECIMAL_PLACES, true,
|
||||
commentStarter, simulationComments, fieldComments, eventComments, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports a CSV file using a progress dialog if necessary.
|
||||
@ -92,14 +104,14 @@ public class SaveCSVWorker extends SwingWorker<Void, Void> {
|
||||
* @return <code>true</code> if the save was successful, <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean export(File file, Simulation simulation, FlightDataBranch branch,
|
||||
FlightDataType[] fields, Unit[] units, String fieldSeparator, String commentStarter,
|
||||
boolean simulationComments, boolean fieldComments, boolean eventComments,
|
||||
Window parent) {
|
||||
FlightDataType[] fields, Unit[] units, String fieldSeparator, int decimalPlaces,
|
||||
boolean isExponentialNotation, String commentStarter, boolean simulationComments,
|
||||
boolean fieldComments, boolean eventComments, Window parent) {
|
||||
|
||||
|
||||
SaveCSVWorker worker = new SaveCSVWorker(file, simulation, branch, fields, units,
|
||||
fieldSeparator, commentStarter, simulationComments, fieldComments,
|
||||
eventComments);
|
||||
fieldSeparator, decimalPlaces, isExponentialNotation, commentStarter, simulationComments,
|
||||
fieldComments, eventComments);
|
||||
|
||||
if (!SwingWorkerDialog.runWorker(parent, "Exporting flight data",
|
||||
"Writing " + file.getName() + "...", worker)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user