From 447a025545c98bbb92418cae6d9a7eb94b7d54dc Mon Sep 17 00:00:00 2001 From: SiboVG Date: Wed, 28 Dec 2022 01:43:28 +0100 Subject: [PATCH 1/6] Improve tooltip text for flight event icons --- .../openrocket/gui/plot/SimulationPlot.java | 80 +++++++++++++------ 1 file changed, 56 insertions(+), 24 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java b/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java index 1714fbd6f..26e093282 100644 --- a/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java +++ b/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java @@ -286,32 +286,19 @@ public class SimulationPlot { } XYSeries ser = collection.getSeries(series); String name = ser.getDescription(); + // Extract the unit from the last part of the series description, between parenthesis Matcher m = Pattern.compile(".*\\((.*?)\\)").matcher(name); - String unit_y = ""; + String unitY = ""; if (m.find()) { - unit_y = m.group(1); + unitY = m.group(1); } - String unit_x = domainUnit.getUnit(); - String ord_end = "th"; // Ordinal number ending (1'st', 2'nd'...) - if (item % 10 == 1) - ord_end = "st"; - else if (item % 10 == 2) - ord_end = "nd"; - else if (item % 10 == 3) - ord_end = "rd"; - double data_y = dataset.getYValue(series, item); - double data_x = dataset.getXValue(series, item); - DecimalFormat df_y = DecimalFormatter.df(data_y, 2, false); - DecimalFormat df_x = DecimalFormatter.df(data_x, 2, false); - return String.format("" + - "%s
" + - "Y: %s %s
" + - "X: %s %s
" + - "%d%s sample" + - "", - name, df_y.format(data_y), unit_y, - df_x.format(data_x), unit_x, item, ord_end); + String unitX = domainUnit.getUnit(); + + double dataY = dataset.getYValue(series, item); + double dataX = dataset.getXValue(series, item); + + return formatSampleTooltip(name, dataX, unitX, dataY, unitY, item); } }; @@ -364,6 +351,42 @@ public class SimulationPlot { return chart; } + private String formatSampleTooltip(String dataName, double dataX, String unitX, double dataY, String unitY, int sampleIdx, boolean addYValue) { + String ord_end = "th"; // Ordinal number ending (1'st', 2'nd'...) + if (sampleIdx % 10 == 1) { + ord_end = "st"; + } else if (sampleIdx % 10 == 2) { + ord_end = "nd"; + } else if (sampleIdx % 10 == 3) { + ord_end = "rd"; + } + + DecimalFormat df_y = DecimalFormatter.df(dataY, 2, false); + DecimalFormat df_x = DecimalFormatter.df(dataX, 2, false); + + StringBuilder sb = new StringBuilder(); + sb.append(String.format("" + + "%s
", dataName)); + + if (addYValue) { + sb.append(String.format("Y: %s %s
", df_y.format(dataY), unitY)); + } + + sb.append(String.format("X: %s %s
" + + "%d%s sample" + + "", df_x.format(dataX), unitX, sampleIdx, ord_end)); + + return sb.toString(); + } + + private String formatSampleTooltip(String dataName, double dataX, String unitX, double dataY, String unitY, int sampleIdx) { + return formatSampleTooltip(dataName, dataX, unitX, dataY, unitY, sampleIdx, true); + } + + private String formatSampleTooltip(String dataName, double dataX, String unitX, int sampleIdx) { + return formatSampleTooltip(dataName, dataX, unitX, 0, "", sampleIdx, false); + } + private String getLabel(FlightDataType type, Unit unit) { String name = type.getName(); if (unit != null && !UnitGroup.UNITS_NONE.contains(unit) && @@ -466,13 +489,13 @@ public class SimulationPlot { for (int i = 0; i < eventTimes.size(); i++) { double t = eventTimes.get(i); - String event = eventLabels.get(i); Image image = eventImages.get(i); if (image == null) continue; double xcoord = domainInterpolator.getValue(t); + for (int index = 0; index < config.getTypeCount(); index++) { FlightDataType type = config.getType(index); List range = mainBranch.get(type); @@ -490,9 +513,18 @@ public class SimulationPlot { xcoord = config.getDomainAxisUnit().toUnit(xcoord); ycoord = config.getUnit(index).toUnit(ycoord); + // Get the sample index of the flight event. Because this can be an interpolation between two samples, + // take the closest sample. + final int sampleIdx; + Optional closestSample = time.stream() + .min(Comparator.comparingDouble(sample -> Math.abs(sample - t))); + sampleIdx = closestSample.map(time::indexOf).orElse(-1); + + String tooltipText = formatSampleTooltip(eventLabels.get(i), xcoord, config.getDomainAxisUnit().getUnit(), sampleIdx) ; + XYImageAnnotation annotation = new XYImageAnnotation(xcoord, ycoord, image, RectangleAnchor.CENTER); - annotation.setToolTipText(event); + annotation.setToolTipText(tooltipText); plot.addAnnotation(annotation); } } From 7b88cb468e5b6a242ede9f6dabbb338872d8917e Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 29 Dec 2022 23:29:52 +0100 Subject: [PATCH 2/6] Add option to switch (time) flight event markers to icons --- core/resources/l10n/messages.properties | 5 ++ .../sf/openrocket/startup/Preferences.java | 1 + .../openrocket/gui/plot/SimulationPlot.java | 9 ++- .../gui/simulation/SimulationPlotPanel.java | 63 +++++++++++++++++-- 4 files changed, 72 insertions(+), 6 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 1b94f637b..fb8cf3d99 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -719,6 +719,11 @@ simplotpanel.RIGHT_NAME = Right simplotpanel.CUSTOM = Custom SimulationPlotPanel.error.noPlotSelected = Please add one or more variables to plot on the Y-axis. SimulationPlotPanel.error.noPlotSelected.title = Nothing to plot +simplotpanel.MarkerStyle.lbl.MarkerStyle = Marker style: +simplotpanel.MarkerStyle.lbl.MarkerStyle.ttip = Style of the flight event marker (how it's drawn in the simulation plot) +simplotpanel.MarkerStyle.btn.VerticalMarker = Vertical marker +simplotpanel.MarkerStyle.btn.Icon = Icon +simplotpanel.MarkerStyle.OnlyInTime = Only available for time domain, other domains only support icon markers ! Component add buttons compaddbuttons.AxialStage = Stage diff --git a/core/src/net/sf/openrocket/startup/Preferences.java b/core/src/net/sf/openrocket/startup/Preferences.java index 26b9b1095..f9c31bd82 100644 --- a/core/src/net/sf/openrocket/startup/Preferences.java +++ b/core/src/net/sf/openrocket/startup/Preferences.java @@ -76,6 +76,7 @@ public abstract class Preferences implements ChangeSource { public static final String PREFERRED_THRUST_CURVE_MOTOR_NODE = "preferredThrustCurveMotors"; private static final String AUTO_OPEN_LAST_DESIGN = "AUTO_OPEN_LAST_DESIGN"; private static final String OPEN_LEFTMOST_DESIGN_TAB = "OPEN_LEFTMOST_DESIGN_TAB"; + public static final String MARKER_STYLE_ICON = "MARKER_STYLE_ICON"; private static final String SHOW_MARKERS = "SHOW_MARKERS"; private static final String SHOW_ROCKSIM_FORMAT_WARNING = "SHOW_ROCKSIM_FORMAT_WARNING"; diff --git a/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java b/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java index 26e093282..7c5219c4a 100644 --- a/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java +++ b/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java @@ -20,9 +20,12 @@ import java.util.regex.Pattern; import net.sf.openrocket.document.Simulation; import net.sf.openrocket.gui.simulation.SimulationPlotPanel; +import net.sf.openrocket.gui.util.SwingPreferences; import net.sf.openrocket.simulation.FlightDataBranch; import net.sf.openrocket.simulation.FlightDataType; import net.sf.openrocket.simulation.FlightEvent; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.startup.Preferences; import net.sf.openrocket.unit.Unit; import net.sf.openrocket.unit.UnitGroup; import net.sf.openrocket.util.LinearInterpolator; @@ -65,6 +68,8 @@ import org.jfree.ui.TextAnchor; */ @SuppressWarnings("serial") public class SimulationPlot { + private static final SwingPreferences preferences = (SwingPreferences) Application.getPreferences(); + private static final float PLOT_STROKE_WIDTH = 1.5f; @@ -79,7 +84,7 @@ public class SimulationPlot { private final LegendItems legendItems; - int branchCount; + private int branchCount; void setShowPoints(boolean showPoints) { for (ModifiedXYItemRenderer r : renderers) { @@ -457,7 +462,7 @@ public class SimulationPlot { } // Plot the markers - if (config.getDomainAxisType() == FlightDataType.TYPE_TIME) { + if (config.getDomainAxisType() == FlightDataType.TYPE_TIME && !preferences.getBoolean(Preferences.MARKER_STYLE_ICON, false)) { double markerWidth = 0.01 * plot.getDomainAxis().getUpperBound(); // Domain time is plotted as vertical markers diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java index da516379c..c28cc606c 100644 --- a/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java +++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java @@ -9,12 +9,15 @@ import java.util.Arrays; import java.util.EnumSet; import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JComboBox; +import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; @@ -29,11 +32,13 @@ import net.sf.openrocket.gui.plot.PlotConfiguration; import net.sf.openrocket.gui.plot.SimulationPlotDialog; import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.gui.util.Icons; +import net.sf.openrocket.gui.util.SwingPreferences; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.simulation.FlightDataBranch; import net.sf.openrocket.simulation.FlightDataType; import net.sf.openrocket.simulation.FlightEvent; import net.sf.openrocket.startup.Application; +import net.sf.openrocket.startup.Preferences; import net.sf.openrocket.unit.Unit; import net.sf.openrocket.util.Utils; import net.sf.openrocket.gui.widgets.SelectColorButton; @@ -47,6 +52,7 @@ public class SimulationPlotPanel extends JPanel { private static final long serialVersionUID = -2227129713185477998L; private static final Translator trans = Application.getTranslator(); + private static final SwingPreferences preferences = (SwingPreferences) Application.getPreferences(); // TODO: LOW: Should these be somewhere else? public static final int AUTO = -1; @@ -201,7 +207,7 @@ public class SimulationPlotPanel extends JPanel { typeSelectorPanel = new JPanel(new MigLayout("gapy rel")); JScrollPane scroll = new JScrollPane(typeSelectorPanel); - this.add(scroll, "spany 2, height 10px, wmin 400lp, grow 100, gapright para"); + this.add(scroll, "spany 3, height 10px, wmin 400lp, grow 100, gapright para"); //// Flight events @@ -244,10 +250,46 @@ public class SimulationPlotPanel extends JPanel { eventTableModel.fireTableDataChanged(); } }); - this.add(button, "gapleft para, gapright para, growx, sizegroup buttons, wrap para"); - - + this.add(button, "gapleft para, gapright para, growx, sizegroup buttons, wrap"); + + //// Style event marker + JLabel styleEventMarker = new JLabel(trans.get("simplotpanel.MarkerStyle.lbl.MarkerStyle")); + JRadioButton radioVerticalMarker = new JRadioButton(trans.get("simplotpanel.MarkerStyle.btn.VerticalMarker")); + JRadioButton radioIcon = new JRadioButton(trans.get("simplotpanel.MarkerStyle.btn.Icon")); + ButtonGroup bg = new ButtonGroup(); + bg.add(radioVerticalMarker); + bg.add(radioIcon); + + boolean useIcon = preferences.getBoolean(Preferences.MARKER_STYLE_ICON, false); + if (useIcon) { + radioIcon.setSelected(true); + } else { + radioVerticalMarker.setSelected(true); + } + + radioIcon.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (modifying > 0) + return; + preferences.putBoolean(Preferences.MARKER_STYLE_ICON, radioIcon.isSelected()); + } + }); + + domainTypeSelector.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + updateStyleEventWidgets(styleEventMarker, radioVerticalMarker, radioIcon); + } + }); + updateStyleEventWidgets(styleEventMarker, radioVerticalMarker, radioIcon); + + this.add(styleEventMarker, "split 3, growx"); + this.add(radioVerticalMarker); + this.add(radioIcon, "wrap para"); + + //// New Y axis plot type button = new SelectColorButton(trans.get("simplotpanel.but.NewYaxisplottype")); button.addActionListener(new ActionListener() { @@ -322,6 +364,19 @@ public class SimulationPlotPanel extends JPanel { */ updatePlots(); } + + private void updateStyleEventWidgets(JLabel styleEventMarker, JRadioButton radioVerticalMarker, JRadioButton radioIcon) { + if (modifying > 0) + return; + FlightDataType type = (FlightDataType) domainTypeSelector.getSelectedItem(); + boolean isTime = type == FlightDataType.TYPE_TIME; + styleEventMarker.setEnabled(isTime); + radioVerticalMarker.setEnabled(isTime); + radioIcon.setEnabled(isTime); + styleEventMarker.setToolTipText(isTime ? trans.get("simplotpanel.MarkerStyle.lbl.MarkerStyle.ttip") : trans.get("simplotpanel.MarkerStyle.OnlyInTime")); + radioVerticalMarker.setToolTipText(isTime ? null : trans.get("simplotpanel.MarkerStyle.OnlyInTime")); + radioIcon.setToolTipText(isTime ? null : trans.get("simplotpanel.MarkerStyle.OnlyInTime")); + } public JDialog doPlot(Window parent) { if (configuration.getTypeCount() == 0) { From 29a737f38b6a425431b651156b00a98d8579fcaf Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 29 Dec 2022 23:55:48 +0100 Subject: [PATCH 3/6] Remove redundant boxing --- .../net/sf/openrocket/util/LinearInterpolator.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/net/sf/openrocket/util/LinearInterpolator.java b/core/src/net/sf/openrocket/util/LinearInterpolator.java index e16726bb5..8a9e786ac 100644 --- a/core/src/net/sf/openrocket/util/LinearInterpolator.java +++ b/core/src/net/sf/openrocket/util/LinearInterpolator.java @@ -82,7 +82,7 @@ public class LinearInterpolator implements Cloneable { if ( y1 != null ) { // Wow, x was a key in the map. Such luck. - return y1.doubleValue(); + return y1; } // we now know that x is not in the map, so we need to find the lower and higher keys. @@ -96,16 +96,16 @@ public class LinearInterpolator implements Cloneable { Double firstKey = sortMap.firstKey(); // x is smaller than the first entry in the map. - if ( x < firstKey.doubleValue() ) { + if ( x < firstKey) { y1 = sortMap.get(firstKey); - return y1.doubleValue(); + return y1; } // floor key is the largest key smaller than x - since we have at least one key, // and x>=firstKey, we know that floorKey != null. Double floorKey = sortMap.subMap(firstKey, x).lastKey(); - x1 = floorKey.doubleValue(); + x1 = floorKey; y1 = sortMap.get(floorKey); // Now we need to find the key that is greater or equal to x @@ -113,16 +113,16 @@ public class LinearInterpolator implements Cloneable { // Check if x is bigger than all the entries. if ( tailMap.isEmpty() ) { - return y1.doubleValue(); + return y1; } Double ceilKey = tailMap.firstKey(); // Check if x is bigger than all the entries. if ( ceilKey == null ) { - return y1.doubleValue(); + return y1; } - x2 = ceilKey.doubleValue(); + x2 = ceilKey; y2 = sortMap.get(ceilKey); return (x - x1)/(x2-x1) * (y2-y1) + y1; From 6cdc2d920e7665c6bf104afbfc2c7227d13e002c Mon Sep 17 00:00:00 2001 From: SiboVG Date: Fri, 30 Dec 2022 18:32:37 +0100 Subject: [PATCH 4/6] Fix icon marker plot for multiple branches --- .../openrocket/gui/plot/SimulationPlot.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java b/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java index 7c5219c4a..66eeb2d46 100644 --- a/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java +++ b/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java @@ -94,6 +94,7 @@ public class SimulationPlot { void setShowBranch(int branch) { XYPlot plot = (XYPlot) chart.getPlot(); + plot.clearAnnotations(); int datasetcount = plot.getDatasetCount(); for (int i = 0; i < datasetcount; i++) { int seriescount = ((XYSeriesCollection) plot.getDataset(i)).getSeriesCount(); @@ -400,9 +401,13 @@ public class SimulationPlot { return name; } - private void drawDomainMarkers(int stage) { + /** + * Draw the domain markers for a certain branch. Draws all the markers if the branch is -1. + * @param branch branch to draw, or -1 to draw all + */ + private void drawDomainMarkers(int branch) { XYPlot plot = chart.getXYPlot(); - FlightDataBranch mainBranch = simulation.getSimulatedData().getBranch(0); + FlightDataBranch dataBranch = simulation.getSimulatedData().getBranch(Math.max(branch, 0)); // Clear existing domain markers plot.clearDomainMarkers(); @@ -420,7 +425,7 @@ public class SimulationPlot { Color color = null; Image image = null; for (EventDisplayInfo info : eventList) { - if (stage >= 0 && stage != info.stage) { + if (branch >= 0 && branch != info.stage) { continue; } @@ -484,11 +489,9 @@ public class SimulationPlot { } } - } else { - - // Other domains are plotted as image annotations - List time = mainBranch.get(FlightDataType.TYPE_TIME); - List domain = mainBranch.get(config.getDomainAxisType()); + } else { // Other domains are plotted as image annotations + List time = dataBranch.get(FlightDataType.TYPE_TIME); + List domain = dataBranch.get(config.getDomainAxisType()); LinearInterpolator domainInterpolator = new LinearInterpolator(time, domain); @@ -503,7 +506,7 @@ public class SimulationPlot { for (int index = 0; index < config.getTypeCount(); index++) { FlightDataType type = config.getType(index); - List range = mainBranch.get(type); + List range = dataBranch.get(type); LinearInterpolator rangeInterpolator = new LinearInterpolator(time, range); // Image annotations are not supported on the right-side axis From c374f616b99679824cfb1940f0f61e275c116e32 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Fri, 30 Dec 2022 20:32:33 +0100 Subject: [PATCH 5/6] Fix icon marker plotting for branch == -1 --- .../openrocket/gui/plot/SimulationPlot.java | 263 ++++++++++-------- 1 file changed, 144 insertions(+), 119 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java b/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java index 66eeb2d46..951b75d6c 100644 --- a/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java +++ b/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java @@ -94,7 +94,6 @@ public class SimulationPlot { void setShowBranch(int branch) { XYPlot plot = (XYPlot) chart.getPlot(); - plot.clearAnnotations(); int datasetcount = plot.getDatasetCount(); for (int i = 0; i < datasetcount; i++) { int seriescount = ((XYSeriesCollection) plot.getDataset(i)).getSeriesCount(); @@ -409,132 +408,158 @@ public class SimulationPlot { XYPlot plot = chart.getXYPlot(); FlightDataBranch dataBranch = simulation.getSimulatedData().getBranch(Math.max(branch, 0)); - // Clear existing domain markers + // Clear existing domain markers and annotations plot.clearDomainMarkers(); + plot.clearAnnotations(); - // Construct domain marker lists collapsing based on time. - - List eventTimes = new ArrayList(); - List eventLabels = new ArrayList(); - List eventColors = new ArrayList(); - List eventImages = new ArrayList(); - { - HashSet typeSet = new HashSet(); - double prevTime = -100; - String text = null; - Color color = null; - Image image = null; - for (EventDisplayInfo info : eventList) { - if (branch >= 0 && branch != info.stage) { - continue; - } - - double t = info.time; - FlightEvent.Type type = info.event.getType(); - - if (Math.abs(t - prevTime) <= 0.05) { - - if (!typeSet.contains(type)) { - text = text + ", " + type.toString(); - color = EventGraphics.getEventColor(type); - image = EventGraphics.getEventImage(type); - typeSet.add(type); - } - - } else { - - if (text != null) { - eventTimes.add(prevTime); - eventLabels.add(text); - eventColors.add(color); - eventImages.add(image); - } - prevTime = t; - text = type.toString(); - color = EventGraphics.getEventColor(type); - image = EventGraphics.getEventImage(type); - typeSet.clear(); - typeSet.add(type); - } - - } - if (text != null) { - eventTimes.add(prevTime); - eventLabels.add(text); - eventColors.add(color); - eventImages.add(image); - } - } + // Store flight event information + List eventTimes = new ArrayList<>(); + List eventLabels = new ArrayList<>(); + List eventColors = new ArrayList<>(); + List eventImages = new ArrayList<>(); // Plot the markers if (config.getDomainAxisType() == FlightDataType.TYPE_TIME && !preferences.getBoolean(Preferences.MARKER_STYLE_ICON, false)) { - double markerWidth = 0.01 * plot.getDomainAxis().getUpperBound(); - - // Domain time is plotted as vertical markers - for (int i = 0; i < eventTimes.size(); i++) { - double t = eventTimes.get(i); - String event = eventLabels.get(i); - Color color = eventColors.get(i); - - ValueMarker m = new ValueMarker(t); - m.setLabel(event); - m.setPaint(color); - m.setLabelPaint(color); - m.setAlpha(0.7f); - m.setLabelFont(new Font("Dialog", Font.PLAIN, 13)); - plot.addDomainMarker(m); - - if (t > plot.getDomainAxis().getUpperBound() - markerWidth) { - plot.setDomainAxis(new PresetNumberAxis(plot.getDomainAxis().getLowerBound(), t + markerWidth)); - } - } + fillEventLists(branch, eventTimes, eventLabels, eventColors, eventImages); + plotVerticalMarkers(plot, eventTimes, eventLabels, eventColors); } else { // Other domains are plotted as image annotations - List time = dataBranch.get(FlightDataType.TYPE_TIME); - List domain = dataBranch.get(config.getDomainAxisType()); - - LinearInterpolator domainInterpolator = new LinearInterpolator(time, domain); - - for (int i = 0; i < eventTimes.size(); i++) { - double t = eventTimes.get(i); - Image image = eventImages.get(i); - - if (image == null) - continue; - - double xcoord = domainInterpolator.getValue(t); - - for (int index = 0; index < config.getTypeCount(); index++) { - FlightDataType type = config.getType(index); - List range = dataBranch.get(type); - - LinearInterpolator rangeInterpolator = new LinearInterpolator(time, range); - // Image annotations are not supported on the right-side axis - // TODO: LOW: Can this be achieved by JFreeChart? - if (filled.getAxis(index) != SimulationPlotPanel.LEFT) { - continue; - } - - double ycoord = rangeInterpolator.getValue(t); - - // Convert units - xcoord = config.getDomainAxisUnit().toUnit(xcoord); - ycoord = config.getUnit(index).toUnit(ycoord); - - // Get the sample index of the flight event. Because this can be an interpolation between two samples, - // take the closest sample. - final int sampleIdx; - Optional closestSample = time.stream() - .min(Comparator.comparingDouble(sample -> Math.abs(sample - t))); - sampleIdx = closestSample.map(time::indexOf).orElse(-1); - - String tooltipText = formatSampleTooltip(eventLabels.get(i), xcoord, config.getDomainAxisUnit().getUnit(), sampleIdx) ; - - XYImageAnnotation annotation = - new XYImageAnnotation(xcoord, ycoord, image, RectangleAnchor.CENTER); - annotation.setToolTipText(tooltipText); - plot.addAnnotation(annotation); + if (branch == -1) { + // For icon markers, we need to do the plotting separately, otherwise you can have icon markers from e.g. + // branch 1 be plotted on branch 0 + for (int b = 0; b < simulation.getSimulatedData().getBranchCount(); b++) { + fillEventLists(b, eventTimes, eventLabels, eventColors, eventImages); + dataBranch = simulation.getSimulatedData().getBranch(b); + plotIconMarkers(plot, dataBranch, eventTimes, eventLabels, eventImages); + eventTimes.clear(); + eventLabels.clear(); + eventColors.clear(); + eventImages.clear(); } + } else { + fillEventLists(branch, eventTimes, eventLabels, eventColors, eventImages); + plotIconMarkers(plot, dataBranch, eventTimes, eventLabels, eventImages); + } + } + } + + private void fillEventLists(int branch, List eventTimes, List eventLabels, + List eventColors, List eventImages) { + HashSet typeSet = new HashSet<>(); + double prevTime = -100; + String text = null; + Color color = null; + Image image = null; + for (EventDisplayInfo info : eventList) { + if (branch >= 0 && branch != info.stage) { + continue; + } + + double t = info.time; + FlightEvent.Type type = info.event.getType(); + + if (Math.abs(t - prevTime) <= 0.05) { + if (!typeSet.contains(type)) { + text = text + ", " + type.toString(); + color = EventGraphics.getEventColor(type); + image = EventGraphics.getEventImage(type); + typeSet.add(type); + } + + } else { + if (text != null) { + eventTimes.add(prevTime); + eventLabels.add(text); + eventColors.add(color); + eventImages.add(image); + } + prevTime = t; + text = type.toString(); + color = EventGraphics.getEventColor(type); + image = EventGraphics.getEventImage(type); + typeSet.clear(); + typeSet.add(type); + } + + } + if (text != null) { + eventTimes.add(prevTime); + eventLabels.add(text); + eventColors.add(color); + eventImages.add(image); + } + } + + private static void plotVerticalMarkers(XYPlot plot, List eventTimes, List eventLabels, List eventColors) { + double markerWidth = 0.01 * plot.getDomainAxis().getUpperBound(); + + // Domain time is plotted as vertical markers + for (int i = 0; i < eventTimes.size(); i++) { + double t = eventTimes.get(i); + String event = eventLabels.get(i); + Color color = eventColors.get(i); + + ValueMarker m = new ValueMarker(t); + m.setLabel(event); + m.setPaint(color); + m.setLabelPaint(color); + m.setAlpha(0.7f); + m.setLabelFont(new Font("Dialog", Font.PLAIN, 13)); + plot.addDomainMarker(m); + + if (t > plot.getDomainAxis().getUpperBound() - markerWidth) { + plot.setDomainAxis(new PresetNumberAxis(plot.getDomainAxis().getLowerBound(), t + markerWidth)); + } + } + } + + private void plotIconMarkers(XYPlot plot, FlightDataBranch dataBranch, List eventTimes, + List eventLabels, List eventImages) { + List time = dataBranch.get(FlightDataType.TYPE_TIME); + List domain = dataBranch.get(config.getDomainAxisType()); + + LinearInterpolator domainInterpolator = new LinearInterpolator(time, domain); + + for (int i = 0; i < eventTimes.size(); i++) { + double t = eventTimes.get(i); + Image image = eventImages.get(i); + + if (image == null) { + continue; + } + + double xcoord = domainInterpolator.getValue(t); + + for (int index = 0; index < config.getTypeCount(); index++) { + FlightDataType type = config.getType(index); + List range = dataBranch.get(type); + + LinearInterpolator rangeInterpolator = new LinearInterpolator(time, range); + // Image annotations are not supported on the right-side axis + // TODO: LOW: Can this be achieved by JFreeChart? + if (filled.getAxis(index) != SimulationPlotPanel.LEFT) { + continue; + } + + double ycoord = rangeInterpolator.getValue(t); + + // Convert units + xcoord = config.getDomainAxisUnit().toUnit(xcoord); + ycoord = config.getUnit(index).toUnit(ycoord); + + // Get the sample index of the flight event. Because this can be an interpolation between two samples, + // take the closest sample. + final int sampleIdx; + Optional closestSample = time.stream() + .min(Comparator.comparingDouble(sample -> Math.abs(sample - t))); + sampleIdx = closestSample.map(time::indexOf).orElse(-1); + + String tooltipText = formatSampleTooltip(eventLabels.get(i), xcoord, config.getDomainAxisUnit().getUnit(), sampleIdx) ; + + XYImageAnnotation annotation = + new XYImageAnnotation(xcoord, ycoord, image, RectangleAnchor.CENTER); + annotation.setToolTipText(tooltipText); + plot.addAnnotation(annotation); } } } From a3252e3d152c982afc7eaf9ffb12c304c7ec8ec9 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Sun, 1 Jan 2023 05:22:36 +0100 Subject: [PATCH 6/6] Change "Vertical marker" to "Vertical line" --- core/resources/l10n/messages.properties | 2 +- swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index fb8cf3d99..1d70c562b 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -721,7 +721,7 @@ SimulationPlotPanel.error.noPlotSelected = Please add one or more variables to p SimulationPlotPanel.error.noPlotSelected.title = Nothing to plot simplotpanel.MarkerStyle.lbl.MarkerStyle = Marker style: simplotpanel.MarkerStyle.lbl.MarkerStyle.ttip = Style of the flight event marker (how it's drawn in the simulation plot) -simplotpanel.MarkerStyle.btn.VerticalMarker = Vertical marker +simplotpanel.MarkerStyle.btn.VerticalMarker = Vertical line simplotpanel.MarkerStyle.btn.Icon = Icon simplotpanel.MarkerStyle.OnlyInTime = Only available for time domain, other domains only support icon markers diff --git a/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java b/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java index 951b75d6c..57f45c09c 100644 --- a/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java +++ b/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java @@ -421,7 +421,7 @@ public class SimulationPlot { // Plot the markers if (config.getDomainAxisType() == FlightDataType.TYPE_TIME && !preferences.getBoolean(Preferences.MARKER_STYLE_ICON, false)) { fillEventLists(branch, eventTimes, eventLabels, eventColors, eventImages); - plotVerticalMarkers(plot, eventTimes, eventLabels, eventColors); + plotVerticalLineMarkers(plot, eventTimes, eventLabels, eventColors); } else { // Other domains are plotted as image annotations if (branch == -1) { @@ -490,10 +490,10 @@ public class SimulationPlot { } } - private static void plotVerticalMarkers(XYPlot plot, List eventTimes, List eventLabels, List eventColors) { + private static void plotVerticalLineMarkers(XYPlot plot, List eventTimes, List eventLabels, List eventColors) { double markerWidth = 0.01 * plot.getDomainAxis().getUpperBound(); - // Domain time is plotted as vertical markers + // Domain time is plotted as vertical lines for (int i = 0; i < eventTimes.size(); i++) { double t = eventTimes.get(i); String event = eventLabels.get(i);