From 34279641c9b64295d0661fd39a0ee2c68583f3b5 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Sat, 11 Jun 2022 03:40:10 +0200 Subject: [PATCH] Add decimal places and exponential notation option in sim export --- core/resources/l10n/messages.properties | 6 ++- .../src/net/sf/openrocket/file/CSVExport.java | 20 ++++----- core/src/net/sf/openrocket/util/TextUtil.java | 27 +++++++++--- .../gui/components/CsvOptionPanel.java | 41 ++++++++++++++++--- .../gui/components/SimulationExportPanel.java | 6 ++- .../gui/simulation/SimulationExportPanel.java | 10 +++-- .../sf/openrocket/gui/util/SaveCSVWorker.java | 32 ++++++++++----- 7 files changed, 104 insertions(+), 38 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 95b8960d0..99a6ee242 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -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.StorageSettings = Storage settings SimExpPan.lbl.Fieldsepstr = Field separator string: SimExpPan.lbl.longA1 = The string used to separate the fields in the exported file.
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 diff --git a/core/src/net/sf/openrocket/file/CSVExport.java b/core/src/net/sf/openrocket/file/CSVExport.java index 7d66dfe42..042ae77c0 100644 --- a/core/src/net/sf/openrocket/file/CSVExport.java +++ b/core/src/net/sf/openrocket/file/CSVExport.java @@ -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,12 +135,7 @@ public class CSVExport { // Store CSV line for (int i = 0; i < fields.length; i++) { double value = fieldValues.get(i).get(pos); - // The latitude and longitude fields need a bit more accurate formatting - if (fields[i] == FlightDataType.TYPE_LATITUDE || fields[i] == FlightDataType.TYPE_LONGITUDE) { - writer.print(TextUtil.doubleToString(units[i].toUnit(value), 5)); - } else { - 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); diff --git a/core/src/net/sf/openrocket/util/TextUtil.java b/core/src/net/sf/openrocket/util/TextUtil.java index ffed25a90..c39affaba 100644 --- a/core/src/net/sf/openrocket/util/TextUtil.java +++ b/core/src/net/sf/openrocket/util/TextUtil.java @@ -47,9 +47,11 @@ public class TextUtil { * 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, int decimalPlaces) { + public static String doubleToString(double d, int decimalPlaces, boolean isExponentialNotation) { // Check for special cases if (MathUtil.equals(d, 0)) return "0"; @@ -68,7 +70,7 @@ public class TextUtil { 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); } @@ -81,22 +83,37 @@ public class TextUtil { dec = decimalFormat(abs, decimalPlaces); } - if (dec.length() <= exp.length()) + 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 final String doubleToString(double d) { - return doubleToString(d, -1); + public static String doubleToString(double d) { + return doubleToString(d, -1, true); } diff --git a/swing/src/net/sf/openrocket/gui/components/CsvOptionPanel.java b/swing/src/net/sf/openrocket/gui/components/CsvOptionPanel.java index 5a121d9ad..631992d44 100644 --- a/swing/src/net/sf/openrocket/gui/components/CsvOptionPanel.java +++ b/swing/src/net/sf/openrocket/gui/components/CsvOptionPanel.java @@ -5,6 +5,9 @@ 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.l10n.Translator; @@ -27,6 +30,8 @@ public class CsvOptionPanel extends JPanel { private final String baseClassName; private final JComboBox fieldSeparator; + private final JSpinner decimalPlacesSpinner; + private final JCheckBox exponentialNotationCheckbox; private final JCheckBox[] options; private final JComboBox commentCharacter; @@ -48,10 +53,11 @@ public class CsvOptionPanel extends JPanel { // TODO: HIGH: Rename the translation keys - // Field separator panel + // Storage 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.StorageSettings"))); + + //// Field separation label = new JLabel(trans.get("SimExpPan.lbl.Fieldsepstr")); tip = trans.get("SimExpPan.lbl.longA1") + trans.get("SimExpPan.lbl.longA2"); @@ -62,8 +68,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(3, 0, 15, 1); + decimalPlacesSpinner = new JSpinner(dpModel); + decimalPlacesSpinner.setToolTipText(trans.get("SimExpPan.lbl.DecimalPlaces.ttip")); + panel.add(decimalPlacesSpinner, "growx, wrap"); + // TODO: preferences + action + + //// Exponential notation + exponentialNotationCheckbox = new JCheckBox(trans.get("SimExpPan.lbl.ExponentialNotation")); + exponentialNotationCheckbox.setToolTipText(trans.get("SimExpPan.lbl.ExponentialNotation.ttip")); + panel.add(exponentialNotationCheckbox); + // TODO: preferences + action + this.add(panel, "growx, wrap unrel"); @@ -104,6 +127,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(); diff --git a/swing/src/net/sf/openrocket/gui/components/SimulationExportPanel.java b/swing/src/net/sf/openrocket/gui/components/SimulationExportPanel.java index 4d2c54bff..9ad4e3820 100644 --- a/swing/src/net/sf/openrocket/gui/components/SimulationExportPanel.java +++ b/swing/src/net/sf/openrocket/gui/components/SimulationExportPanel.java @@ -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)); } diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationExportPanel.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationExportPanel.java index f6236b5aa..ad6172ffb 100644 --- a/swing/src/net/sf/openrocket/gui/simulation/SimulationExportPanel.java +++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationExportPanel.java @@ -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; diff --git a/swing/src/net/sf/openrocket/gui/util/SaveCSVWorker.java b/swing/src/net/sf/openrocket/gui/util/SaveCSVWorker.java index 342d2c17d..06c1e4944 100644 --- a/swing/src/net/sf/openrocket/gui/util/SaveCSVWorker.java +++ b/swing/src/net/sf/openrocket/gui/util/SaveCSVWorker.java @@ -23,6 +23,7 @@ import net.sf.openrocket.util.BugException; public class SaveCSVWorker extends SwingWorker { private static final int BYTES_PER_FIELD_PER_POINT = 7; + private static final int DEFAULT_DECIMAL_PLACES = 3; private final File file; private final Simulation simulation; @@ -30,6 +31,8 @@ public class SaveCSVWorker extends SwingWorker { 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 { 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 { }; 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 { } 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 { * @return true if the save was successful, false 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)) {