1 package net.sf.openrocket.gui.plot;
4 import java.awt.Window;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.ActionListener;
9 import javax.swing.BorderFactory;
10 import javax.swing.JButton;
11 import javax.swing.JDialog;
12 import javax.swing.JPanel;
14 import net.miginfocom.swing.MigLayout;
15 import net.sf.openrocket.document.Simulation;
16 import net.sf.openrocket.simulation.FlightDataBranch;
17 import net.sf.openrocket.unit.Unit;
18 import net.sf.openrocket.unit.UnitGroup;
19 import net.sf.openrocket.util.GUIUtil;
21 import org.jfree.chart.ChartFactory;
22 import org.jfree.chart.ChartPanel;
23 import org.jfree.chart.JFreeChart;
24 import org.jfree.chart.axis.NumberAxis;
25 import org.jfree.chart.plot.PlotOrientation;
26 import org.jfree.chart.plot.ValueMarker;
27 import org.jfree.chart.plot.XYPlot;
28 import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
29 import org.jfree.chart.title.TextTitle;
30 import org.jfree.data.xy.XYSeries;
31 import org.jfree.data.xy.XYSeriesCollection;
33 public class PlotDialog extends JDialog {
35 private PlotDialog(Window parent, Simulation simulation, PlotConfiguration config) {
36 super(parent, "Flight data plot");
37 this.setModalityType(ModalityType.DOCUMENT_MODAL);
40 // Fill the auto-selections
41 FlightDataBranch branch = simulation.getSimulatedData().getBranch(0);
42 PlotConfiguration filled = config.fillAutoAxes(branch);
43 List<Axis> axes = filled.getAllAxes();
46 // Create the data series for both axes
47 XYSeriesCollection[] data = new XYSeriesCollection[2];
48 data[0] = new XYSeriesCollection();
49 data[1] = new XYSeriesCollection();
52 // Get the domain axis type
53 final FlightDataBranch.Type domainType = filled.getDomainAxisType();
54 final Unit domainUnit = filled.getDomainAxisUnit();
55 if (domainType == null) {
56 throw new IllegalArgumentException("Domain axis type not specified.");
58 List<Double> x = branch.get(domainType);
61 // Get plot length (ignore trailing NaN's)
62 int typeCount = filled.getTypeCount();
64 for (int i=0; i<typeCount; i++) {
65 FlightDataBranch.Type type = filled.getType(i);
66 List<Double> y = branch.get(type);
68 for (int j = dataLength; j < y.size(); j++) {
69 if (!Double.isNaN(y.get(j)) && !Double.isInfinite(y.get(j)))
73 dataLength = Math.min(dataLength, x.size());
76 // Create the XYSeries objects from the flight data and store into the collections
77 String[] axisLabel = new String[2];
78 for (int i = 0; i < typeCount; i++) {
80 FlightDataBranch.Type type = filled.getType(i);
81 Unit unit = filled.getUnit(i);
82 int axis = filled.getAxis(i);
83 String name = getLabel(type, unit);
85 // Store data in provided units
86 List<Double> y = branch.get(type);
87 XYSeries series = new XYSeries(name, false, true);
88 for (int j=0; j < dataLength; j++) {
89 series.add(domainUnit.toUnit(x.get(j)), unit.toUnit(y.get(j)));
91 data[axis].addSeries(series);
94 if (axisLabel[axis] == null)
95 axisLabel[axis] = type.getName();
97 axisLabel[axis] += "; " + type.getName();
101 // Create the chart using the factory to get all default settings
102 JFreeChart chart = ChartFactory.createXYLineChart(
107 PlotOrientation.VERTICAL,
113 chart.addSubtitle(new TextTitle(config.getName()));
115 // Add the data and formatting to the plot
116 XYPlot plot = chart.getXYPlot();
118 for (int i=0; i<2; i++) {
119 // Check whether axis has any data
120 if (data[i].getSeriesCount() > 0) {
121 // Create and set axis
122 double min = axes.get(i).getMinValue();
123 double max = axes.get(i).getMaxValue();
124 NumberAxis axis = new PresetNumberAxis(min, max);
125 axis.setLabel(axisLabel[i]);
126 // axis.setRange(axes.get(i).getMinValue(), axes.get(i).getMaxValue());
127 plot.setRangeAxis(axisno, axis);
129 // Add data and map to the axis
130 plot.setDataset(axisno, data[i]);
131 plot.setRenderer(axisno, new StandardXYItemRenderer());
132 plot.mapDatasetToRangeAxis(axisno, axisno);
137 plot.getDomainAxis().setLabel(getLabel(domainType,domainUnit));
138 plot.addDomainMarker(new ValueMarker(0));
139 plot.addRangeMarker(new ValueMarker(0));
144 JPanel panel = new JPanel(new MigLayout("fill"));
147 ChartPanel chartPanel = new ChartPanel(chart,
153 chartPanel.setMouseWheelEnabled(true);
154 chartPanel.setEnforceFileExtensions(true);
155 chartPanel.setInitialDelay(500);
157 chartPanel.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
159 panel.add(chartPanel, "grow, wrap 20lp");
161 JButton button = new JButton("Close");
162 button.addActionListener(new ActionListener() {
164 public void actionPerformed(ActionEvent e) {
165 PlotDialog.this.dispose();
168 panel.add(button, "right");
170 this.setLocationByPlatform(true);
172 GUIUtil.installEscapeCloseOperation(this);
173 GUIUtil.setDefaultButton(button);
177 private String getLabel(FlightDataBranch.Type type, Unit unit) {
178 String name = type.getName();
179 if (unit != null && !UnitGroup.UNITS_NONE.contains(unit) &&
180 !UnitGroup.UNITS_COEFFICIENT.contains(unit) && unit.getUnit().length() > 0)
181 name += " ("+unit.getUnit() + ")";
187 private class PresetNumberAxis extends NumberAxis {
188 private final double min;
189 private final double max;
191 public PresetNumberAxis(double min, double max) {
198 protected void autoAdjustRange() {
199 this.setRange(min, max);
205 * Static method that shows a plot with the specified parameters.
207 * @param parent the parent window, which will be blocked.
208 * @param simulation the simulation to plot.
209 * @param config the configuration of the plot.
211 public static void showPlot(Window parent, Simulation simulation, PlotConfiguration config) {
212 new PlotDialog(parent, simulation, config).setVisible(true);