From: plaa Date: Thu, 29 Sep 2011 18:08:07 +0000 (+0000) Subject: bug fixes X-Git-Tag: upstream/1.1.9^2~9 X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=a6fd69724587af3dee9d33240a60678e0fef9444;p=debian%2Fopenrocket bug fixes git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@175 180e2498-e6e9-4542-8430-84ac67f01cd8 --- diff --git a/ChangeLog b/ChangeLog index 24d7bd2e..11b8fd24 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2011-09-26 Sampo Niskanen + + * [BUG] Thrust was computed from dropped stages + 2011-09-18 Sampo Niskanen * Remember window/dialog sizes and/or positions diff --git a/l10n/messages.properties b/l10n/messages.properties index f58be3d5..4457bc7b 100644 --- a/l10n/messages.properties +++ b/l10n/messages.properties @@ -401,6 +401,8 @@ SimuRunDlg.msg.unknownerror1 = An unknown error was encountered during the simul SimuRunDlg.msg.unknownerror2 = The program may be unstable, you should save all your designs and restart OpenRocket now! +RK4SimulationStepper.error.valuesTooLarge = Simulation values exceeded limits. Try selecting a shorter time step. + ! SimulationExportPanel SimExpPan.desc = Comma Separated Files (*.csv) @@ -469,6 +471,9 @@ simplotpanel.AUTO_NAME = Auto simplotpanel.LEFT_NAME = Left simplotpanel.RIGHT_NAME = Right simplotpanel.CUSTOM = Custom +SimulationPlotPanel.error.noPlotSelected = Please add one or more variables to plot on the Y-axis. +SimulationPlotPanel.error.noPlotSelected.title = Nothing to plot + ! Component add buttons compaddbuttons.Bodycompandfinsets = Body components and fin sets diff --git a/src/net/sf/openrocket/file/configuration/XmlContainerElement.java b/src/net/sf/openrocket/file/configuration/XmlContainerElement.java new file mode 100644 index 00000000..c227f6d0 --- /dev/null +++ b/src/net/sf/openrocket/file/configuration/XmlContainerElement.java @@ -0,0 +1,24 @@ +package net.sf.openrocket.file.configuration; + +import java.util.ArrayList; +import java.util.List; + +public class XmlContainerElement extends XmlElement { + + private ArrayList subelements = new ArrayList(); + + public XmlContainerElement(String name) { + super(name); + } + + + public void addElement(XmlElement element) { + subelements.add(element); + } + + @SuppressWarnings("unchecked") + public List getElements() { + return (List) subelements.clone(); + } + +} diff --git a/src/net/sf/openrocket/file/configuration/XmlContentElement.java b/src/net/sf/openrocket/file/configuration/XmlContentElement.java new file mode 100644 index 00000000..bf469271 --- /dev/null +++ b/src/net/sf/openrocket/file/configuration/XmlContentElement.java @@ -0,0 +1,28 @@ +package net.sf.openrocket.file.configuration; + +/** + * A simple XML element that contains textual content. + * + * @author Sampo Niskanen + */ +public class XmlContentElement extends XmlElement { + + private String content = ""; + + public XmlContentElement(String name) { + super(name); + } + + + public String getContent() { + return content; + } + + public void setContent(String content) { + if (content == null) { + throw new IllegalArgumentException("XML content cannot be null"); + } + this.content = content; + } + +} diff --git a/src/net/sf/openrocket/file/configuration/XmlElement.java b/src/net/sf/openrocket/file/configuration/XmlElement.java new file mode 100644 index 00000000..ee094340 --- /dev/null +++ b/src/net/sf/openrocket/file/configuration/XmlElement.java @@ -0,0 +1,45 @@ +package net.sf.openrocket.file.configuration; + +import java.util.HashMap; +import java.util.Map; + +/** + * A base simple XML element. A simple XML element can contain either other XML elements + * (XmlContainerElement) or textual content (XmlContentElement), but not both. + * + * @author Sampo Niskanen + */ +public abstract class XmlElement { + + private final String name; + private final HashMap attributes = new HashMap(); + + + + public XmlElement(String name) { + this.name = name; + } + + + public String getName() { + return name; + } + + public void setAttribute(String key, String value) { + attributes.put(key, value); + } + + public void removeAttribute(String key) { + attributes.remove(key); + } + + public String getAttribute(String key) { + return attributes.get(key); + } + + @SuppressWarnings("unchecked") + public Map getAttributes() { + return (Map) attributes.clone(); + } + +} diff --git a/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java b/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java index 6554a537..2e78e61e 100644 --- a/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java +++ b/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java @@ -409,10 +409,6 @@ public class OpenRocketSaver extends RocketSaver { data.add(branch.get(types[i])); } List timeData = branch.get(FlightDataType.TYPE_TIME); - if (timeData == null) { - // TODO: MEDIUM: External data may not have time data - throw new IllegalArgumentException("Data did not contain time data"); - } // Build the tag StringBuilder sb = new StringBuilder(); @@ -442,9 +438,14 @@ public class OpenRocketSaver extends RocketSaver { } for (int i = 1; i < length - 1; i++) { - if (Math.abs(timeData.get(i) - previousTime - timeSkip) < Math.abs(timeData.get(i + 1) - previousTime - timeSkip)) { + if (timeData != null) { + if (Math.abs(timeData.get(i) - previousTime - timeSkip) < Math.abs(timeData.get(i + 1) - previousTime - timeSkip)) { + writeDataPointString(data, i, sb); + previousTime = timeData.get(i); + } + } else { + // If time data is not available, write all points writeDataPointString(data, i, sb); - previousTime = timeData.get(i); } } @@ -475,8 +476,8 @@ public class OpenRocketSaver extends RocketSaver { List timeData = branch.get(FlightDataType.TYPE_TIME); if (timeData == null) { - // TODO: MEDIUM: External data may not have time data - throw new IllegalArgumentException("Data did not contain time data"); + // If time data not available, store all points + return branch.getLength(); } // Write the data diff --git a/src/net/sf/openrocket/gui/dialogs/DetailDialog.java b/src/net/sf/openrocket/gui/dialogs/DetailDialog.java index 88e3b9e6..87e36e67 100644 --- a/src/net/sf/openrocket/gui/dialogs/DetailDialog.java +++ b/src/net/sf/openrocket/gui/dialogs/DetailDialog.java @@ -6,12 +6,9 @@ import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextArea; -import net.sf.openrocket.l10n.Translator; -import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.GUIUtil; public class DetailDialog { - private static final Translator trans = Application.getTranslator(); public static void showDetailedMessageDialog(Component parentComponent, Object message, String details, String title, int messageType) { diff --git a/src/net/sf/openrocket/gui/main/SimulationRunDialog.java b/src/net/sf/openrocket/gui/main/SimulationRunDialog.java index 4405bdb5..fc4dc5af 100644 --- a/src/net/sf/openrocket/gui/main/SimulationRunDialog.java +++ b/src/net/sf/openrocket/gui/main/SimulationRunDialog.java @@ -8,8 +8,6 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import java.io.CharArrayWriter; -import java.io.PrintWriter; import java.util.Iterator; import java.util.List; import java.util.concurrent.ExecutorService; @@ -382,12 +380,6 @@ public class SimulationRunDialog extends JDialog { return; // Ignore cancellations } - // Retrieve the stack trace in a textual form - CharArrayWriter arrayWriter = new CharArrayWriter(); - arrayWriter.append(t.toString() + "\n" + "\n"); - t.printStackTrace(new PrintWriter(arrayWriter)); - String stackTrace = arrayWriter.toString(); - // Analyze the exception type if (t instanceof SimulationLaunchException) { @@ -407,7 +399,7 @@ public class SimulationRunDialog extends JDialog { trans.get("SimuRunDlg.msg.errorOccurred"), t.getMessage() }, - stackTrace, simulation.getName(), JOptionPane.ERROR_MESSAGE); + null, simulation.getName(), JOptionPane.ERROR_MESSAGE); } else { diff --git a/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java b/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java index 664d32da..898d7f67 100644 --- a/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java +++ b/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java @@ -32,6 +32,7 @@ import net.sf.openrocket.startup.Application; import net.sf.openrocket.unit.Unit; import net.sf.openrocket.util.GUIUtil; import net.sf.openrocket.util.Icons; +import net.sf.openrocket.util.Utils; /** * Panel that displays the simulation plot options to the user. @@ -105,10 +106,8 @@ public class SimulationPlotPanel extends JPanel { FlightDataBranch branch = simulation.getSimulatedData().getBranch(0); types = branch.getTypes(); - // TODO: LOW: Revert to custom if data type is not available. - configuration = defaultConfiguration.clone(); + setConfiguration(defaultConfiguration); - //// Configuration selector // Setup the combo box @@ -118,6 +117,9 @@ public class SimulationPlotPanel extends JPanel { configurationSelector.setSelectedItem(config); } } + + // FIXME: Bugs when expected branch is not present + configurationSelector.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { @@ -127,7 +129,7 @@ public class SimulationPlotPanel extends JPanel { if (conf == CUSTOM_CONFIGURATION) return; modifying++; - configuration = conf.clone().resetUnits(); + setConfiguration(conf.clone().resetUnits()); updatePlots(); modifying--; } @@ -291,6 +293,13 @@ public class SimulationPlotPanel extends JPanel { button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { + if (configuration.getTypeCount() == 0) { + JOptionPane.showMessageDialog(SimulationPlotPanel.this, + trans.get("error.noPlotSelected"), + trans.get("error.noPlotSelected.title"), + JOptionPane.ERROR_MESSAGE); + return; + } defaultConfiguration = configuration.clone(); SimulationPlotDialog.showPlot(SwingUtilities.getWindowAncestor(SimulationPlotPanel.this), simulation, configuration); @@ -303,6 +312,31 @@ public class SimulationPlotPanel extends JPanel { } + private void setConfiguration(PlotConfiguration conf) { + + boolean modified = false; + + configuration = conf.clone(); + if (!Utils.contains(types, configuration.getDomainAxisType())) { + configuration.setDomainAxisType(types[0]); + modified = true; + } + + for (int i = 0; i < configuration.getTypeCount(); i++) { + if (!Utils.contains(types, configuration.getType(i))) { + configuration.removePlotDataType(i); + i--; + modified = true; + } + } + + if (modified) { + configuration.setName(CUSTOM); + } + + } + + private void setToCustom() { modifying++; configuration.setName(CUSTOM); diff --git a/src/net/sf/openrocket/motor/MotorInstanceConfiguration.java b/src/net/sf/openrocket/motor/MotorInstanceConfiguration.java index ee54143f..a3142028 100644 --- a/src/net/sf/openrocket/motor/MotorInstanceConfiguration.java +++ b/src/net/sf/openrocket/motor/MotorInstanceConfiguration.java @@ -51,6 +51,9 @@ public final class MotorInstanceConfiguration implements Monitorable, Cloneable modID++; } + /** + * Return a list of all motor IDs in this configuration (not only ones in active stages). + */ public List getMotorIDs() { return unmodifiableIds; } diff --git a/src/net/sf/openrocket/rocketcomponent/Configuration.java b/src/net/sf/openrocket/rocketcomponent/Configuration.java index be00f1d4..404e84c3 100644 --- a/src/net/sf/openrocket/rocketcomponent/Configuration.java +++ b/src/net/sf/openrocket/rocketcomponent/Configuration.java @@ -98,14 +98,11 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi return isStageActive(0); } - public boolean isStageActive(RocketComponent stage) { - if (!(stage instanceof Stage)) { - throw new IllegalArgumentException("called with component " + stage); - } - return stages.get(stage.getParent().getChildPosition(stage)); - } - + + /** + * Check whether the stage specified by the index is active. + */ public boolean isStageActive(int stage) { if (stage >= rocket.getStageCount()) return false; @@ -255,6 +252,15 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi } + /** + * Return whether a component is in the currently active stages. + */ + public boolean isComponentActive(final RocketComponent c) { + int stage = c.getStageNumber(); + return isStageActive(stage); + } + + /** * Return the bounds of the current configuration. The bounds are cached. * @@ -366,7 +372,7 @@ public class Configuration implements Cloneable, ChangeSource, ComponentChangeLi List> list = new ArrayList>(); for (RocketComponent stage : rocket.getChildren()) { - if (isStageActive(stage)) { + if (isComponentActive(stage)) { list.add(stage.iterator(false)); } } diff --git a/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java b/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java index ea94f3b4..e971eed9 100644 --- a/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java +++ b/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java @@ -5,6 +5,8 @@ import net.sf.openrocket.models.atmosphere.AtmosphericConditions; import net.sf.openrocket.motor.MotorId; import net.sf.openrocket.motor.MotorInstance; import net.sf.openrocket.motor.MotorInstanceConfiguration; +import net.sf.openrocket.rocketcomponent.Configuration; +import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.simulation.exception.SimulationException; import net.sf.openrocket.simulation.listeners.SimulationListenerHelper; import net.sf.openrocket.util.BugException; @@ -168,16 +170,20 @@ public abstract class AbstractSimulationStepper implements SimulationStepper { return thrust; } + Configuration configuration = status.getConfiguration(); + // Iterate over the motors and calculate combined thrust - MotorInstanceConfiguration configuration = status.getMotorConfiguration(); + MotorInstanceConfiguration mic = status.getMotorConfiguration(); if (!stepMotors) { - configuration = configuration.clone(); + mic = mic.clone(); } - configuration.step(status.getSimulationTime() + timestep, acceleration, atmosphericConditions); + mic.step(status.getSimulationTime() + timestep, acceleration, atmosphericConditions); thrust = 0; - for (MotorId id : configuration.getMotorIDs()) { - MotorInstance motor = configuration.getMotorInstance(id); - thrust += motor.getThrust(); + for (MotorId id : mic.getMotorIDs()) { + if (configuration.isComponentActive((RocketComponent) mic.getMotorMount(id))) { + MotorInstance motor = mic.getMotorInstance(id); + thrust += motor.getThrust(); + } } // Post-listeners diff --git a/src/net/sf/openrocket/simulation/BasicLandingStepper.java b/src/net/sf/openrocket/simulation/BasicLandingStepper.java index 0af17121..dc67e853 100644 --- a/src/net/sf/openrocket/simulation/BasicLandingStepper.java +++ b/src/net/sf/openrocket/simulation/BasicLandingStepper.java @@ -4,14 +4,14 @@ import net.sf.openrocket.models.atmosphere.AtmosphericConditions; import net.sf.openrocket.rocketcomponent.RecoveryDevice; import net.sf.openrocket.simulation.exception.SimulationException; import net.sf.openrocket.util.Coordinate; +import net.sf.openrocket.util.GeodeticComputationStrategy; import net.sf.openrocket.util.MathUtil; +import net.sf.openrocket.util.WorldCoordinate; public class BasicLandingStepper extends AbstractSimulationStepper { private static final double RECOVERY_TIME_STEP = 0.5; - // FIXME: Add lat/lon code here as well - @Override public SimulationStatus initialize(SimulationStatus status) throws SimulationException { return status; @@ -55,6 +55,13 @@ public class BasicLandingStepper extends AbstractSimulationStepper { linearAcceleration = linearAcceleration.sub(0, 0, gravity); + // Add coriolis acceleration + Coordinate coriolisAcceleration = status.getSimulationConditions().getGeodeticComputation().getCoriolisAcceleration( + status.getRocketWorldPosition(), status.getRocketVelocity()); + linearAcceleration = linearAcceleration.add(coriolisAcceleration); + + + // Select time step double timeStep = MathUtil.min(0.5 / linearAcceleration.length(), RECOVERY_TIME_STEP); @@ -65,6 +72,12 @@ public class BasicLandingStepper extends AbstractSimulationStepper { status.setSimulationTime(status.getSimulationTime() + timeStep); + // Update the world coordinate + WorldCoordinate w = status.getSimulationConditions().getLaunchSite(); + w = status.getSimulationConditions().getGeodeticComputation().addCoordinate(w, status.getRocketPosition()); + status.setRocketWorldPosition(w); + + // Store data FlightDataBranch data = status.getFlightData(); boolean extra = status.getSimulationConditions().isCalculateExtras(); @@ -93,6 +106,14 @@ public class BasicLandingStepper extends AbstractSimulationStepper { data.setValue(FlightDataType.TYPE_REYNOLDS_NUMBER, Re); } + + data.setValue(FlightDataType.TYPE_LATITUDE, status.getRocketWorldPosition().getLatitudeRad()); + data.setValue(FlightDataType.TYPE_LONGITUDE, status.getRocketWorldPosition().getLongitudeRad()); + if (status.getSimulationConditions().getGeodeticComputation() != GeodeticComputationStrategy.FLAT) { + data.setValue(FlightDataType.TYPE_CORIOLIS_ACCELERATION, coriolisAcceleration.length()); + } + + data.setValue(FlightDataType.TYPE_VELOCITY_Z, status.getRocketVelocity().z); data.setValue(FlightDataType.TYPE_ACCELERATION_Z, linearAcceleration.z); diff --git a/src/net/sf/openrocket/simulation/RK4SimulationStepper.java b/src/net/sf/openrocket/simulation/RK4SimulationStepper.java index eea60277..6b7aad9d 100644 --- a/src/net/sf/openrocket/simulation/RK4SimulationStepper.java +++ b/src/net/sf/openrocket/simulation/RK4SimulationStepper.java @@ -6,6 +6,7 @@ import java.util.Random; import net.sf.openrocket.aerodynamics.AerodynamicForces; import net.sf.openrocket.aerodynamics.FlightConditions; import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.logging.LogHelper; import net.sf.openrocket.models.atmosphere.AtmosphericConditions; import net.sf.openrocket.simulation.exception.SimulationCalculationException; @@ -22,7 +23,9 @@ import net.sf.openrocket.util.WorldCoordinate; public class RK4SimulationStepper extends AbstractSimulationStepper { private static final LogHelper log = Application.getLogger(); + private static final Translator trans = Application.getTranslator(); + /** Random value with which to XOR the random seed value */ private static final int SEED_RANDOMIZATION = 0x23E3A01F; @@ -266,10 +269,7 @@ public class RK4SimulationStepper extends AbstractSimulationStepper { if (status.getRocketVelocity().length2() > 1e18 || status.getRocketPosition().length2() > 1e18 || status.getRocketRotationVelocity().length2() > 1e18) { - - // FIXME: Make error message better, recommend shortening time step - - throw new SimulationCalculationException("Simulation values exceeded limits"); + throw new SimulationCalculationException(trans.get("error.valuesTooLarge")); } } diff --git a/src/net/sf/openrocket/simulation/exception/SimulationCalculationException.java b/src/net/sf/openrocket/simulation/exception/SimulationCalculationException.java index 3bd61154..40f86321 100644 --- a/src/net/sf/openrocket/simulation/exception/SimulationCalculationException.java +++ b/src/net/sf/openrocket/simulation/exception/SimulationCalculationException.java @@ -9,22 +9,18 @@ package net.sf.openrocket.simulation.exception; public class SimulationCalculationException extends SimulationException { public SimulationCalculationException() { - // TODO Auto-generated constructor stub } public SimulationCalculationException(String message) { super(message); - // TODO Auto-generated constructor stub } public SimulationCalculationException(Throwable cause) { super(cause); - // TODO Auto-generated constructor stub } public SimulationCalculationException(String message, Throwable cause) { super(message, cause); - // TODO Auto-generated constructor stub } } diff --git a/src/net/sf/openrocket/util/Utils.java b/src/net/sf/openrocket/util/Utils.java index 39b3e861..93d320ef 100644 --- a/src/net/sf/openrocket/util/Utils.java +++ b/src/net/sf/openrocket/util/Utils.java @@ -17,4 +17,21 @@ public class Utils { } } + + /** + * Check whether an array contains a specified object. + * + * @param array the array to search + * @param search the object to search for + * @return whether the object was in the array + */ + public static boolean contains(Object[] array, Object search) { + for (Object o : array) { + if (equals(o, search)) { + return true; + } + } + return false; + } + }