diff --git a/core/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java b/core/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java index a47d827d1..c07c5edfc 100644 --- a/core/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java +++ b/core/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java @@ -48,6 +48,7 @@ import javax.swing.event.TreeSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableColumnModel; +import javax.swing.table.TableRowSorter; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; @@ -96,7 +97,6 @@ import net.sf.openrocket.util.TextUtil; import com.itextpdf.text.Font; - /** * General rocket optimization dialog. * @@ -105,45 +105,41 @@ import com.itextpdf.text.Font; public class GeneralOptimizationDialog extends JDialog { private static final LogHelper log = Application.getLogger(); private static final Translator trans = Application.getTranslator(); - + private static final Collator collator = Collator.getInstance(); - - + private static final String GOAL_MAXIMIZE = trans.get("goal.maximize"); private static final String GOAL_MINIMIZE = trans.get("goal.minimize"); private static final String GOAL_SEEK = trans.get("goal.seek"); - + private static final String START_TEXT = trans.get("btn.start"); private static final String STOP_TEXT = trans.get("btn.stop"); - - - + private final List optimizationParameters = new ArrayList(); private final Map> simulationModifiers = new HashMap>(); - + private final OpenRocketDocument baseDocument; private OpenRocketDocument documentCopy; - - + private final JButton addButton; private final JButton removeButton; private final JButton removeAllButton; - + private final ParameterSelectionTableModel selectedModifierTableModel; private final JTable selectedModifierTable; private final DescriptionArea selectedModifierDescription; private final SimulationModifierTree availableModifierTree; - - private final JComboBox simulationSelectionCombo; - private final JComboBox optimizationParameterCombo; - - private final JComboBox optimizationGoalCombo; + + private final JComboBox simulationSelectionCombo; + private final JComboBox optimizationParameterCombo; + + private final JComboBox optimizationGoalCombo; private final JSpinner optimizationGoalSpinner; private final UnitSelector optimizationGoalUnitSelector; private final DoubleModel optimizationSeekValue; - + private DoubleModel minimumStability; private DoubleModel maximumStability; private final JCheckBox minimumStabilitySelected; @@ -152,68 +148,64 @@ public class GeneralOptimizationDialog extends JDialog { private final JCheckBox maximumStabilitySelected; private final JSpinner maximumStabilitySpinner; private final UnitSelector maximumStabilityUnitSelector; - + private final JLabel bestValueLabel; private final JLabel stepCountLabel; private final JLabel evaluationCountLabel; private final JLabel stepSizeLabel; - + private final RocketFigure figure; private final JToggleButton startButton; private final JButton plotButton; private final JButton saveButton; - + private final JButton applyButton; private final JButton resetButton; private final JButton closeButton; - + private final List selectedModifiers = new ArrayList(); - + /** List of components to disable while optimization is running */ private final List disableComponents = new ArrayList(); - + /** Whether optimization is currently running or not */ private boolean running = false; /** The optimization worker that is running */ private OptimizationWorker worker = null; - - + private double bestValue = Double.NaN; private Unit bestValueUnit = Unit.NOUNIT; private int stepCount = 0; private int evaluationCount = 0; private double stepSize = 0; - + private final Map evaluationHistory = new LinkedHashMap(); private final List optimizationPath = new LinkedList(); - - + private boolean updating = false; - - + /** * Sole constructor. * - * @param document the document - * @param parent the parent window + * @param document the document + * @param parent the parent window */ public GeneralOptimizationDialog(OpenRocketDocument document, Window parent) { super(parent, trans.get("title")); - + this.baseDocument = document; this.documentCopy = document.copy(); - + loadOptimizationParameters(); loadSimulationModifiers(); - + JPanel sub; JLabel label; JScrollPane scroll; String tip; - + JPanel panel = new JPanel(new MigLayout("fill")); - - + ChangeListener clearHistoryChangeListener = new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { @@ -226,47 +218,48 @@ public class GeneralOptimizationDialog extends JDialog { clearHistory(); } }; - - - - //// Selected modifiers table - + + // // Selected modifiers table + selectedModifierTableModel = new ParameterSelectionTableModel(); selectedModifierTable = new JTable(selectedModifierTableModel); selectedModifierTable.setDefaultRenderer(Double.class, new DoubleCellRenderer()); selectedModifierTable.setRowSelectionAllowed(true); selectedModifierTable.setColumnSelectionAllowed(false); selectedModifierTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - + TableRowSorter sorter = new TableRowSorter(selectedModifierTableModel); + sorter.setComparator(0, new SimulationModifierComparator()); + selectedModifierTable.setRowSorter( sorter ); + // Make sure spinner editor fits into the cell height selectedModifierTable.setRowHeight(new JSpinner().getPreferredSize().height - 4); - + selectedModifierTable.setDefaultEditor(Double.class, new DoubleCellEditor()); selectedModifierTable.setDefaultEditor(Unit.class, new UnitCellEditor() { @Override protected UnitGroup getUnitGroup(Unit value, int row, int column) { - return selectedModifiers.get(row).getUnitGroup(); - } - }); - + return selectedModifiers.get(row).getUnitGroup(); + } + }); + disableComponents.add(selectedModifierTable); - + selectedModifierTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - updateComponents(); - } - }); - + @Override + public void valueChanged(ListSelectionEvent e) { + updateComponents(); + } + }); + // Set column widths TableColumnModel columnModel = selectedModifierTable.getColumnModel(); columnModel.getColumn(0).setPreferredWidth(150); columnModel.getColumn(1).setPreferredWidth(40); columnModel.getColumn(2).setPreferredWidth(40); columnModel.getColumn(3).setPreferredWidth(40); - + scroll = new JScrollPane(selectedModifierTable); - + label = new StyledLabel(trans.get("lbl.paramsToOptimize"), Style.BOLD); disableComponents.add(label); panel.add(label, "split 3, flowy"); @@ -274,12 +267,10 @@ public class GeneralOptimizationDialog extends JDialog { selectedModifierDescription = new DescriptionArea(2, -3); disableComponents.add(selectedModifierDescription); panel.add(selectedModifierDescription, "growx"); - - - - //// Add/remove buttons + + // // Add/remove buttons sub = new JPanel(new MigLayout("fill")); - + addButton = new JButton(Chars.LEFT_ARROW + " " + trans.get("btn.add") + " "); addButton.setToolTipText(trans.get("btn.add.ttip")); addButton.addActionListener(new ActionListener() { @@ -296,7 +287,7 @@ public class GeneralOptimizationDialog extends JDialog { }); disableComponents.add(addButton); sub.add(addButton, "wrap para, sg button"); - + removeButton = new JButton(" " + trans.get("btn.remove") + " " + Chars.RIGHT_ARROW); removeButton.setToolTipText(trans.get("btn.remove.ttip")); removeButton.addActionListener(new ActionListener() { @@ -313,7 +304,7 @@ public class GeneralOptimizationDialog extends JDialog { }); disableComponents.add(removeButton); sub.add(removeButton, "wrap para*2, sg button"); - + removeAllButton = new JButton(trans.get("btn.removeAll")); removeAllButton.setToolTipText(trans.get("btn.removeAll.ttip")); removeAllButton.addActionListener(new ActionListener() { @@ -328,20 +319,18 @@ public class GeneralOptimizationDialog extends JDialog { }); disableComponents.add(removeAllButton); sub.add(removeAllButton, "wrap para, sg button"); - + panel.add(sub); - - - - //// Available modifier tree + + // // Available modifier tree availableModifierTree = new SimulationModifierTree(documentCopy.getRocket(), simulationModifiers, selectedModifiers); availableModifierTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { - @Override - public void valueChanged(TreeSelectionEvent e) { - updateComponents(); - } - }); - + @Override + public void valueChanged(TreeSelectionEvent e) { + updateComponents(); + } + }); + // Handle double-click availableModifierTree.addMouseListener(new MouseAdapter() { @Override @@ -357,113 +346,98 @@ public class GeneralOptimizationDialog extends JDialog { } } }); - + disableComponents.add(availableModifierTree); scroll = new JScrollPane(availableModifierTree); label = new StyledLabel(trans.get("lbl.availableParams"), Style.BOLD); disableComponents.add(label); panel.add(label, "split 2, flowy"); panel.add(scroll, "width 300lp, height 200lp, grow, wrap para*2"); - - - - - //// Optimization options sub-panel - + + // // Optimization options sub-panel + sub = new JPanel(new MigLayout("fill")); TitledBorder border = BorderFactory.createTitledBorder(trans.get("lbl.optimizationOpts")); GUIUtil.changeFontStyle(border, Font.BOLD); sub.setBorder(border); disableComponents.add(sub); - - - //// Simulation to optimize - + + // // Simulation to optimize + label = new JLabel(trans.get("lbl.optimizeSim")); tip = trans.get("lbl.optimizeSim.ttip"); label.setToolTipText(tip); disableComponents.add(label); sub.add(label, ""); - - simulationSelectionCombo = new JComboBox(); + + simulationSelectionCombo = new JComboBox(); simulationSelectionCombo.setToolTipText(tip); populateSimulations(); simulationSelectionCombo.addActionListener(clearHistoryActionListener); disableComponents.add(simulationSelectionCombo); sub.add(simulationSelectionCombo, "growx, wrap unrel"); - - - - //// Value to optimize + + // // Value to optimize label = new JLabel(trans.get("lbl.optimizeValue")); tip = trans.get("lbl.optimizeValue.ttip"); label.setToolTipText(tip); disableComponents.add(label); sub.add(label, ""); - - optimizationParameterCombo = new JComboBox(); + + optimizationParameterCombo = new JComboBox(); optimizationParameterCombo.setToolTipText(tip); populateParameters(); optimizationParameterCombo.addActionListener(clearHistoryActionListener); disableComponents.add(optimizationParameterCombo); sub.add(optimizationParameterCombo, "growx, wrap unrel"); - - - - //// Optimization goal + + // // Optimization goal label = new JLabel(trans.get("lbl.optimizeGoal")); tip = trans.get("lbl.optimizeGoal"); label.setToolTipText(tip); disableComponents.add(label); sub.add(label, ""); - - optimizationGoalCombo = new JComboBox(new String[] { GOAL_MAXIMIZE, GOAL_MINIMIZE, GOAL_SEEK }); + + optimizationGoalCombo = new JComboBox(new String[] { GOAL_MAXIMIZE, GOAL_MINIMIZE, GOAL_SEEK }); optimizationGoalCombo.setToolTipText(tip); optimizationGoalCombo.setEditable(false); optimizationGoalCombo.addActionListener(clearHistoryActionListener); disableComponents.add(optimizationGoalCombo); sub.add(optimizationGoalCombo, "growx"); - - - //// Optimization custom value + + // // Optimization custom value optimizationSeekValue = new DoubleModel(0, UnitGroup.UNITS_NONE); optimizationSeekValue.addChangeListener(clearHistoryChangeListener); - + optimizationGoalSpinner = new JSpinner(optimizationSeekValue.getSpinnerModel()); tip = trans.get("lbl.optimizeGoalValue.ttip"); optimizationGoalSpinner.setToolTipText(tip); optimizationGoalSpinner.setEditor(new SpinnerEditor(optimizationGoalSpinner)); disableComponents.add(optimizationGoalSpinner); sub.add(optimizationGoalSpinner, "width 30lp"); - + optimizationGoalUnitSelector = new UnitSelector(optimizationSeekValue); optimizationGoalUnitSelector.setToolTipText(tip); disableComponents.add(optimizationGoalUnitSelector); sub.add(optimizationGoalUnitSelector, "width 20lp, wrap unrel"); - - + panel.add(sub, "grow"); - - - - //// Required stability sub-panel - + + // // Required stability sub-panel + sub = new JPanel(new MigLayout("fill")); border = BorderFactory.createTitledBorder(trans.get("lbl.requireStability")); GUIUtil.changeFontStyle(border, Font.BOLD); sub.setBorder(border); disableComponents.add(sub); - - - + double ref = CaliberUnit.calculateCaliber(baseDocument.getRocket()); minimumStability = new DoubleModel(ref, UnitGroup.stabilityUnits(ref)); maximumStability = new DoubleModel(5 * ref, UnitGroup.stabilityUnits(ref)); minimumStability.addChangeListener(clearHistoryChangeListener); maximumStability.addChangeListener(clearHistoryChangeListener); - - - //// Minimum stability + + // // Minimum stability tip = trans.get("lbl.requireMinStability.ttip"); minimumStabilitySelected = new JCheckBox(trans.get("lbl.requireMinStability")); minimumStabilitySelected.setSelected(true); @@ -476,20 +450,19 @@ public class GeneralOptimizationDialog extends JDialog { }); disableComponents.add(minimumStabilitySelected); sub.add(minimumStabilitySelected); - + minimumStabilitySpinner = new JSpinner(minimumStability.getSpinnerModel()); minimumStabilitySpinner.setToolTipText(tip); minimumStabilitySpinner.setEditor(new SpinnerEditor(minimumStabilitySpinner)); disableComponents.add(minimumStabilitySpinner); sub.add(minimumStabilitySpinner, "growx"); - + minimumStabilityUnitSelector = new UnitSelector(minimumStability); minimumStabilityUnitSelector.setToolTipText(tip); disableComponents.add(minimumStabilityUnitSelector); sub.add(minimumStabilityUnitSelector, "growx, wrap unrel"); - - - //// Maximum stability + + // // Maximum stability tip = trans.get("lbl.requireMaxStability.ttip"); maximumStabilitySelected = new JCheckBox(trans.get("lbl.requireMaxStability")); maximumStabilitySelected.setToolTipText(tip); @@ -501,85 +474,75 @@ public class GeneralOptimizationDialog extends JDialog { }); disableComponents.add(maximumStabilitySelected); sub.add(maximumStabilitySelected); - + maximumStabilitySpinner = new JSpinner(maximumStability.getSpinnerModel()); maximumStabilitySpinner.setToolTipText(tip); maximumStabilitySpinner.setEditor(new SpinnerEditor(maximumStabilitySpinner)); disableComponents.add(maximumStabilitySpinner); sub.add(maximumStabilitySpinner, "growx"); - + maximumStabilityUnitSelector = new UnitSelector(maximumStability); maximumStabilityUnitSelector.setToolTipText(tip); disableComponents.add(maximumStabilityUnitSelector); sub.add(maximumStabilityUnitSelector, "growx, wrap para"); - + // DescriptionArea desc = new DescriptionArea("Stability requirements are verified during each time step of the simulation.", - // 2, -2, false); - // desc.setViewportBorder(null); - // disableComponents.add(desc); - // sub.add(desc, "span, growx"); - - + // 2, -2, false); + // desc.setViewportBorder(null); + // disableComponents.add(desc); + // sub.add(desc, "span, growx"); + panel.add(sub, "span 2, grow, wrap para*2"); - - - - - //// Rocket figure + + // // Rocket figure figure = new RocketFigure(getSelectedSimulation().getConfiguration()); figure.setBorderPixels(1, 1); ScaleScrollPane figureScrollPane = new ScaleScrollPane(figure); figureScrollPane.setFitting(true); panel.add(figureScrollPane, "span, split, height 200lp, grow"); - - + sub = new JPanel(new MigLayout("fill")); - - + label = new JLabel(trans.get("status.bestValue")); tip = trans.get("status.bestValue.ttip"); label.setToolTipText(tip); sub.add(label, "gapright unrel"); - + bestValueLabel = new JLabel(); bestValueLabel.setToolTipText(tip); sub.add(bestValueLabel, "wmin 60lp, wrap rel"); - - + label = new JLabel(trans.get("status.stepCount")); tip = trans.get("status.stepCount.ttip"); label.setToolTipText(tip); sub.add(label, "gapright unrel"); - + stepCountLabel = new JLabel(); stepCountLabel.setToolTipText(tip); sub.add(stepCountLabel, "wrap rel"); - - + label = new JLabel(trans.get("status.evalCount")); tip = trans.get("status.evalCount.ttip"); label.setToolTipText(tip); sub.add(label, "gapright unrel"); - + evaluationCountLabel = new JLabel(); evaluationCountLabel.setToolTipText(tip); sub.add(evaluationCountLabel, "wrap rel"); - - + label = new JLabel(trans.get("status.stepSize")); tip = trans.get("status.stepSize.ttip"); label.setToolTipText(tip); sub.add(label, "gapright unrel"); - + stepSizeLabel = new JLabel(); stepSizeLabel.setToolTipText(tip); sub.add(stepSizeLabel, "wrap para"); - - - //// Start/Stop button - + + // // Start/Stop button + startButton = new JToggleButton(START_TEXT); startButton.addActionListener(new ActionListener() { @Override @@ -598,8 +561,7 @@ public class GeneralOptimizationDialog extends JDialog { } }); sub.add(startButton, "span, growx, wrap para*2"); - - + plotButton = new JButton(trans.get("btn.plotPath")); plotButton.setToolTipText(trans.get("btn.plotPath.ttip")); plotButton.addActionListener(new ActionListener() { @@ -618,8 +580,7 @@ public class GeneralOptimizationDialog extends JDialog { }); disableComponents.add(plotButton); sub.add(plotButton, "span, growx, wrap"); - - + saveButton = new JButton(trans.get("btn.save")); saveButton.setToolTipText(trans.get("btn.save.ttip")); saveButton.addActionListener(new ActionListener() { @@ -631,16 +592,11 @@ public class GeneralOptimizationDialog extends JDialog { }); disableComponents.add(saveButton); sub.add(saveButton, "span, growx"); - - - + panel.add(sub, "wrap para*2"); - - - - - //// Bottom buttons - + + // // Bottom buttons + applyButton = new JButton(trans.get("btn.apply")); applyButton.setToolTipText(trans.get("btn.apply.ttip")); applyButton.addActionListener(new ActionListener() { @@ -652,7 +608,7 @@ public class GeneralOptimizationDialog extends JDialog { }); disableComponents.add(applyButton); panel.add(applyButton, "span, split, gapright para, right"); - + resetButton = new JButton(trans.get("btn.reset")); resetButton.setToolTipText(trans.get("btn.reset.ttip")); resetButton.addActionListener(new ActionListener() { @@ -664,7 +620,7 @@ public class GeneralOptimizationDialog extends JDialog { }); disableComponents.add(resetButton); panel.add(resetButton, "gapright para, right"); - + closeButton = new JButton(trans.get("btn.close")); closeButton.setToolTipText(trans.get("btn.close.ttip")); closeButton.addActionListener(new ActionListener() { @@ -676,22 +632,19 @@ public class GeneralOptimizationDialog extends JDialog { } }); panel.add(closeButton, "right"); - - + this.add(panel); clearHistory(); updateComponents(); GUIUtil.setDisposableDialogOptions(this, null); } - - + private void startOptimization() { if (running) { log.info("Optimization already running"); return; } - - + if (selectedModifiers.isEmpty()) { JOptionPane.showMessageDialog(this, trans.get("error.selectParams.text"), trans.get("error.selectParams.title"), JOptionPane.ERROR_MESSAGE); @@ -701,24 +654,23 @@ public class GeneralOptimizationDialog extends JDialog { updating = false; return; } - - + running = true; - + // Update the button status updating = true; startButton.setSelected(true); startButton.setText(STOP_TEXT); updating = false; - + // Create a copy of the simulation (we're going to modify the original in the current thread) Simulation simulation = getSelectedSimulation(); Rocket rocketCopy = simulation.getRocket().copyWithOriginalID(); simulation = simulation.duplicateSimulation(rocketCopy); - + OptimizableParameter parameter = getSelectedParameter(); - + OptimizationGoal goal; String value = (String) optimizationGoalCombo.getSelectedItem(); if (GOAL_MAXIMIZE.equals(value)) { @@ -730,17 +682,17 @@ public class GeneralOptimizationDialog extends JDialog { } else { throw new BugException("optimizationGoalCombo had invalid value: " + value); } - + SimulationDomain domain; if (minimumStabilitySelected.isSelected() || maximumStabilitySelected.isSelected()) { double min, max; boolean minAbsolute, maxAbsolute; - + /* * Make minAbsolute/maxAbsolute consistent with each other to produce reasonable * result in plot tool tips. Yes, this is a bit ugly. */ - + // Min stability Unit unit = minimumStability.getCurrentUnit(); if (unit instanceof CaliberUnit) { @@ -750,7 +702,7 @@ public class GeneralOptimizationDialog extends JDialog { min = minimumStability.getValue(); minAbsolute = true; } - + // Max stability unit = maximumStability.getCurrentUnit(); if (unit instanceof CaliberUnit) { @@ -760,8 +712,7 @@ public class GeneralOptimizationDialog extends JDialog { max = maximumStability.getValue(); maxAbsolute = true; } - - + if (!minimumStabilitySelected.isSelected()) { min = Double.NaN; minAbsolute = maxAbsolute; @@ -770,31 +721,31 @@ public class GeneralOptimizationDialog extends JDialog { max = Double.NaN; maxAbsolute = minAbsolute; } - + domain = new StabilityDomain(min, minAbsolute, max, maxAbsolute); } else { domain = new IdentitySimulationDomain(); } - + SimulationModifier[] modifiers = selectedModifiers.toArray(new SimulationModifier[0]); - + // Create and start the background worker worker = new OptimizationWorker(simulation, parameter, goal, domain, modifiers) { @Override protected void done(OptimizationException exception) { log.info("Optimization finished, exception=" + exception, exception); - + if (exception != null) { JOptionPane.showMessageDialog(GeneralOptimizationDialog.this, - new Object[] { - trans.get("error.optimizationFailure.text"), + new Object[] { + trans.get("error.optimizationFailure.text"), exception.getLocalizedMessage() }, trans.get("error.optimizationFailure.title"), JOptionPane.ERROR_MESSAGE); } - + worker = null; stopOptimization(); - + // Disable the start/stop button for a short while after ending the simulation // to prevent accidentally starting a new optimization when trying to stop it startButton.setEnabled(false); @@ -808,7 +759,7 @@ public class GeneralOptimizationDialog extends JDialog { timer.start(); updateComponents(); } - + @Override protected void functionEvaluated(List data) { for (FunctionEvaluationData d : data) { @@ -817,31 +768,31 @@ public class GeneralOptimizationDialog extends JDialog { } updateCounters(); } - + @Override protected void optimizationStepTaken(List data) { - + // Add starting point to the path if (optimizationPath.isEmpty()) { optimizationPath.add(data.get(0).getOldPoint()); } - + // Add other points to the path for (OptimizationStepData d : data) { optimizationPath.add(d.getNewPoint()); } - + // Get function value from the latest point OptimizationStepData latest = data.get(data.size() - 1); Point newPoint = latest.getNewPoint(); - + FunctionEvaluationData pointValue = evaluationHistory.get(newPoint); if (pointValue != null && pointValue.getParameterValue() != null) { bestValue = pointValue.getParameterValue().getValue(); } else { bestValue = Double.NaN; } - + // Update the simulation Simulation sim = getSelectedSimulation(); for (int i = 0; i < newPoint.dim(); i++) { @@ -853,7 +804,7 @@ public class GeneralOptimizationDialog extends JDialog { } } figure.updateFigure(); - + // Update other counter data stepCount += data.size(); stepSize = latest.getStepSize(); @@ -861,41 +812,36 @@ public class GeneralOptimizationDialog extends JDialog { } }; worker.start(); - - + clearHistory(); - + updateComponents(); } - + private void stopOptimization() { if (!running) { log.info("Optimization not running"); return; } - + if (worker != null && worker.isAlive()) { log.info("Worker still running, interrupting it and setting to null"); worker.interrupt(); worker = null; return; } - + running = false; - + // Update the button status updating = true; startButton.setSelected(false); startButton.setText(START_TEXT); updating = false; - - + updateComponents(); } - - - - + /** * Reset the current optimization history and values. This does not reset the design. */ @@ -910,8 +856,7 @@ public class GeneralOptimizationDialog extends JDialog { updateCounters(); updateComponents(); } - - + private void applyDesign() { // TODO: MEDIUM: Apply also potential changes to simulations Rocket src = getSelectedSimulation().getRocket().copyWithOriginalID(); @@ -919,34 +864,33 @@ public class GeneralOptimizationDialog extends JDialog { try { baseDocument.startUndo(trans.get("undoText")); dest.freeze(); - + // Remove all children while (dest.getChildCount() > 0) { dest.removeChild(0); } - + // Move all children to the destination rocket while (src.getChildCount() > 0) { RocketComponent c = src.getChild(0); src.removeChild(0); dest.addChild(c); } - + } finally { dest.thaw(); baseDocument.stopUndo(); } } - - + private void resetDesign() { clearHistory(); - + documentCopy = baseDocument.copy(); - + loadOptimizationParameters(); loadSimulationModifiers(); - + // Replace selected modifiers with corresponding new modifiers List newSelected = new ArrayList(); for (SimulationModifier original : selectedModifiers) { @@ -964,38 +908,35 @@ public class GeneralOptimizationDialog extends JDialog { selectedModifiers.clear(); selectedModifiers.addAll(newSelected); selectedModifierTableModel.fireTableDataChanged(); - + // Update the available modifier tree availableModifierTree.populateTree(documentCopy.getRocket(), simulationModifiers); availableModifierTree.expandComponents(); - - + // Update selectable simulations populateSimulations(); - + // Update selectable parameters populateParameters(); - + } - - + private void populateSimulations() { String current = null; Object selection = simulationSelectionCombo.getSelectedItem(); if (selection != null) { current = selection.toString(); } - - + List> simulations = new ArrayList>(); Rocket rocket = documentCopy.getRocket(); - + for (Simulation s : documentCopy.getSimulations()) { String id = s.getConfiguration().getFlightConfigurationID(); String name = createSimulationName(s.getName(), rocket.getFlightConfigurationNameOrDescription(id)); simulations.add(new Named(s, name)); } - + for (String id : rocket.getFlightConfigurationIDs()) { if (id == null) { continue; @@ -1005,15 +946,14 @@ public class GeneralOptimizationDialog extends JDialog { String name = createSimulationName(trans.get("basicSimulationName"), rocket.getFlightConfigurationNameOrDescription(id)); simulations.add(new Named(sim, name)); } - - + Simulation sim = new Simulation(rocket); sim.getConfiguration().setFlightConfigurationID(null); String name = createSimulationName(trans.get("noSimulationName"), rocket.getFlightConfigurationNameOrDescription(null)); simulations.add(new Named(sim, name)); + - - simulationSelectionCombo.setModel(new DefaultComboBoxModel(simulations.toArray())); + simulationSelectionCombo.setModel(new DefaultComboBoxModel(simulations.toArray())); simulationSelectionCombo.setSelectedIndex(0); if (current != null) { for (int i = 0; i < simulations.size(); i++) { @@ -1024,8 +964,7 @@ public class GeneralOptimizationDialog extends JDialog { } } } - - + private void populateParameters() { String current = null; Object selection = optimizationParameterCombo.getSelectedItem(); @@ -1035,14 +974,14 @@ public class GeneralOptimizationDialog extends JDialog { // Default to apogee altitude event if it is not the first one in the list current = trans.get("MaximumAltitudeParameter.name"); } - + List> parameters = new ArrayList>(); for (OptimizableParameter p : optimizationParameters) { parameters.add(new Named(p, p.getName())); } - - optimizationParameterCombo.setModel(new DefaultComboBoxModel(parameters.toArray())); - + + optimizationParameterCombo.setModel(new DefaultComboBoxModel(parameters.toArray())); + for (int i = 0; i < parameters.size(); i++) { if (parameters.get(i).toString().equals(current)) { optimizationParameterCombo.setSelectedIndex(i); @@ -1050,35 +989,33 @@ public class GeneralOptimizationDialog extends JDialog { } } } - + private void updateCounters() { bestValueLabel.setText(bestValueUnit.toStringUnit(bestValue)); stepCountLabel.setText("" + stepCount); evaluationCountLabel.setText("" + evaluationCount); stepSizeLabel.setText(UnitGroup.UNITS_RELATIVE.toStringUnit(stepSize)); } - - + private void loadOptimizationParameters() { optimizationParameters.clear(); optimizationParameters.addAll(OptimizationServiceHelper.getOptimizableParameters(documentCopy)); - + if (optimizationParameters.isEmpty()) { throw new BugException("No rocket optimization parameters found, distribution built wrong."); } - + Collections.sort(optimizationParameters, new Comparator() { - @Override + @Override public int compare(OptimizableParameter o1, OptimizableParameter o2) { - return o1.getName().compareTo(o2.getName()); - } - }); + return o1.getName().compareTo(o2.getName()); + } + }); } - - + private void loadSimulationModifiers() { simulationModifiers.clear(); - + for (SimulationModifier m : OptimizationServiceHelper.getSimulationModifiers(documentCopy)) { Object key = m.getRelatedObject(); List list = simulationModifiers.get(key); @@ -1088,7 +1025,7 @@ public class GeneralOptimizationDialog extends JDialog { } list.add(m); } - + for (Object key : simulationModifiers.keySet()) { List list = simulationModifiers.get(key); Collections.sort(list, new Comparator() { @@ -1098,49 +1035,42 @@ public class GeneralOptimizationDialog extends JDialog { } }); } - + } - - - + private void addModifier(SimulationModifier mod) { if (!selectedModifiers.contains(mod)) { log.user(1, "Adding simulation modifier " + mod); selectedModifiers.add(mod); - Collections.sort(selectedModifiers, new SimulationModifierComparator()); selectedModifierTableModel.fireTableDataChanged(); availableModifierTree.repaint(); } else { log.user(1, "Attempting to add an already existing simulation modifier " + mod); } } - - + private void removeModifier(SimulationModifier mod) { log.user(1, "Removing simulation modifier " + mod); selectedModifiers.remove(mod); selectedModifierTableModel.fireTableDataChanged(); availableModifierTree.repaint(); } - - - + /** * Update the enabled status of all components in the dialog. */ private void updateComponents() { boolean state; - + if (updating) { log.debug("Ignoring updateComponents"); return; } - + log.debug("Running updateComponents()"); - + updating = true; - - + // First enable all components if optimization not running if (!running) { log.debug("Initially enabling all components"); @@ -1148,57 +1078,52 @@ public class GeneralOptimizationDialog extends JDialog { c.setEnabled(true); } } - - + // "Add" button SimulationModifier mod = getSelectedAvailableModifier(); state = (mod != null && !selectedModifiers.contains(mod)); log.debug("addButton enabled: " + state); addButton.setEnabled(state); - + // "Remove" button state = (selectedModifierTable.getSelectedRow() >= 0); log.debug("removeButton enabled: " + state); removeButton.setEnabled(state); - + // "Remove all" button state = (!selectedModifiers.isEmpty()); log.debug("removeAllButton enabled: " + state); removeAllButton.setEnabled(state); - - + // Optimization goal String selected = (String) optimizationGoalCombo.getSelectedItem(); state = GOAL_SEEK.equals(selected); log.debug("optimizationGoalSpinner & UnitSelector enabled: " + state); optimizationGoalSpinner.setVisible(state); optimizationGoalUnitSelector.setVisible(state); - - + // Minimum/maximum stability options state = minimumStabilitySelected.isSelected(); log.debug("minimumStabilitySpinner & UnitSelector enabled: " + state); minimumStabilitySpinner.setEnabled(state); minimumStabilityUnitSelector.setEnabled(state); - + state = maximumStabilitySelected.isSelected(); log.debug("maximumStabilitySpimmer & UnitSelector enabled: " + state); maximumStabilitySpinner.setEnabled(state); maximumStabilityUnitSelector.setEnabled(state); - - + // Plot button (enabled if path exists and dimensionality is 1 or 2) state = (!optimizationPath.isEmpty() && (selectedModifiers.size() == 1 || selectedModifiers.size() == 2)); log.debug("plotButton enabled: " + state + " optimizationPath.isEmpty=" + optimizationPath.isEmpty() + " selectedModifiers.size=" + selectedModifiers.size()); plotButton.setEnabled(state); - + // Save button (enabled if path exists) state = (!evaluationHistory.isEmpty()); log.debug("saveButton enabled: " + state); saveButton.setEnabled(state); - - + // Last disable all components if optimization is running if (running) { log.debug("Disabling all components because optimization is running"); @@ -1206,8 +1131,7 @@ public class GeneralOptimizationDialog extends JDialog { c.setEnabled(false); } } - - + // Update description text mod = getSelectedModifier(); if (mod != null) { @@ -1215,57 +1139,55 @@ public class GeneralOptimizationDialog extends JDialog { } else { selectedModifierDescription.setText(""); } - - + // Update the figure figure.setConfiguration(getSelectedSimulation().getConfiguration()); - + updating = false; } - - + private void savePath() { - + if (evaluationHistory.isEmpty()) { throw new BugException("evaluation history is empty"); } - + CsvOptionPanel csvOptions = new CsvOptionPanel(GeneralOptimizationDialog.class, trans.get("export.header"), trans.get("export.header.ttip")); - + JFileChooser chooser = new JFileChooser(); chooser.setFileFilter(FileHelper.CSV_FILE_FILTER); chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory()); chooser.setAccessory(csvOptions); - + if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return; - + File file = chooser.getSelectedFile(); if (file == null) return; - + file = FileHelper.ensureExtension(file, "csv"); if (!FileHelper.confirmWrite(file, this)) { return; } - + String fieldSeparator = csvOptions.getFieldSeparator(); String commentCharacter = csvOptions.getCommentCharacter(); boolean includeHeader = csvOptions.getSelectionOption(0); csvOptions.storePreferences(); - + log.info("Saving optimization path to " + file + ", fieldSeparator=" + fieldSeparator + ", commentCharacter=" + commentCharacter + ", includeHeader=" + includeHeader); - + try { Writer writer = new BufferedWriter(new FileWriter(file)); - + // Write header if (includeHeader) { FunctionEvaluationData data = evaluationHistory.values().iterator().next(); - + writer.write(commentCharacter); for (SimulationModifier mod : selectedModifiers) { writer.write(mod.getRelatedObject().toString() + ": " + mod.getName() + " / " + @@ -1278,24 +1200,23 @@ public class GeneralOptimizationDialog extends JDialog { } writer.write(getSelectedParameter().getName() + " / " + getSelectedParameter().getUnitGroup().getDefaultUnit().getUnit()); - + writer.write("\n"); } - - + for (FunctionEvaluationData data : evaluationHistory.values()) { Value[] state = data.getState(); - + for (int i = 0; i < state.length; i++) { writer.write(TextUtil.doubleToString(state[i].getUnitValue())); writer.write(fieldSeparator); } - + if (minimumStabilitySelected.isSelected() || maximumStabilitySelected.isSelected()) { writer.write(TextUtil.doubleToString(data.getDomainReference().getUnitValue())); writer.write(fieldSeparator); } - + if (data.getParameterValue() != null) { writer.write(TextUtil.doubleToString(data.getParameterValue().getUnitValue())); } else { @@ -1303,16 +1224,16 @@ public class GeneralOptimizationDialog extends JDialog { } writer.write("\n"); } - + writer.close(); log.info("File successfully saved"); - + } catch (IOException e) { FileHelper.errorWriting(e, this); } - + } - + /** * Return the currently selected available simulation modifier from the modifier tree, * or null if none selected. @@ -1327,10 +1248,10 @@ public class GeneralOptimizationDialog extends JDialog { } return null; } - + /** * Return the currently selected simulation. - * @return the selected simulation. + * @return the selected simulation. */ @SuppressWarnings("unchecked") private Simulation getSelectedSimulation() { @@ -1346,12 +1267,11 @@ public class GeneralOptimizationDialog extends JDialog { } return ((Named) item).get(); } - - + /** * Return the currently selected simulation modifier from the table, * or null if none selected. - * @return the selected modifier or null. + * @return the selected modifier or null. */ private SimulationModifier getSelectedModifier() { int row = selectedModifierTable.getSelectedRow(); @@ -1361,22 +1281,20 @@ public class GeneralOptimizationDialog extends JDialog { row = selectedModifierTable.convertRowIndexToModel(row); return selectedModifiers.get(row); } - - + /** * Return the currently selected optimization parameter. - * @return the selected optimization parameter. + * @return the selected optimization parameter. */ @SuppressWarnings("unchecked") private OptimizableParameter getSelectedParameter() { return ((Named) optimizationParameterCombo.getSelectedItem()).get(); } - - + private Unit getModifierUnit(int index) { return selectedModifiers.get(index).getUnitGroup().getDefaultUnit(); } - + private String createSimulationName(String simulationName, String motorConfiguration) { String name; boolean hasParenthesis = motorConfiguration.matches("^[\\[\\(].*[\\]\\)]$"); @@ -1390,30 +1308,30 @@ public class GeneralOptimizationDialog extends JDialog { } return name; } - + /** * The table model for the parameter selection. * - * [Body tube: Length] [min] [max] [unit] + * [Body tube: Length] [min] [max] [unit] */ private class ParameterSelectionTableModel extends AbstractTableModel { - + private static final int PARAMETER = 0; private static final int CURRENT = 1; private static final int MIN = 2; private static final int MAX = 3; private static final int COUNT = 4; - + @Override public int getColumnCount() { return COUNT; } - + @Override public int getRowCount() { return selectedModifiers.size(); } - + @Override public String getColumnName(int column) { switch (column) { @@ -1428,9 +1346,9 @@ public class GeneralOptimizationDialog extends JDialog { default: throw new IndexOutOfBoundsException("column=" + column); } - + } - + @Override public Class getColumnClass(int column) { switch (column) { @@ -1446,12 +1364,12 @@ public class GeneralOptimizationDialog extends JDialog { throw new IndexOutOfBoundsException("column=" + column); } } - + @Override public Object getValueAt(int row, int column) { - + SimulationModifier modifier = selectedModifiers.get(row); - + switch (column) { case PARAMETER: return modifier.getRelatedObject().toString() + ": " + modifier.getName(); @@ -1468,44 +1386,44 @@ public class GeneralOptimizationDialog extends JDialog { default: throw new IndexOutOfBoundsException("column=" + column); } - + } - + @Override public void setValueAt(Object value, int row, int column) { - + if (row >= selectedModifiers.size()) { throw new BugException("setValueAt with invalid row: value=" + value + " row=" + row + " column=" + column + " selectedModifiers.size=" + selectedModifiers.size() + " selectedModifiers=" + selectedModifiers + " selectedModifierTable.getRowCount=" + selectedModifierTable.getRowCount()); } - + switch (column) { case PARAMETER: break; - + case MIN: double min = (Double) value; min = getModifierUnit(row).fromUnit(min); selectedModifiers.get(row).setMinValue(min); break; - + case CURRENT: break; - + case MAX: double max = (Double) value; max = getModifierUnit(row).fromUnit(max); selectedModifiers.get(row).setMaxValue(max); break; - + default: throw new IndexOutOfBoundsException("column=" + column); } this.fireTableRowsUpdated(row, row); - + } - + @Override public boolean isCellEditable(int row, int column) { switch (column) { @@ -1521,35 +1439,34 @@ public class GeneralOptimizationDialog extends JDialog { throw new IndexOutOfBoundsException("column=" + column); } } - + } - - + private class DoubleCellRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - + double val = (Double) value; Unit unit = getModifierUnit(row); - + val = unit.fromUnit(val); this.setText(unit.toStringUnit(val)); - + return this; } } - - + + private static class SimulationModifierComparator implements Comparator { @Override public int compare(SimulationModifier mod1, SimulationModifier mod2) { Object rel1 = mod1.getRelatedObject(); Object rel2 = mod2.getRelatedObject(); - + /* * Primarily order by related object: * @@ -1557,10 +1474,10 @@ public class GeneralOptimizationDialog extends JDialog { * - Two RocketComponents are ordered based on their position in the rocket */ if (!rel1.equals(rel2)) { - + if (rel1 instanceof RocketComponent) { if (rel2 instanceof RocketComponent) { - + RocketComponent root = ((RocketComponent) rel1).getRoot(); for (RocketComponent c : root) { if (c.equals(rel1)) { @@ -1570,10 +1487,10 @@ public class GeneralOptimizationDialog extends JDialog { return 1; } } - + throw new BugException("Error sorting modifiers, mod1=" + mod1 + " rel1=" + rel1 + " mod2=" + mod2 + " rel2=" + rel2); - + } else { return -1; } @@ -1582,14 +1499,12 @@ public class GeneralOptimizationDialog extends JDialog { return 1; } } - + } - + // Secondarily sort by name return collator.compare(mod1.getName(), mod2.getName()); } } - - - + }