bug fixes

This commit is contained in:
Sampo Niskanen 2011-09-29 18:08:07 +00:00
parent d2cf2aa180
commit 85b6d7358b
16 changed files with 227 additions and 48 deletions

View File

@ -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

View 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

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View 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

View 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) {

View 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 {

View 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);

View 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;
}

View 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));
}
}

View 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

View 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);

View 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"));
}
}

View 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
}
}

View 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;
}
}