From 77f2457dc781c8c517ddef157c18491ad770f6c6 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Wed, 8 Aug 2012 02:24:40 +0000 Subject: [PATCH] Rework the CustomExpression evaluation to use SimulationListeners. Removed the OpenRocketDocument member variable from the Simulation object. git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@959 180e2498-e6e9-4542-8430-84ac67f01cd8 --- .../sf/openrocket/android/CurrentRocket.java | 3 +- .../document/OpenRocketDocument.java | 2 +- .../sf/openrocket/document/Simulation.java | 19 +- .../openrocket/importt/OpenRocketLoader.java | 2 +- .../CustomExpressionPanel.java | 10 +- .../GeneralOptimizationDialog.java | 4 +- .../gui/main/SimulationEditDialog.java | 13 +- .../openrocket/gui/main/SimulationPanel.java | 6 +- .../gui/main/SimulationRunDialog.java | 21 +- .../gui/scalefigure/RocketPanel.java | 298 +++++++++--------- .../openrocket/gui/util/SwingPreferences.java | 3 +- .../DefaultSimulationModifierService.java | 2 +- .../BasicEventSimulationEngine.java | 6 - .../customexpression/CustomExpression.java | 4 +- .../CustomExpressionSimulationListener.java | 34 ++ .../TestRocketOptimizationFunction.java | 11 +- .../modifiers/TestGenericModifier.java | 5 +- 17 files changed, 232 insertions(+), 211 deletions(-) create mode 100644 core/src/net/sf/openrocket/simulation/customexpression/CustomExpressionSimulationListener.java diff --git a/android/src/net/sf/openrocket/android/CurrentRocket.java b/android/src/net/sf/openrocket/android/CurrentRocket.java index f4b7861e..36446063 100644 --- a/android/src/net/sf/openrocket/android/CurrentRocket.java +++ b/android/src/net/sf/openrocket/android/CurrentRocket.java @@ -75,8 +75,7 @@ public class CurrentRocket { public synchronized void addNewSimulation( Context context ) { isModified = true; Rocket rocket = rocketDocument.getRocket(); - // FIXME - hopefully the change to the Simulation object will be reverted soon. - Simulation newSim = new Simulation(rocketDocument, rocket); + Simulation newSim = new Simulation(rocket); newSim.setName(rocketDocument.getNextSimulationName()); rocketDocument.addSimulation(newSim); notifySimsChanged(context); diff --git a/core/src/net/sf/openrocket/document/OpenRocketDocument.java b/core/src/net/sf/openrocket/document/OpenRocketDocument.java index c7719346..06422181 100644 --- a/core/src/net/sf/openrocket/document/OpenRocketDocument.java +++ b/core/src/net/sf/openrocket/document/OpenRocketDocument.java @@ -117,7 +117,7 @@ public class OpenRocketDocument implements ComponentChangeListener { customExpressions.remove(expression); } - public ArrayList getCustomExpressions(){ + public List getCustomExpressions(){ return customExpressions; } diff --git a/core/src/net/sf/openrocket/document/Simulation.java b/core/src/net/sf/openrocket/document/Simulation.java index 162ee20d..edb093c3 100644 --- a/core/src/net/sf/openrocket/document/Simulation.java +++ b/core/src/net/sf/openrocket/document/Simulation.java @@ -60,7 +60,6 @@ public class Simulation implements ChangeSource, Cloneable { private SafetyMutex mutex = SafetyMutex.newInstance(); private final Rocket rocket; - private final OpenRocketDocument document; private String name = ""; @@ -94,11 +93,7 @@ public class Simulation implements ChangeSource, Cloneable { * * @param rocket the rocket associated with the simulation. */ - public Simulation(OpenRocketDocument doc, Rocket rocket) { - // It may seem silly to pass in the document and rocket, since usually when called we - // use doc.getRocket, but I guess there is some reason; when cloning a simulation + rocket we don't need - // to make a duplicate of the undo data etc stored in the document. --Richard - this.document = doc; + public Simulation(Rocket rocket) { this.rocket = rocket; this.status = Status.NOT_SIMULATED; @@ -109,7 +104,7 @@ public class Simulation implements ChangeSource, Cloneable { } - public Simulation(OpenRocketDocument doc, Rocket rocket, Status status, String name, SimulationOptions options, + public Simulation(Rocket rocket, Status status, String name, SimulationOptions options, List listeners, FlightData data) { if (rocket == null) @@ -122,7 +117,6 @@ public class Simulation implements ChangeSource, Cloneable { throw new IllegalArgumentException("options cannot be null"); this.rocket = rocket; - this.document = doc; if (status == Status.UPTODATE) { this.status = Status.LOADED; @@ -152,13 +146,6 @@ public class Simulation implements ChangeSource, Cloneable { } - /* - * Return the parent document for this simulation - */ - public OpenRocketDocument getDocument(){ - return document; - } - /** * Return the rocket associated with this simulation. * @@ -423,7 +410,7 @@ public class Simulation implements ChangeSource, Cloneable { public Simulation duplicateSimulation(Rocket newRocket) { mutex.lock("duplicateSimulation"); try { - Simulation copy = new Simulation(document, newRocket); + Simulation copy = new Simulation(newRocket); copy.name = this.name; copy.options.copyFrom(this.options); diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/OpenRocketLoader.java b/core/src/net/sf/openrocket/file/openrocket/importt/OpenRocketLoader.java index b8b34b3b..d6c4e249 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/OpenRocketLoader.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/OpenRocketLoader.java @@ -1383,7 +1383,7 @@ class SingleSimulationHandler extends AbstractElementHandler { else data = dataHandler.getFlightData(); - Simulation simulation = new Simulation(doc, doc.getRocket(), status, name, + Simulation simulation = new Simulation(doc.getRocket(), status, name, conditions, listeners, data); doc.addSimulation(simulation); diff --git a/core/src/net/sf/openrocket/gui/customexpression/CustomExpressionPanel.java b/core/src/net/sf/openrocket/gui/customexpression/CustomExpressionPanel.java index ec60f250..08c83a4b 100644 --- a/core/src/net/sf/openrocket/gui/customexpression/CustomExpressionPanel.java +++ b/core/src/net/sf/openrocket/gui/customexpression/CustomExpressionPanel.java @@ -5,8 +5,8 @@ import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; -import java.util.ArrayList; import java.util.Collections; +import java.util.List; import javax.swing.BorderFactory; import javax.swing.JButton; @@ -17,23 +17,17 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; import javax.swing.border.Border; -import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.file.DatabaseMotorFinder; import net.sf.openrocket.file.GeneralRocketLoader; -import net.sf.openrocket.file.MotorFinder; import net.sf.openrocket.file.RocketLoadException; -import net.sf.openrocket.document.Simulation; -import net.sf.openrocket.gui.components.DescriptionArea; import net.sf.openrocket.gui.components.UnitSelector; -import net.sf.openrocket.gui.customexpression.ExpressionBuilderDialog; import net.sf.openrocket.gui.util.Icons; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.logging.LogHelper; -import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.simulation.customexpression.CustomExpression; import net.sf.openrocket.startup.Application; @@ -158,7 +152,7 @@ public class CustomExpressionPanel extends JPanel { * @param move integer - +1 to move down, -1 to move up */ private void moveExpression(CustomExpression expression, int move){ - ArrayList expressions = doc.getCustomExpressions(); + List expressions = doc.getCustomExpressions(); int i = expressions.indexOf(expression); if (i+move == expressions.size() || i+move < 0) return; 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 50d55547..7a0ecc5f 100644 --- a/core/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java +++ b/core/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java @@ -1000,14 +1000,14 @@ public class GeneralOptimizationDialog extends JDialog { if (id == null) { continue; } - Simulation sim = new Simulation(documentCopy, rocket); + Simulation sim = new Simulation(rocket); sim.getConfiguration().setMotorConfigurationID(id); String name = createSimulationName(trans.get("basicSimulationName"), rocket.getMotorConfigurationNameOrDescription(id)); simulations.add(new Named(sim, name)); } - Simulation sim = new Simulation(documentCopy, rocket); + Simulation sim = new Simulation(rocket); sim.getConfiguration().setMotorConfigurationID(null); String name = createSimulationName(trans.get("noSimulationName"), rocket.getMotorConfigurationNameOrDescription(null)); simulations.add(new Named(sim, name)); diff --git a/core/src/net/sf/openrocket/gui/main/SimulationEditDialog.java b/core/src/net/sf/openrocket/gui/main/SimulationEditDialog.java index b8a59ea7..35c72db6 100644 --- a/core/src/net/sf/openrocket/gui/main/SimulationEditDialog.java +++ b/core/src/net/sf/openrocket/gui/main/SimulationEditDialog.java @@ -30,6 +30,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.Simulation; import net.sf.openrocket.gui.SpinnerEditor; import net.sf.openrocket.gui.adaptors.BooleanModel; @@ -41,7 +42,6 @@ import net.sf.openrocket.gui.components.DescriptionArea; import net.sf.openrocket.gui.components.SimulationExportPanel; import net.sf.openrocket.gui.components.UnitSelector; import net.sf.openrocket.gui.plot.Axis; -import net.sf.openrocket.gui.customexpression.CustomExpressionPanel; import net.sf.openrocket.gui.plot.PlotConfiguration; import net.sf.openrocket.gui.plot.SimulationPlotPanel; import net.sf.openrocket.gui.util.GUIUtil; @@ -83,19 +83,20 @@ public class SimulationEditDialog extends JDialog { private final Window parentWindow; private final Simulation simulation; + private final OpenRocketDocument document; private final SimulationOptions conditions; private final Configuration configuration; private static final Translator trans = Application.getTranslator(); - public SimulationEditDialog(Window parent, Simulation s) { - this(parent, s, 0); + public SimulationEditDialog(Window parent, OpenRocketDocument document, Simulation s) { + this(parent, document, s, 0); } - public SimulationEditDialog(Window parent, Simulation s, int tab) { + public SimulationEditDialog(Window parent, OpenRocketDocument document, Simulation s, int tab) { //// Edit simulation super(parent, trans.get("simedtdlg.title.Editsim"), JDialog.ModalityType.DOCUMENT_MODAL); - + this.document = document; this.parentWindow = parent; this.simulation = s; this.conditions = simulation.getOptions(); @@ -170,7 +171,7 @@ public class SimulationEditDialog extends JDialog { @Override public void actionPerformed(ActionEvent e) { SimulationEditDialog.this.dispose(); - SimulationRunDialog.runSimulations(parentWindow, simulation); + SimulationRunDialog.runSimulations(parentWindow, SimulationEditDialog.this.document, simulation); } }); mainPanel.add(button, "gapright para"); diff --git a/core/src/net/sf/openrocket/gui/main/SimulationPanel.java b/core/src/net/sf/openrocket/gui/main/SimulationPanel.java index 09751730..66950a94 100644 --- a/core/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/core/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -82,7 +82,7 @@ public class SimulationPanel extends JPanel { button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - Simulation sim = new Simulation(document, document.getRocket()); + Simulation sim = new Simulation(document.getRocket()); sim.setName(document.getNextSimulationName()); int n = document.getSimulationCount(); @@ -135,7 +135,7 @@ public class SimulationPanel extends JPanel { long t = System.currentTimeMillis(); new SimulationRunDialog(SwingUtilities.getWindowAncestor( - SimulationPanel.this), sims).setVisible(true); + SimulationPanel.this), document, sims).setVisible(true); log.info("Running simulations took " + (System.currentTimeMillis() - t) + " ms"); fireMaintainSelection(); } @@ -514,7 +514,7 @@ public class SimulationPanel extends JPanel { } private void openDialog(final Simulation sim, int position) { - new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), sim, position) + new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sim, position) .setVisible(true); fireMaintainSelection(); } diff --git a/core/src/net/sf/openrocket/gui/main/SimulationRunDialog.java b/core/src/net/sf/openrocket/gui/main/SimulationRunDialog.java index 3b170d42..65fabb8f 100644 --- a/core/src/net/sf/openrocket/gui/main/SimulationRunDialog.java +++ b/core/src/net/sf/openrocket/gui/main/SimulationRunDialog.java @@ -24,6 +24,7 @@ import javax.swing.JPanel; import javax.swing.JProgressBar; import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.Simulation; import net.sf.openrocket.gui.dialogs.DetailDialog; import net.sf.openrocket.gui.util.GUIUtil; @@ -35,6 +36,8 @@ import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.MotorMount.IgnitionEvent; import net.sf.openrocket.simulation.FlightEvent; import net.sf.openrocket.simulation.SimulationStatus; +import net.sf.openrocket.simulation.customexpression.CustomExpression; +import net.sf.openrocket.simulation.customexpression.CustomExpressionSimulationListener; import net.sf.openrocket.simulation.exception.SimulationCancelledException; import net.sf.openrocket.simulation.exception.SimulationException; import net.sf.openrocket.simulation.exception.SimulationLaunchException; @@ -95,6 +98,7 @@ public class SimulationRunDialog extends JDialog { * will result in an exception being thrown! */ private final Simulation[] simulations; + private final OpenRocketDocument document; private final String[] simulationNames; private final SimulationWorker[] simulationWorkers; private final SimulationStatus[] simulationStatuses; @@ -102,9 +106,10 @@ public class SimulationRunDialog extends JDialog { private final double[] simulationMaxVelocity; private final boolean[] simulationDone; - public SimulationRunDialog(Window window, Simulation... simulations) { + public SimulationRunDialog(Window window, OpenRocketDocument document, Simulation... simulations) { //// Running simulations... super(window, trans.get("SimuRunDlg.title.RunSim"), Dialog.ModalityType.APPLICATION_MODAL); + this.document = document; if (simulations.length == 0) { throw new IllegalArgumentException("Called with no simulations to run"); @@ -129,7 +134,7 @@ public class SimulationRunDialog extends JDialog { for (int i = 0; i < n; i++) { simulationNames[i] = simulations[i].getName(); - simulationWorkers[i] = new InteractiveSimulationWorker(simulations[i], i); + simulationWorkers[i] = new InteractiveSimulationWorker(document, simulations[i], i); executor.execute(simulationWorkers[i]); } @@ -208,8 +213,8 @@ public class SimulationRunDialog extends JDialog { * @param parent the parent Window of the dialog to use. * @param simulations the simulations to run. */ - public static void runSimulations(Window parent, Simulation... simulations) { - new SimulationRunDialog(parent, simulations).setVisible(true); + public static void runSimulations(Window parent, OpenRocketDocument document, Simulation... simulations) { + new SimulationRunDialog(parent, document, simulations).setVisible(true); } @@ -277,6 +282,8 @@ public class SimulationRunDialog extends JDialog { private volatile double burnoutVelocity; private volatile double apogeeAltitude; + private final CustomExpressionSimulationListener exprListener; + /* * -2 = time from 0 ... burnoutTimeEstimate * -1 = velocity from v(burnoutTimeEstimate) ... 0 @@ -287,8 +294,10 @@ public class SimulationRunDialog extends JDialog { private int progress = 0; - public InteractiveSimulationWorker(Simulation sim, int index) { + public InteractiveSimulationWorker(OpenRocketDocument doc, Simulation sim, int index) { super(sim); + List exprs = doc.getCustomExpressions(); + exprListener = new CustomExpressionSimulationListener(exprs); this.index = index; // Calculate estimate of motor burn time @@ -314,7 +323,7 @@ public class SimulationRunDialog extends JDialog { */ @Override protected SimulationListener[] getExtraListeners() { - return new SimulationListener[] { new SimulationProgressListener() }; + return new SimulationListener[] { new SimulationProgressListener(), exprListener }; } diff --git a/core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java b/core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java index e82c77ee..ed80812d 100644 --- a/core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java +++ b/core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java @@ -62,6 +62,8 @@ import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.SymmetricComponent; import net.sf.openrocket.simulation.FlightData; +import net.sf.openrocket.simulation.customexpression.CustomExpression; +import net.sf.openrocket.simulation.customexpression.CustomExpressionSimulationListener; import net.sf.openrocket.simulation.listeners.SimulationListener; import net.sf.openrocket.simulation.listeners.system.ApogeeEndListener; import net.sf.openrocket.simulation.listeners.system.InterruptListener; @@ -87,47 +89,47 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change private boolean is3d; private final RocketFigure figure; private final RocketFigure3d figure3d; - - + + private final ScaleScrollPane scrollPane; - + private final JPanel figureHolder; - + private JLabel infoMessage; - + private TreeSelectionModel selectionModel = null; - + private BasicSlider rotationSlider; ScaleSelector scaleSelector; - + /* Calculation of CP and CG */ private AerodynamicCalculator aerodynamicCalculator; private MassCalculator massCalculator; - + private final OpenRocketDocument document; private final Configuration configuration; - + private Caret extraCP = null; private Caret extraCG = null; private RocketInfo extraText = null; - + private double cpAOA = Double.NaN; private double cpTheta = Double.NaN; private double cpMach = Double.NaN; private double cpRoll = Double.NaN; - + // The functional ID of the rocket that was simulated private int flightDataFunctionalID = -1; private String flightDataMotorID = null; - + private SimulationWorker backgroundSimulationWorker = null; - + private List listeners = new ArrayList(); - + /** * The executor service used for running the background simulations. @@ -138,34 +140,34 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change static { backgroundSimulationExecutor = Executors.newFixedThreadPool(SwingPreferences.getMaxThreadCount(), new ThreadFactory() { - private ThreadFactory factory = Executors.defaultThreadFactory(); - - @Override - public Thread newThread(Runnable r) { - Thread t = factory.newThread(r); - t.setDaemon(true); - t.setPriority(Thread.MIN_PRIORITY); - return t; - } - }); + private ThreadFactory factory = Executors.defaultThreadFactory(); + + @Override + public Thread newThread(Runnable r) { + Thread t = factory.newThread(r); + t.setDaemon(true); + t.setPriority(Thread.MIN_PRIORITY); + return t; + } + }); } - - + + public RocketPanel(OpenRocketDocument document) { - + this.document = document; configuration = document.getDefaultConfiguration(); - + // TODO: FUTURE: calculator selection aerodynamicCalculator = new BarrowmanCalculator(); massCalculator = new BasicMassCalculator(); - + // Create figure and custom scroll pane figure = new RocketFigure(configuration); figure3d = new RocketFigure3d(configuration); - + figureHolder = new JPanel(new BorderLayout()); - + scrollPane = new ScaleScrollPane(figure) { private static final long serialVersionUID = 1L; @@ -176,12 +178,12 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change }; scrollPane.getViewport().setScrollMode(JViewport.SIMPLE_SCROLL_MODE); scrollPane.setFitting(true); - + createPanel(); - + is3d = true; go2D(); - + configuration.addChangeListener(new StateChangeListener() { @Override public void stateChanged(EventObject e) { @@ -190,7 +192,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change updateFigures(); } }); - + figure3d.addComponentSelectionListener(new RocketFigure3d.ComponentSelectionListener() { @Override public void componentClicked(RocketComponent clicked[], MouseEvent event) { @@ -198,7 +200,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change } }); } - + private void updateFigures() { if (!is3d) figure.updateFigure(); @@ -233,20 +235,20 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change figureHolder.revalidate(); figure.repaint(); } - + /** * Creates the layout and components of the panel. */ private void createPanel() { setLayout(new MigLayout("", "[shrink][grow]", "[shrink][shrink][grow][shrink]")); - + setPreferredSize(new Dimension(800, 300)); - + //// Create toolbar - + ButtonGroup bg = new ButtonGroup(); - + // Side/back buttons FigureTypeAction action = new FigureTypeAction(RocketFigure.TYPE_SIDE); //// Side view @@ -256,7 +258,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change JToggleButton toggle = new JToggleButton(action); bg.add(toggle); add(toggle, "spanx, split"); - + action = new FigureTypeAction(RocketFigure.TYPE_BACK); //// Back view action.putValue(Action.NAME, trans.get("RocketPanel.FigTypeAct.Backview")); @@ -265,7 +267,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change toggle = new JToggleButton(action); bg.add(toggle); add(toggle, "gap rel"); - + //// 3d Toggle final JToggleButton toggle3d = new JToggleButton(new AbstractAction("3D") { private static final long serialVersionUID = 1L; @@ -284,18 +286,18 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change }); bg.add(toggle3d); add(toggle3d, "gap rel"); - + // Zoom level selector scaleSelector = new ScaleSelector(scrollPane); add(scaleSelector); - + // Stage selector StageSelector stageSelector = new StageSelector(configuration); add(stageSelector, ""); - + // Motor configuration selector @@ -304,55 +306,55 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change label.setHorizontalAlignment(JLabel.RIGHT); add(label, "growx, right"); add(new JComboBox(new MotorConfigurationModel(configuration)), "wrap"); - + // Create slider and scroll pane - + DoubleModel theta = new DoubleModel(figure, "Rotation", UnitGroup.UNITS_ANGLE, 0, 2 * Math.PI); UnitSelector us = new UnitSelector(theta, true); us.setHorizontalAlignment(JLabel.CENTER); add(us, "alignx 50%, growx"); - + // Add the rocket figure add(figureHolder, "grow, spany 2, wmin 300lp, hmin 100lp, wrap"); - + // Add rotation slider // Minimum size to fit "360deg" JLabel l = new JLabel("360" + Chars.DEGREE); Dimension d = l.getPreferredSize(); - + add(rotationSlider = new BasicSlider(theta.getSliderModel(0, 2 * Math.PI), JSlider.VERTICAL, true), "ax 50%, wrap, width " + (d.width + 6) + "px:null:null, growy"); - + //// Click to select    Shift+click to select other    Double-click to edit    Click+drag to move infoMessage = new JLabel(trans.get("RocketPanel.lbl.infoMessage")); infoMessage.setFont(new Font("Sans Serif", Font.PLAIN, 9)); add(infoMessage, "skip, span, gapleft 25, wrap"); - + addExtras(); } - - + + public RocketFigure getFigure() { return figure; } - + public AerodynamicCalculator getAerodynamicCalculator() { return aerodynamicCalculator; } - + public Configuration getConfiguration() { return configuration; } - + /** * Get the center of pressure figure element. * @@ -361,7 +363,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change public Caret getExtraCP() { return extraCP; } - + /** * Get the center of gravity figure element. * @@ -370,7 +372,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change public Caret getExtraCG() { return extraCG; } - + /** * Get the extra text figure element. * @@ -379,7 +381,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change public RocketInfo getExtraText() { return extraText; } - + public void setSelectionModel(TreeSelectionModel m) { if (selectionModel != null) { selectionModel.removeTreeSelectionListener(this); @@ -388,8 +390,8 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change selectionModel.addTreeSelectionListener(this); valueChanged((TreeSelectionEvent) null); // updates FigureParameters } - - + + /** * Return the angle of attack used in CP calculation. NaN signifies the default value @@ -399,7 +401,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change public double getCPAOA() { return cpAOA; } - + /** * Set the angle of attack to be used in CP calculation. A value of NaN signifies that * the default AOA (zero) should be used. @@ -414,11 +416,11 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change updateFigures(); fireChangeEvent(); } - + public double getCPTheta() { return cpTheta; } - + public void setCPTheta(double theta) { if (MathUtil.equals(theta, cpTheta) || (Double.isNaN(theta) && Double.isNaN(cpTheta))) @@ -430,11 +432,11 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change updateFigures(); fireChangeEvent(); } - + public double getCPMach() { return cpMach; } - + public void setCPMach(double mach) { if (MathUtil.equals(mach, cpMach) || (Double.isNaN(mach) && Double.isNaN(cpMach))) @@ -444,11 +446,11 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change updateFigures(); fireChangeEvent(); } - + public double getCPRoll() { return cpRoll; } - + public void setCPRoll(double roll) { if (MathUtil.equals(roll, cpRoll) || (Double.isNaN(roll) && Double.isNaN(cpRoll))) @@ -458,19 +460,19 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change updateFigures(); fireChangeEvent(); } - - + + @Override public void addChangeListener(EventListener listener) { listeners.add(0, listener); } - + @Override public void removeChangeListener(EventListener listener) { listeners.remove(listener); } - + protected void fireChangeEvent() { EventObject e = new EventObject(this); for (EventListener l : listeners) { @@ -479,8 +481,8 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change } } } - - + + /** @@ -493,7 +495,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change * the next component. Otherwise select the first component in the list. */ public static final int CYCLE_SELECTION_MODIFIER = InputEvent.SHIFT_DOWN_MASK; - + private void handleMouseClick(MouseEvent event) { if (event.getButton() != MouseEvent.BUTTON1) return; @@ -501,18 +503,18 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change Point p1 = scrollPane.getViewport().getViewPosition(); int x = p0.x + p1.x; int y = p0.y + p1.y; - + RocketComponent[] clicked = figure.getComponentsByPoint(x, y); - + handleComponentClick(clicked, event); } - + private void handleComponentClick(RocketComponent[] clicked, MouseEvent event){ - + // If no component is clicked, do nothing if (clicked.length == 0) return; - + // Check whether the currently selected component is in the clicked components. TreePath path = selectionModel.getSelectionPath(); if (path != null) { @@ -529,7 +531,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change } } } - + // Currently selected component not clicked if (path == null) { if (event.isShiftDown() && event.getClickCount() == 1 && clicked.length > 1) { @@ -538,18 +540,18 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change path = ComponentTreeModel.makeTreePath(clicked[0]); } } - + // Set selection and check for double-click selectionModel.setSelectionPath(path); if (event.getClickCount() == 2) { RocketComponent component = (RocketComponent) path.getLastPathComponent(); - + ComponentConfigDialog.showDialog(SwingUtilities.getWindowAncestor(this), document, component); } } - - + + /** @@ -557,15 +559,15 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change * the CP and CG carets. */ private WarningSet warnings = new WarningSet(); - + private void updateExtras() { Coordinate cp, cg; double cpx, cgx; - + // TODO: MEDIUM: User-definable conditions FlightConditions conditions = new FlightConditions(configuration); warnings.clear(); - + if (!Double.isNaN(cpMach)) { conditions.setMach(cpMach); extraText.setMach(cpMach); @@ -573,20 +575,20 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change conditions.setMach(Application.getPreferences().getDefaultMach()); extraText.setMach(Application.getPreferences().getDefaultMach()); } - + if (!Double.isNaN(cpAOA)) { conditions.setAOA(cpAOA); } else { conditions.setAOA(0); } extraText.setAOA(cpAOA); - + if (!Double.isNaN(cpRoll)) { conditions.setRollRate(cpRoll); } else { conditions.setRollRate(0); } - + if (!Double.isNaN(cpTheta)) { conditions.setTheta(cpTheta); cp = aerodynamicCalculator.getCP(configuration, conditions, warnings); @@ -594,24 +596,24 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change cp = aerodynamicCalculator.getWorstCP(configuration, conditions, warnings); } extraText.setTheta(cpTheta); - + cg = massCalculator.getCG(configuration, MassCalcType.LAUNCH_MASS); // System.out.println("CG computed as "+cg+ " CP as "+cp); - + if (cp.weight > 0.000001) cpx = cp.x; else cpx = Double.NaN; - + if (cg.weight > 0.000001) cgx = cg.x; else cgx = Double.NaN; - + figure3d.setCG(cg); figure3d.setCP(cp); - + // Length bound is assumed to be tight double length = 0, diameter = 0; Collection bounds = configuration.getBounds(); @@ -625,7 +627,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change } length = maxX - minX; } - + for (RocketComponent c : configuration) { if (c instanceof SymmetricComponent) { double d1 = ((SymmetricComponent) c).getForeRadius() * 2; @@ -633,31 +635,31 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change diameter = MathUtil.max(diameter, d1, d2); } } - + extraText.setCG(cgx); extraText.setCP(cpx); extraText.setLength(length); extraText.setDiameter(diameter); extraText.setMass(cg.weight); extraText.setWarnings(warnings); - + if (figure.getType() == RocketFigure.TYPE_SIDE && length > 0) { - + // TODO: LOW: Y-coordinate and rotation extraCP.setPosition(cpx * RocketFigure.EXTRA_SCALE, 0); extraCG.setPosition(cgx * RocketFigure.EXTRA_SCALE, 0); - + } else { - + extraCP.setPosition(Double.NaN, Double.NaN); extraCG.setPosition(Double.NaN, Double.NaN); - + } - + //////// Flight simulation in background - + // Check whether to compute or not if (!((SwingPreferences) Application.getPreferences()).computeFlightInBackground()) { extraText.setFlightData(null); @@ -665,38 +667,38 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change stopBackgroundSimulation(); return; } - + // Check whether data is already up to date if (flightDataFunctionalID == configuration.getRocket().getFunctionalModID() && flightDataMotorID == configuration.getMotorConfigurationID()) { return; } - + flightDataFunctionalID = configuration.getRocket().getFunctionalModID(); flightDataMotorID = configuration.getMotorConfigurationID(); - + // Stop previous computation (if any) stopBackgroundSimulation(); - + // Check that configuration has motors if (!configuration.hasMotors()) { extraText.setFlightData(FlightData.NaN_DATA); extraText.setCalculatingData(false); return; } - + // Start calculation process extraText.setCalculatingData(true); - + Rocket duplicate = (Rocket) configuration.getRocket().copy(); Simulation simulation = ((SwingPreferences)Application.getPreferences()).getBackgroundSimulation(duplicate); simulation.getOptions().setMotorConfigurationID( configuration.getMotorConfigurationID()); - - backgroundSimulationWorker = new BackgroundSimulationWorker(simulation); + + backgroundSimulationWorker = new BackgroundSimulationWorker(document, simulation); backgroundSimulationExecutor.execute(backgroundSimulationWorker); } - + /** * Cancels the current background simulation worker, if any. */ @@ -706,22 +708,26 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change backgroundSimulationWorker = null; } } - - + + /** * A SimulationWorker that simulates the rocket flight in the background and * sets the results to the extra text when finished. The worker can be cancelled * if necessary. */ private class BackgroundSimulationWorker extends SimulationWorker { - - public BackgroundSimulationWorker(Simulation sim) { + + private final CustomExpressionSimulationListener exprListener; + + public BackgroundSimulationWorker(OpenRocketDocument doc, Simulation sim) { super(sim); + List exprs = doc.getCustomExpressions(); + exprListener = new CustomExpressionSimulationListener(exprs); } - + @Override protected FlightData doInBackground() { - + // Pause a little while to allow faster UI reaction try { Thread.sleep(300); @@ -729,36 +735,38 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change } if (isCancelled() || backgroundSimulationWorker != this) return null; - + return super.doInBackground(); } - + @Override protected void simulationDone() { // Do nothing if cancelled if (isCancelled() || backgroundSimulationWorker != this) return; - + backgroundSimulationWorker = null; extraText.setFlightData(simulation.getSimulatedData()); extraText.setCalculatingData(false); figure.repaint(); figure3d.repaint(); } - + @Override protected SimulationListener[] getExtraListeners() { return new SimulationListener[] { InterruptListener.INSTANCE, - ApogeeEndListener.INSTANCE }; + ApogeeEndListener.INSTANCE, + exprListener}; + } - + @Override protected void simulationInterrupted(Throwable t) { // Do nothing on cancel, set N/A data otherwise if (isCancelled() || backgroundSimulationWorker != this) // Double-check return; - + backgroundSimulationWorker = null; extraText.setFlightData(FlightData.NaN_DATA); extraText.setCalculatingData(false); @@ -766,8 +774,8 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change figure3d.repaint(); } } - - + + /** * Adds the extra data to the figure. Currently this includes the CP and CG carets. @@ -777,21 +785,21 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change extraCP = new CPCaret(0, 0); extraText = new RocketInfo(configuration); updateExtras(); - + figure.clearRelativeExtra(); figure.addRelativeExtra(extraCP); figure.addRelativeExtra(extraCG); figure.addAbsoluteExtra(extraText); - - + + figure3d.clearRelativeExtra(); //figure3d.addRelativeExtra(extraCP); //figure3d.addRelativeExtra(extraCG); figure3d.addAbsoluteExtra(extraText); - + } - - + + /** * Updates the selection in the FigureParameters and repaints the figure. * Ignores the event itself. @@ -803,16 +811,16 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change figure.setSelection(null); return; } - + RocketComponent[] components = new RocketComponent[paths.length]; for (int i = 0; i < paths.length; i++) components[i] = (RocketComponent) paths[i].getLastPathComponent(); figure.setSelection(components); - + figure3d.setSelection(components); } - - + + /** * An Action that shows whether the figure type is the type @@ -823,13 +831,13 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change private class FigureTypeAction extends AbstractAction implements StateChangeListener { private static final long serialVersionUID = 1L; private final int type; - + public FigureTypeAction(int type) { this.type = type; stateChanged(null); figure.addChangeListener(this); } - + @Override public void actionPerformed(ActionEvent e) { boolean state = (Boolean) getValue(Action.SELECTED_KEY); @@ -841,11 +849,11 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change } stateChanged(null); } - + @Override public void stateChanged(EventObject e) { putValue(Action.SELECTED_KEY, figure.getType() == type && !is3d); } } - + } diff --git a/core/src/net/sf/openrocket/gui/util/SwingPreferences.java b/core/src/net/sf/openrocket/gui/util/SwingPreferences.java index 13b24962..55aed616 100644 --- a/core/src/net/sf/openrocket/gui/util/SwingPreferences.java +++ b/core/src/net/sf/openrocket/gui/util/SwingPreferences.java @@ -15,7 +15,6 @@ import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import net.sf.openrocket.arch.SystemInfo; -import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.Simulation; import net.sf.openrocket.logging.LogHelper; import net.sf.openrocket.material.Material; @@ -399,7 +398,7 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences { } public Simulation getBackgroundSimulation(Rocket rocket) { - Simulation s = new Simulation(new OpenRocketDocument(rocket), rocket); + Simulation s = new Simulation(rocket); SimulationOptions cond = s.getOptions(); cond.setTimeStep(RK4SimulationStepper.RECOMMENDED_TIME_STEP * 2); diff --git a/core/src/net/sf/openrocket/optimization/services/DefaultSimulationModifierService.java b/core/src/net/sf/openrocket/optimization/services/DefaultSimulationModifierService.java index 84e6af62..cf77e3c5 100644 --- a/core/src/net/sf/openrocket/optimization/services/DefaultSimulationModifierService.java +++ b/core/src/net/sf/openrocket/optimization/services/DefaultSimulationModifierService.java @@ -126,7 +126,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi Rocket rocket = document.getRocket(); // Simulation is used to calculate default min/max values - Simulation simulation = new Simulation(document, rocket); + Simulation simulation = new Simulation(rocket); simulation.getConfiguration().setMotorConfigurationID(null); for (RocketComponent c : rocket) { diff --git a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java index d8f44ba0..139fb688 100644 --- a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java +++ b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java @@ -90,12 +90,6 @@ public class BasicEventSimulationEngine implements SimulationEngine { } SimulationListenerHelper.firePostStep(status); - // Calculate values for custom expressions - FlightDataBranch data = status.getFlightData(); - ArrayList allExpressions = status.getSimulationConditions().getSimulation().getDocument().getCustomExpressions(); - for (CustomExpression expression : allExpressions ) { - data.setValue(expression.getType(), expression.evaluateDouble(status)); - } // Check for NaN values in the simulation status checkNaN(); diff --git a/core/src/net/sf/openrocket/simulation/customexpression/CustomExpression.java b/core/src/net/sf/openrocket/simulation/customexpression/CustomExpression.java index 2ac41ffc..ddafd9bf 100644 --- a/core/src/net/sf/openrocket/simulation/customexpression/CustomExpression.java +++ b/core/src/net/sf/openrocket/simulation/customexpression/CustomExpression.java @@ -175,7 +175,7 @@ public class CustomExpression implements Cloneable{ names.add(type.getName()); if (doc != null){ - ArrayList expressions = doc.getCustomExpressions(); + List expressions = doc.getCustomExpressions(); for (CustomExpression exp : expressions ){ if (exp != this) names.add(exp.getName()); @@ -412,7 +412,7 @@ public class CustomExpression implements Cloneable{ */ public void addToDocument(){ // Abort if exact expression already in - ArrayList expressions = doc.getCustomExpressions(); + List expressions = doc.getCustomExpressions(); if ( !expressions.isEmpty() ) { // check if expression already exists if ( expressions.contains(this) ){ diff --git a/core/src/net/sf/openrocket/simulation/customexpression/CustomExpressionSimulationListener.java b/core/src/net/sf/openrocket/simulation/customexpression/CustomExpressionSimulationListener.java new file mode 100644 index 00000000..d1ce6e97 --- /dev/null +++ b/core/src/net/sf/openrocket/simulation/customexpression/CustomExpressionSimulationListener.java @@ -0,0 +1,34 @@ +package net.sf.openrocket.simulation.customexpression; + +import java.util.ArrayList; +import java.util.List; + +import net.sf.openrocket.simulation.FlightDataBranch; +import net.sf.openrocket.simulation.SimulationStatus; +import net.sf.openrocket.simulation.exception.SimulationException; +import net.sf.openrocket.simulation.listeners.AbstractSimulationListener; + +public class CustomExpressionSimulationListener extends AbstractSimulationListener { + + private final List expressions; + + public CustomExpressionSimulationListener(List expressions) { + super(); + this.expressions = expressions; + } + + @Override + public void postStep(SimulationStatus status) throws SimulationException { + if ( expressions == null || expressions.size() == 0 ) { + return; + } + // Calculate values for custom expressions + FlightDataBranch data = status.getFlightData(); + for (CustomExpression expression : expressions ) { + data.setValue(expression.getType(), expression.evaluateDouble(status)); + } + + + } + +} diff --git a/core/test/net/sf/openrocket/optimization/rocketoptimization/TestRocketOptimizationFunction.java b/core/test/net/sf/openrocket/optimization/rocketoptimization/TestRocketOptimizationFunction.java index fe2084f0..48cc648b 100644 --- a/core/test/net/sf/openrocket/optimization/rocketoptimization/TestRocketOptimizationFunction.java +++ b/core/test/net/sf/openrocket/optimization/rocketoptimization/TestRocketOptimizationFunction.java @@ -1,7 +1,6 @@ package net.sf.openrocket.optimization.rocketoptimization; import static org.junit.Assert.*; -import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.Simulation; import net.sf.openrocket.optimization.general.OptimizationException; import net.sf.openrocket.optimization.general.Point; @@ -40,7 +39,7 @@ public class TestRocketOptimizationFunction { @Test public void testNormalEvaluation() throws InterruptedException, OptimizationException { final Rocket rocket = new Rocket(); - final Simulation simulation = new Simulation(new OpenRocketDocument(rocket), rocket); + final Simulation simulation = new Simulation(rocket); final double p1 = 0.4; final double p2 = 0.7; @@ -86,7 +85,7 @@ public class TestRocketOptimizationFunction { @Test public void testNaNValue() throws InterruptedException, OptimizationException { final Rocket rocket = new Rocket(); - final Simulation simulation = new Simulation(new OpenRocketDocument(rocket), rocket); + final Simulation simulation = new Simulation(rocket); final double p1 = 0.4; final double p2 = 0.7; @@ -123,7 +122,7 @@ public class TestRocketOptimizationFunction { @Test public void testOutsideDomain() throws InterruptedException, OptimizationException { final Rocket rocket = new Rocket(); - final Simulation simulation = new Simulation(new OpenRocketDocument(rocket), rocket); + final Simulation simulation = new Simulation(rocket); final double p1 = 0.4; final double p2 = 0.7; @@ -164,7 +163,7 @@ public class TestRocketOptimizationFunction { @Test public void testOutsideDomain2() throws InterruptedException, OptimizationException { final Rocket rocket = new Rocket(); - final Simulation simulation = new Simulation(new OpenRocketDocument(rocket), rocket); + final Simulation simulation = new Simulation(rocket); final double p1 = 0.4; final double p2 = 0.7; @@ -197,7 +196,7 @@ public class TestRocketOptimizationFunction { public void testNewSimulationInstance() { final Rocket rocket = new Rocket(); rocket.setName("Foobar"); - final Simulation simulation = new Simulation(new OpenRocketDocument(rocket), rocket); + final Simulation simulation = new Simulation(rocket); simulation.setName("MySim"); RocketOptimizationFunction function = new RocketOptimizationFunction(simulation, diff --git a/core/test/net/sf/openrocket/optimization/rocketoptimization/modifiers/TestGenericModifier.java b/core/test/net/sf/openrocket/optimization/rocketoptimization/modifiers/TestGenericModifier.java index 0fb6d13f..deacacf4 100644 --- a/core/test/net/sf/openrocket/optimization/rocketoptimization/modifiers/TestGenericModifier.java +++ b/core/test/net/sf/openrocket/optimization/rocketoptimization/modifiers/TestGenericModifier.java @@ -2,7 +2,6 @@ package net.sf.openrocket.optimization.rocketoptimization.modifiers; import static net.sf.openrocket.util.MathUtil.EPSILON; import static org.junit.Assert.assertEquals; -import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.Simulation; import net.sf.openrocket.optimization.general.OptimizationException; import net.sf.openrocket.rocketcomponent.Rocket; @@ -21,9 +20,7 @@ public class TestGenericModifier { @Before public void setup() { value = new TestValue(); - Rocket rocket = new Rocket(); - - sim = new Simulation(new OpenRocketDocument(rocket), rocket); + sim = new Simulation(new Rocket()); Object related = new Object(); -- 2.30.2