1 package net.sf.openrocket.gui.dialogs.optimization;
5 import java.awt.Window;
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
8 import java.util.ArrayList;
9 import java.util.Iterator;
10 import java.util.List;
13 import javax.swing.BorderFactory;
14 import javax.swing.JButton;
15 import javax.swing.JDialog;
16 import javax.swing.JLabel;
17 import javax.swing.JPanel;
19 import net.miginfocom.swing.MigLayout;
20 import net.sf.openrocket.gui.components.StyledLabel;
21 import net.sf.openrocket.l10n.Translator;
22 import net.sf.openrocket.logging.LogHelper;
23 import net.sf.openrocket.optimization.general.Point;
24 import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
25 import net.sf.openrocket.optimization.rocketoptimization.SimulationModifier;
26 import net.sf.openrocket.startup.Application;
27 import net.sf.openrocket.unit.Unit;
28 import net.sf.openrocket.unit.UnitGroup;
29 import net.sf.openrocket.unit.Value;
30 import net.sf.openrocket.util.GUIUtil;
31 import net.sf.openrocket.util.LinearInterpolator;
32 import net.sf.openrocket.util.MathUtil;
34 import org.jfree.chart.ChartFactory;
35 import org.jfree.chart.ChartPanel;
36 import org.jfree.chart.JFreeChart;
37 import org.jfree.chart.axis.AxisLocation;
38 import org.jfree.chart.axis.NumberAxis;
39 import org.jfree.chart.labels.CustomXYToolTipGenerator;
40 import org.jfree.chart.plot.PlotOrientation;
41 import org.jfree.chart.plot.XYPlot;
42 import org.jfree.chart.renderer.PaintScale;
43 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
44 import org.jfree.chart.renderer.xy.XYShapeRenderer;
45 import org.jfree.chart.title.PaintScaleLegend;
46 import org.jfree.data.xy.DefaultXYZDataset;
47 import org.jfree.data.xy.XYSeries;
48 import org.jfree.data.xy.XYSeriesCollection;
49 import org.jfree.ui.RectangleEdge;
52 * A class that plots the path of an optimization.
54 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
56 public class OptimizationPlotDialog extends JDialog {
57 private static final LogHelper log = Application.getLogger();
58 private static final Translator trans = Application.getTranslator();
60 // FIXME: Set range to optimization range
62 private static final LinearInterpolator RED = new LinearInterpolator(
63 new double[] { 0.0, 1.0 }, new double[] { 0.0, 1.0 }
65 private static final LinearInterpolator GREEN = new LinearInterpolator(
66 new double[] { 0.0, 1.0 }, new double[] { 0.0, 0.0 }
68 private static final LinearInterpolator BLUE = new LinearInterpolator(
69 new double[] { 0.0, 1.0 }, new double[] { 1.0, 0.0 }
72 private static final Color OUT_OF_DOMAIN_COLOR = Color.BLACK;
74 private static final Color PATH_COLOR = new Color(220, 0, 0);
77 public OptimizationPlotDialog(List<Point> path, Map<Point, FunctionEvaluationData> evaluations,
78 List<SimulationModifier> modifiers, OptimizableParameter parameter, UnitGroup stabilityUnit, Window parent) {
79 super(parent, trans.get("title"), ModalityType.APPLICATION_MODAL);
82 JPanel panel = new JPanel(new MigLayout("fill"));
85 if (modifiers.size() == 1) {
86 chart = create1DPlot(path, evaluations, modifiers, parameter, stabilityUnit);
87 } else if (modifiers.size() == 2) {
88 chart = create2DPlot(path, evaluations, modifiers, parameter, stabilityUnit);
90 throw new IllegalArgumentException("Invalid dimensionality, dim=" + modifiers.size());
92 chart.setBorder(BorderFactory.createLineBorder(Color.BLACK));
93 panel.add(chart, "span, grow, wrap para");
96 JLabel label = new StyledLabel(trans.get("lbl.zoomInstructions"), -2);
100 JButton close = new JButton(trans.get("button.close"));
101 close.addActionListener(new ActionListener() {
103 public void actionPerformed(ActionEvent e) {
104 OptimizationPlotDialog.this.setVisible(false);
107 panel.add(close, "right");
112 GUIUtil.setDisposableDialogOptions(this, close);
118 * Create a 1D plot of the optimization path.
120 private ChartPanel create1DPlot(List<Point> path, Map<Point, FunctionEvaluationData> evaluations,
121 List<SimulationModifier> modifiers, OptimizableParameter parameter, UnitGroup stabilityUnit) {
123 SimulationModifier modX = modifiers.get(0);
124 Unit xUnit = modX.getUnitGroup().getDefaultUnit();
125 Unit yUnit = parameter.getUnitGroup().getDefaultUnit();
127 // Create the optimization path (with autosort)
128 XYSeries series = new XYSeries(trans.get("plot1d.series"), true, true);
129 List<String> tooltips = new ArrayList<String>();
130 for (Point p : evaluations.keySet()) {
131 FunctionEvaluationData data = evaluations.get(p);
133 if (data.getParameterValue() != null) {
134 Value[] state = data.getState();
135 series.add(xUnit.toUnit(state[0].getValue()), yUnit.toUnit(data.getParameterValue().getValue()));
136 tooltips.add(getTooltip(data, parameter));
139 log.error("Could not find evaluation data for point " + p);
144 String xLabel = modX.getRelatedObject().toString() + ": " + modX.getName() + " / " + xUnit.getUnit();
145 String yLabel = parameter.getName() + " / " + yUnit.getUnit();
147 JFreeChart chart = ChartFactory.createXYLineChart(
148 trans.get("plot1d.title"),
152 PlotOrientation.VERTICAL,
158 XYLineAndShapeRenderer lineRenderer = new XYLineAndShapeRenderer(true, true);
159 lineRenderer.setBaseShapesVisible(true);
160 lineRenderer.setSeriesShapesFilled(0, false);
161 //lineRenderer.setSeriesShape(0, shapeRenderer.getBaseShape());
162 lineRenderer.setSeriesOutlinePaint(0, PATH_COLOR);
163 lineRenderer.setSeriesPaint(0, PATH_COLOR);
164 lineRenderer.setUseOutlinePaint(true);
165 CustomXYToolTipGenerator tooltipGenerator = new CustomXYToolTipGenerator();
166 tooltipGenerator.addToolTipSeries(tooltips);
167 lineRenderer.setBaseToolTipGenerator(tooltipGenerator);
169 XYPlot plot = chart.getXYPlot();
171 plot.setDataset(0, new XYSeriesCollection(series));
172 plot.setRenderer(lineRenderer);
176 return new ChartPanel(chart);
180 * Create a 2D plot of the optimization path.
182 private ChartPanel create2DPlot(List<Point> path, Map<Point, FunctionEvaluationData> evaluations,
183 List<SimulationModifier> modifiers, OptimizableParameter parameter, UnitGroup stabilityUnit) {
185 Unit parameterUnit = parameter.getUnitGroup().getDefaultUnit();
187 SimulationModifier modX = modifiers.get(0);
188 SimulationModifier modY = modifiers.get(1);
190 Unit xUnit = modX.getUnitGroup().getDefaultUnit();
191 Unit yUnit = modY.getUnitGroup().getDefaultUnit();
193 // Create the optimization path dataset
194 XYSeries series = new XYSeries(trans.get("plot2d.path"), false, true);
195 List<String> pathTooltips = new ArrayList<String>();
196 for (Point p : path) {
197 FunctionEvaluationData data = evaluations.get(p);
199 Value[] state = data.getState();
200 series.add(xUnit.toUnit(state[0].getValue()), yUnit.toUnit(state[1].getValue()));
201 pathTooltips.add(getTooltip(data, parameter));
203 log.error("Could not find evaluation data for point " + p);
208 // Create evaluations dataset
209 double min = Double.POSITIVE_INFINITY;
210 double max = Double.NEGATIVE_INFINITY;
211 double[][] evals = new double[3][evaluations.size()];
212 List<String> evalTooltips = new ArrayList<String>();
214 Iterator<FunctionEvaluationData> iterator = evaluations.values().iterator();
215 for (int i = 0; i < evaluations.size(); i++) {
216 FunctionEvaluationData data = iterator.next();
217 Value param = data.getParameterValue();
220 value = parameterUnit.toUnit(data.getParameterValue().getValue());
225 Value[] state = data.getState();
226 evals[0][i] = xUnit.toUnit(state[0].getValue());
227 evals[1][i] = yUnit.toUnit(state[1].getValue());
237 evalTooltips.add(getTooltip(data, parameter));
239 DefaultXYZDataset evalDataset = new DefaultXYZDataset();
240 evalDataset.addSeries(trans.get("plot2d.evals"), evals);
244 String xLabel = modX.getRelatedObject().toString() + ": " + modX.getName() + " / " + xUnit.getUnit();
245 String yLabel = modY.getRelatedObject().toString() + ": " + modY.getName() + " / " + yUnit.getUnit();
247 JFreeChart chart = ChartFactory.createXYLineChart(
248 trans.get("plot2d.title"),
253 PlotOrientation.VERTICAL,
259 chart.getXYPlot().getDomainAxis().setRange(xUnit.toUnit(modX.getMinValue()),
260 xUnit.toUnit(modX.getMaxValue()));
262 chart.getXYPlot().getRangeAxis().setRange(yUnit.toUnit(modY.getMinValue()),
263 yUnit.toUnit(modY.getMaxValue()));
266 PaintScale paintScale = new GradientScale(min, max);
268 XYShapeRenderer shapeRenderer = new XYShapeRenderer();
269 shapeRenderer.setPaintScale(paintScale);
270 shapeRenderer.setUseFillPaint(true);
271 CustomXYToolTipGenerator tooltipGenerator = new CustomXYToolTipGenerator();
272 tooltipGenerator.addToolTipSeries(evalTooltips);
273 shapeRenderer.setBaseToolTipGenerator(tooltipGenerator);
276 shapeRenderer.getLegendItem(0, 0);
279 XYLineAndShapeRenderer lineRenderer = new XYLineAndShapeRenderer(true, true);
280 lineRenderer.setBaseShapesVisible(true);
281 lineRenderer.setSeriesShapesFilled(0, false);
282 lineRenderer.setSeriesShape(0, shapeRenderer.getBaseShape());
283 lineRenderer.setSeriesOutlinePaint(0, PATH_COLOR);
284 lineRenderer.setSeriesPaint(0, PATH_COLOR);
285 lineRenderer.setUseOutlinePaint(true);
286 tooltipGenerator = new CustomXYToolTipGenerator();
287 tooltipGenerator.addToolTipSeries(pathTooltips);
288 lineRenderer.setBaseToolTipGenerator(tooltipGenerator);
291 XYPlot plot = chart.getXYPlot();
293 plot.setDataset(0, new XYSeriesCollection(series));
294 plot.setRenderer(lineRenderer);
296 plot.setDataset(1, evalDataset);
297 plot.setRenderer(1, shapeRenderer);
301 NumberAxis numberAxis = new NumberAxis(parameter.getName() + " / " + parameterUnit.getUnit());
302 PaintScaleLegend scale = new PaintScaleLegend(paintScale, numberAxis);
303 scale.setPosition(RectangleEdge.RIGHT);
304 scale.setMargin(4.0D, 4.0D, 40.0D, 4.0D);
305 scale.setAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
306 chart.addSubtitle(scale);
309 return new ChartPanel(chart);
314 private String getTooltip(FunctionEvaluationData data, OptimizableParameter parameter) {
315 String ttip = "<html>";
316 if (data.getParameterValue() != null) {
317 ttip += parameter.getName() + ": " +
318 parameter.getUnitGroup().getDefaultUnit().toStringUnit(data.getParameterValue().getValue());
321 if (data.getDomainReference() != null) {
322 ttip += trans.get("plot.ttip.stability") + " " + data.getDomainReference();
327 private class GradientScale implements PaintScale {
329 private final double min;
330 private final double max;
332 public GradientScale(double min, double max) {
338 public Paint getPaint(double value) {
339 if (Double.isNaN(value)) {
340 return OUT_OF_DOMAIN_COLOR;
343 value = MathUtil.map(value, min, max, 0.0, 1.0);
344 value = MathUtil.clamp(value, 0.0, 1.0);
346 float r = (float) RED.getValue(value);
347 float g = (float) GREEN.getValue(value);
348 float b = (float) BLUE.getValue(value);
350 return new Color(r, g, b);
354 public double getLowerBound() {
359 public double getUpperBound() {