bug fixes
authorplaa <plaa@180e2498-e6e9-4542-8430-84ac67f01cd8>
Thu, 29 Sep 2011 18:08:07 +0000 (18:08 +0000)
committerplaa <plaa@180e2498-e6e9-4542-8430-84ac67f01cd8>
Thu, 29 Sep 2011 18:08:07 +0000 (18:08 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@175 180e2498-e6e9-4542-8430-84ac67f01cd8

16 files changed:
ChangeLog
l10n/messages.properties
src/net/sf/openrocket/file/configuration/XmlContainerElement.java [new file with mode: 0644]
src/net/sf/openrocket/file/configuration/XmlContentElement.java [new file with mode: 0644]
src/net/sf/openrocket/file/configuration/XmlElement.java [new file with mode: 0644]
src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java
src/net/sf/openrocket/gui/dialogs/DetailDialog.java
src/net/sf/openrocket/gui/main/SimulationRunDialog.java
src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java
src/net/sf/openrocket/motor/MotorInstanceConfiguration.java
src/net/sf/openrocket/rocketcomponent/Configuration.java
src/net/sf/openrocket/simulation/AbstractSimulationStepper.java
src/net/sf/openrocket/simulation/BasicLandingStepper.java
src/net/sf/openrocket/simulation/RK4SimulationStepper.java
src/net/sf/openrocket/simulation/exception/SimulationCalculationException.java
src/net/sf/openrocket/util/Utils.java

index 24d7bd2e763a2446a2d15942ca92c268b0839a21..11b8fd246d8f67a2025c168f8be86efc028e7e49 100644 (file)
--- 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
index f58be3d554c968d4c3f0035c6df6896d29a26567..4457bc7b12c61135305ca69e19ddd4c754428f65 100644 (file)
@@ -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 (file)
index 0000000..c227f6d
--- /dev/null
@@ -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<XmlElement> subelements = new ArrayList<XmlElement>();
+       
+       public XmlContainerElement(String name) {
+               super(name);
+       }
+       
+       
+       public void addElement(XmlElement element) {
+               subelements.add(element);
+       }
+       
+       @SuppressWarnings("unchecked")
+       public List<XmlElement> getElements() {
+               return (List<XmlElement>) 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 (file)
index 0000000..bf46927
--- /dev/null
@@ -0,0 +1,28 @@
+package net.sf.openrocket.file.configuration;
+
+/**
+ * A simple XML element that contains textual content.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+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 (file)
index 0000000..ee09434
--- /dev/null
@@ -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 <sampo.niskanen@iki.fi>
+ */
+public abstract class XmlElement {
+       
+       private final String name;
+       private final HashMap<String, String> attributes = new HashMap<String, String>();
+       
+       
+
+       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<String, String> getAttributes() {
+               return (Map<String, String>) attributes.clone();
+       }
+       
+}
index 6554a5375446b6dd9e6fccff9510d347cff05d7b..2e78e61ed787f92bcfbc5cf7ec32efcc84a2a166 100644 (file)
@@ -409,10 +409,6 @@ public class OpenRocketSaver extends RocketSaver {
                        data.add(branch.get(types[i]));
                }
                List<Double> 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 <databranch> 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<Double> 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
index 88e3b9e640649e1768e15b61368fcb3634f3f3b4..87e36e67852418682510f1367e992e63994f9881 100644 (file)
@@ -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) {
index 4405bdb50d622d18b98c29ed87db1edc7544fe86..fc4dc5af3ea49af0521b7aae9351026d4a900332 100644 (file)
@@ -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 {
                                
index 664d32da21383bb65cd63951b1ef6de9c4d71937..898d7f67ae6d293439d5864b97577a9cac4ad872 100644 (file)
@@ -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);
index ee54143fac4794edf9214fd67ea05820cf25ad1f..a3142028d3df6e4b8c011ef1bc8fc762fe292732 100644 (file)
@@ -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<MotorId> getMotorIDs() {
                return unmodifiableIds;
        }
index be00f1d49607c0c14857ddea83dbb0df3c8e9c0d..404e84c326657df89d3669e0ae33ef2e1e8d120c 100644 (file)
@@ -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<Iterator<RocketComponent>> list = new ArrayList<Iterator<RocketComponent>>();
                        
                        for (RocketComponent stage : rocket.getChildren()) {
-                               if (isStageActive(stage)) {
+                               if (isComponentActive(stage)) {
                                        list.add(stage.iterator(false));
                                }
                        }
index ea94f3b43eada649814a8f4593aad7aa6ce1baa5..e971eed9a2a6150f23d8099eb36c55b4271dbc72 100644 (file)
@@ -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
index 0af17121516c476316eb3598816bb352558ce079..dc67e85375c60cdc8c2e15d1937f433c8db999ec 100644 (file)
@@ -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);
                
index eea602770ebbb796a49e297835693410a26318e2..6b7aad9d8312adcb7170f5556ab46ce5d9577357 100644 (file)
@@ -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"));
                }
        }
        
index 3bd61154e8a8baaf2e66f8bcf6323330668b970b..40f863210ac64bdc202f2eed686caedb0270d07d 100644 (file)
@@ -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
        }
        
 }
index 39b3e861f9ea221b58374646488ae9539e45c041..93d320ef2b5e4ad0f694b4d3855ef828dd4f7f5b 100644 (file)
@@ -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;
+       }
+       
 }