[Bugfix] Fixed Stage Separation Bugs

UI elements now change per-configuration separations not the defaults
   fixed separation configuration file-write code.
Added max-time guard for simulations at 1200 seconds.
This commit is contained in:
Daniel_M_Williams 2015-12-12 19:38:38 -05:00
parent 238726f371
commit ec05e46a0e
11 changed files with 96 additions and 70 deletions

View File

@ -150,7 +150,7 @@ class DocumentConfig {
"auto",
Reflection.findMethod(BodyTube.class, "setOuterRadiusAutomatic", boolean.class)));
// ParallelStage
// Parallel Stage
setters.put("ParallelStage:instancecount", new IntSetter(
Reflection.findMethod(ParallelStage.class, "setInstanceCount",int.class)));
setters.put("ParallelStage:radialoffset", new DoubleSetter(

View File

@ -51,24 +51,20 @@ public class AxialStageSaver extends ComponentAssemblySaver {
// Note - getFlightConfigurationIDs returns at least one element. The first element
// is null and means "default".
int configCount = rocket.getConfigSet().size();
if (1 < configCount ){
for (FlightConfiguration curConfig : rocket.getConfigSet()){
FlightConfigurationID fcid = curConfig.getFlightConfigurationID();
if (fcid == null) {
continue;
}
if (stage.getSeparationConfigurations().isDefault(fcid)) {
continue;
}
StageSeparationConfiguration separationConfig = stage.getSeparationConfigurations().get(fcid);
elements.add("<separationconfiguration configid=\"" + fcid.key + "\">");
elements.addAll(separationConfig(separationConfig, true));
elements.add("</separationconfiguration>");
for (FlightConfiguration curConfig : rocket.getConfigSet()){
FlightConfigurationID fcid = curConfig.getFlightConfigurationID();
if (fcid == null) {
continue;
}
StageSeparationConfiguration curSepCfg = stage.getSeparationConfigurations().get(fcid);
if( stage.getSeparationConfigurations().isDefault( curSepCfg )){
continue;
}
elements.add("<separationconfiguration configid=\"" + fcid.key + "\">");
elements.addAll(separationConfig(curSepCfg, true));
elements.add("</separationconfiguration>");
}
}
}

View File

@ -12,12 +12,12 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
private static final Translator trans = Application.getTranslator();
//private static final Logger log = LoggerFactory.getLogger(AxialStage.class);
protected ParameterSet<StageSeparationConfiguration> separationConfigurations;
protected ParameterSet<StageSeparationConfiguration> separations;
protected int stageNumber;
public AxialStage(){
this.separationConfigurations = new ParameterSet<StageSeparationConfiguration>(
this.separations = new ParameterSet<StageSeparationConfiguration>(
this, ComponentChangeEvent.EVENT_CHANGE, new StageSeparationConfiguration());
this.relativePosition = Position.AFTER;
this.stageNumber = 0;
@ -35,7 +35,7 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
}
public ParameterSet<StageSeparationConfiguration> getSeparationConfigurations() {
return separationConfigurations;
return separations;
}
// not strictly accurate, but this should provide an acceptable estimate for total vehicle size
@ -74,13 +74,13 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
@Override
public void cloneFlightConfiguration(FlightConfigurationID oldConfigId, FlightConfigurationID newConfigId) {
separationConfigurations.cloneFlightConfiguration(oldConfigId, newConfigId);
separations.cloneFlightConfiguration(oldConfigId, newConfigId);
}
@Override
protected RocketComponent copyWithOriginalID() {
AxialStage copy = (AxialStage) super.copyWithOriginalID();
copy.separationConfigurations = new ParameterSet<StageSeparationConfiguration>(separationConfigurations,
copy.separations = new ParameterSet<StageSeparationConfiguration>(separations,
copy, ComponentChangeEvent.EVENT_CHANGE);
return copy;
}
@ -135,6 +135,12 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
// }
return buf;
}
public String toDebugSeparation() {
StringBuilder buff = new StringBuilder();
buff.append( this.separations.toDebug() );
return buff.toString();
}

View File

@ -82,7 +82,7 @@ public class ParallelStage extends AxialStage implements FlightConfigurableCompo
@Override
public void cloneFlightConfiguration(FlightConfigurationID oldConfigId, FlightConfigurationID newConfigId) {
this.separationConfigurations.cloneFlightConfiguration(oldConfigId, newConfigId);
this.separations.cloneFlightConfiguration(oldConfigId, newConfigId);
}
@Override

View File

@ -22,7 +22,7 @@ import net.sf.openrocket.util.Utils;
*/
public class ParameterSet<E extends FlightConfigurableParameter<E>> implements FlightConfigurable<E> {
private static final Logger log = LoggerFactory.getLogger(ParameterSet.class);
//private static final Logger log = LoggerFactory.getLogger(ParameterSet.class);
protected final HashMap<FlightConfigurationID, E> map = new HashMap<FlightConfigurationID, E>();
protected E defaultValue;
@ -185,12 +185,8 @@ public class ParameterSet<E extends FlightConfigurableParameter<E>> implements F
@Override
public void reset( FlightConfigurationID fcid) {
// enforce at least one value in the set
if( 1 < this.map.size() ){
if( fcid.isValid() ){
set( fcid, null);
}else{
log.warn(" attempted to remove last element from the FlightConfigurationSet<"+this.getDefault().getClass().getSimpleName()+"> attached to: "+component.getName()+". Ignoring. ");
return;
}
}
@ -230,22 +226,27 @@ public class ParameterSet<E extends FlightConfigurableParameter<E>> implements F
public String toDebug(){
StringBuilder buf = new StringBuilder();
buf.append(String.format("====== Dumping ConfigurationSet for: '%s' of type: %s ======\n", this.component.getName(), this.component.getClass().getSimpleName() ));
buf.append(String.format(" >> FlightConfigurationSet (%d configurations)\n", this.size() ));
buf.append(String.format(" >> ParameterSet<%s> (%d configurations)\n", this.defaultValue.getClass().getSimpleName(), this.size() ));
if( 0 == this.map.size() ){
buf.append(String.format(" >> [%s]= %s\n", "*DEFAULT*", this.getDefault().toString() ));
}else{
for( FlightConfigurationID loopFCID : this.getSortedConfigurationIDs()){
String shortKey = loopFCID.toShortKey();
E inst = this.map.get(loopFCID);
if( this.isDefault(inst)){
shortKey = "*"+shortKey+"*";
}
buf.append(String.format(" >> [%s]= %s\n", shortKey, inst ));
buf.append(String.format(" >> [%s]= %s\n", "DEFAULT", this.getDefault().toString() ));
for( FlightConfigurationID loopFCID : this.getSortedConfigurationIDs()){
String shortKey = loopFCID.toShortKey();
E inst = this.map.get(loopFCID);
if( this.isDefault(inst)){
shortKey = "*"+shortKey+"*";
}
buf.append(String.format(" >> [%s]= %s\n", shortKey, inst ));
}
return buf.toString();
}
/*
* Clears all configuration-specific settings -- meaning querying the parameter for any configuration will return the default value.
*
*/
public void clear() {
this.map.clear();
}
}

View File

@ -100,7 +100,7 @@ public class StageSeparationConfiguration implements FlightConfigurableParameter
private final List<StateChangeListener> listeners = new ArrayList<StateChangeListener>();
private SeparationEvent separationEvent = SeparationEvent.UPPER_IGNITION;
private SeparationEvent separationEvent = SeparationEvent.NEVER;
private double separationDelay = 0;
public SeparationEvent getSeparationEvent() {

View File

@ -21,6 +21,7 @@ import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration;
import net.sf.openrocket.simulation.FlightEvent.Type;
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
@ -483,6 +484,12 @@ public class BasicEventSimulationEngine implements SimulationEngine {
}
if( 1200 < currentStatus.getSimulationTime() ){
ret = false;
log.error("Simulation hit max time (1200s): aborting.");
currentStatus.getFlightData().addEvent(new FlightEvent( FlightEvent.Type.SIMULATION_END, currentStatus.getSimulationTime()));
}
// If no motor has ignited, abort
if (!currentStatus.isMotorIgnited()) {

View File

@ -14,6 +14,7 @@ import net.sf.openrocket.gui.components.StyledLabel;
import net.sf.openrocket.gui.components.StyledLabel.Style;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration;
import net.sf.openrocket.startup.Application;
@ -31,7 +32,6 @@ public class AxialStageConfig extends ComponentAssemblyConfig {
tabbedPane.insertTab(trans.get("StageConfig.tab.Separation"), null, tab,
trans.get("StageConfig.tab.Separation.ttip"), 2);
}
}
@ -41,14 +41,30 @@ public class AxialStageConfig extends ComponentAssemblyConfig {
// Select separation event
panel.add(new StyledLabel(trans.get("StageConfig.separation.lbl.title") + " " + CommonStrings.dagger, Style.BOLD), "spanx, wrap rel");
StageSeparationConfiguration config = stage.getSeparationConfigurations().getDefault();
JComboBox<?> combo = new JComboBox(new EnumModel<StageSeparationConfiguration.SeparationEvent>(config, "SeparationEvent"));
FlightConfiguration flConfig = stage.getRocket().getDefaultConfiguration();
StageSeparationConfiguration sepConfig = stage.getSeparationConfigurations().get(flConfig.getId());
// to ensure the configuration is distinct, and we're not modifying the default
if( sepConfig == stage.getSeparationConfigurations().getDefault() ){
sepConfig = new StageSeparationConfiguration();
stage.getSeparationConfigurations().set( flConfig.getId(), sepConfig );
}
@SuppressWarnings("unchecked")
JComboBox<?> combo = new JComboBox<StageSeparationConfiguration.SeparationEvent>(
new EnumModel<StageSeparationConfiguration.SeparationEvent>( sepConfig, "SeparationEvent",
new StageSeparationConfiguration.SeparationEvent[] {
StageSeparationConfiguration.SeparationEvent.UPPER_IGNITION,
StageSeparationConfiguration.SeparationEvent.IGNITION,
StageSeparationConfiguration.SeparationEvent.BURNOUT,
StageSeparationConfiguration.SeparationEvent.EJECTION,
StageSeparationConfiguration.SeparationEvent.LAUNCH,
StageSeparationConfiguration.SeparationEvent.NEVER }));
//combo.setSelectedItem(sepConfig);
panel.add(combo, "");
// ... and delay
panel.add(new JLabel(trans.get("StageConfig.separation.lbl.plus")), "");
DoubleModel dm = new DoubleModel(config, "SeparationDelay", 0);
DoubleModel dm = new DoubleModel( sepConfig, "SeparationDelay", 0);
JSpinner spin = new JSpinner(dm.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
panel.add(spin, "width 45");

View File

@ -16,27 +16,18 @@ import net.sf.openrocket.gui.adaptors.EnumModel;
import net.sf.openrocket.gui.adaptors.IntegerModel;
import net.sf.openrocket.gui.components.UnitSelector;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.ParallelStage;
import net.sf.openrocket.rocketcomponent.ComponentAssembly;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.ChangeSource;
public class ParallelStageConfig extends RocketComponentConfig {
public class ParallelStageConfig extends AxialStageConfig {
private static final long serialVersionUID = -944969957186522471L;
private static final Translator trans = Application.getTranslator();
public ParallelStageConfig(OpenRocketDocument document, RocketComponent component) {
super(document, component);
// For DEBUG purposes
if( component instanceof AxialStage ){
System.err.println(" Dumping AxialStage tree info for devel / debugging.");
System.err.println(component.toDebugTree());
}
// only stages which are actually off-centerline will get the dialog here:
tabbedPane.insertTab( trans.get("RocketCompCfg.tab.Parallel"), null, parallelTab( (ParallelStage)component ), trans.get("RocketCompCfg.tab.ParallelComment"), 1);
}
@ -88,6 +79,7 @@ public class ParallelStageConfig extends RocketComponentConfig {
motherPanel.add( positionLabel);
// EnumModel(ChangeSource source, String valueName, Enum<T>[] values) {
@SuppressWarnings("unchecked")
ComboBoxModel<RocketComponent.Position> relativePositionMethodModel = new EnumModel<RocketComponent.Position>(component, "RelativePositionMethod",
new RocketComponent.Position[] {
RocketComponent.Position.TOP,

View File

@ -23,6 +23,7 @@ import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.FlightConfigurationID;
import net.sf.openrocket.rocketcomponent.ParameterSet;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration;
import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration.SeparationEvent;
@ -39,11 +40,14 @@ public class SeparationSelectionDialog extends JDialog {
private StageSeparationConfiguration newConfiguration;
public SeparationSelectionDialog(Window parent, final Rocket rocket, final AxialStage component) {
public SeparationSelectionDialog(Window parent, final Rocket rocket, final AxialStage stage) {
super(parent, trans.get("edtmotorconfdlg.title.Selectseparationconf"), Dialog.ModalityType.APPLICATION_MODAL);
final FlightConfigurationID id = rocket.getDefaultConfiguration().getFlightConfigurationID();
newConfiguration = component.getSeparationConfigurations().get(id).clone();
newConfiguration = stage.getSeparationConfigurations().get(id);
if( stage.getSeparationConfigurations().isDefault( newConfiguration )){
newConfiguration = newConfiguration.clone();
}
JPanel panel = new JPanel(new MigLayout("fill"));
@ -51,7 +55,7 @@ public class SeparationSelectionDialog extends JDialog {
// Select separation event
panel.add(new JLabel(trans.get("SeparationSelectionDialog.opt.title")), "span, wrap rel");
boolean isDefault = component.getSeparationConfigurations().isDefault(id);
boolean isDefault = stage.getSeparationConfigurations().isDefault(id);
final JRadioButton defaultButton = new JRadioButton(trans.get("SeparationSelectionDialog.opt.default"), isDefault);
panel.add(defaultButton, "span, gapleft para, wrap rel");
String str = trans.get("SeparationSelectionDialog.opt.override");
@ -65,12 +69,13 @@ public class SeparationSelectionDialog extends JDialog {
// Select the button based on current configuration. If the configuration is overridden
// The the overrideButton is selected.
boolean isOverridden = !component.getSeparationConfigurations().isDefault(id);
boolean isOverridden = !stage.getSeparationConfigurations().isDefault(id);
if (isOverridden) {
overrideButton.setSelected(true);
}
final JComboBox event = new JComboBox(new EnumModel<SeparationEvent>(newConfiguration, "SeparationEvent"));
@SuppressWarnings("unchecked")
final JComboBox<?> event = new JComboBox<SeparationEvent>(new EnumModel<SeparationEvent>(newConfiguration, "SeparationEvent"));
event.setSelectedItem(newConfiguration.getSeparationEvent());
panel.add(event, "wrap rel");
@ -92,14 +97,14 @@ public class SeparationSelectionDialog extends JDialog {
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if( newConfiguration.getSeparationEvent() == StageSeparationConfiguration.SeparationEvent.NEVER ){
newConfiguration.setSeparationDelay(0);
}
if (defaultButton.isSelected()) {
// FlightConfigurationSet<StageSeparationConfiguration> sepConfigSet = component.getSeparationConfigurations();
// StageSeparationConfiguration sepConfig = sepConfigSet.get(FlightConfigurationID.DEFAULT_CONFIGURATION_ID);
// component.getSeparationConfigurations().setDefault( sepConfig);
// old version
//component.getSeparationConfigurations().setDefault( fcid?, newConfiguration);
stage.getSeparationConfigurations().clear();
stage.getSeparationConfigurations().setDefault( newConfiguration);
} else {
component.getSeparationConfigurations().set(id, newConfiguration);
stage.getSeparationConfigurations().set(id, newConfiguration);
}
SeparationSelectionDialog.this.setVisible(false);
}

View File

@ -24,7 +24,7 @@ import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.UnitGroup;
public class SeparationConfigurationPanel extends FlightConfigurablePanel<AxialStage> {
private static final long serialVersionUID = -1556652925279847316L;
static final Translator trans = Application.getTranslator();
private RocketDescriptor descriptor = Application.getInjector().getInstance(RocketDescriptor.class);
@ -67,6 +67,8 @@ public class SeparationConfigurationPanel extends FlightConfigurablePanel<AxialS
protected JTable initializeTable() {
//// Separation selection
separationTableModel = new FlightConfigurableTableModel<AxialStage>(AxialStage.class, rocket) {
private static final long serialVersionUID = 7979648984099308970L;
@Override
protected boolean includeComponent(AxialStage component) {
return component.getStageNumber() > 0;
@ -121,7 +123,8 @@ public class SeparationConfigurationPanel extends FlightConfigurablePanel<AxialS
}
private class SeparationTableCellRenderer extends FlightConfigurablePanel<AxialStage>.FlightConfigurableCellRenderer {
private static final long serialVersionUID = -7066580803931938686L;
@Override
protected JLabel format(AxialStage stage, FlightConfigurationID configId, JLabel label) {
StageSeparationConfiguration sepConfig = stage.getSeparationConfigurations().get(configId);