From ec05e46a0e539955cd6b70d07a9d364316438d95 Mon Sep 17 00:00:00 2001 From: Daniel_M_Williams Date: Sat, 12 Dec 2015 19:38:38 -0500 Subject: [PATCH] [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. --- .../openrocket/importt/DocumentConfig.java | 2 +- .../openrocket/savers/AxialStageSaver.java | 30 +++++++-------- .../rocketcomponent/AxialStage.java | 16 +++++--- .../rocketcomponent/ParallelStage.java | 2 +- .../rocketcomponent/ParameterSet.java | 37 ++++++++++--------- .../StageSeparationConfiguration.java | 2 +- .../BasicEventSimulationEngine.java | 7 ++++ .../gui/configdialog/AxialStageConfig.java | 24 ++++++++++-- .../gui/configdialog/ParallelStageConfig.java | 12 +----- .../SeparationSelectionDialog.java | 27 ++++++++------ .../SeparationConfigurationPanel.java | 7 +++- 11 files changed, 96 insertions(+), 70 deletions(-) diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java index 60fc35d26..2b191429e 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java @@ -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( diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/AxialStageSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/AxialStageSaver.java index b9740f33f..92bec2dce 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/AxialStageSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/AxialStageSaver.java @@ -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(""); - elements.addAll(separationConfig(separationConfig, true)); - elements.add(""); - + 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(""); + elements.addAll(separationConfig(curSepCfg, true)); + elements.add(""); } } } diff --git a/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java b/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java index 5288ce692..0b1a34cd5 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java +++ b/core/src/net/sf/openrocket/rocketcomponent/AxialStage.java @@ -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 separationConfigurations; + protected ParameterSet separations; protected int stageNumber; public AxialStage(){ - this.separationConfigurations = new ParameterSet( + this.separations = new ParameterSet( 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 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(separationConfigurations, + copy.separations = new ParameterSet(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(); + } diff --git a/core/src/net/sf/openrocket/rocketcomponent/ParallelStage.java b/core/src/net/sf/openrocket/rocketcomponent/ParallelStage.java index 6ec4fa2a1..12c346d47 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/ParallelStage.java +++ b/core/src/net/sf/openrocket/rocketcomponent/ParallelStage.java @@ -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 diff --git a/core/src/net/sf/openrocket/rocketcomponent/ParameterSet.java b/core/src/net/sf/openrocket/rocketcomponent/ParameterSet.java index cab9c6e4c..12c84dbdc 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/ParameterSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/ParameterSet.java @@ -22,7 +22,7 @@ import net.sf.openrocket.util.Utils; */ public class ParameterSet> implements FlightConfigurable { - private static final Logger log = LoggerFactory.getLogger(ParameterSet.class); + //private static final Logger log = LoggerFactory.getLogger(ParameterSet.class); protected final HashMap map = new HashMap(); protected E defaultValue; @@ -185,12 +185,8 @@ public class ParameterSet> 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> 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(); + } } diff --git a/core/src/net/sf/openrocket/rocketcomponent/StageSeparationConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/StageSeparationConfiguration.java index e748f1e6f..c4b1e1d72 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/StageSeparationConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/StageSeparationConfiguration.java @@ -100,7 +100,7 @@ public class StageSeparationConfiguration implements FlightConfigurableParameter private final List listeners = new ArrayList(); - private SeparationEvent separationEvent = SeparationEvent.UPPER_IGNITION; + private SeparationEvent separationEvent = SeparationEvent.NEVER; private double separationDelay = 0; public SeparationEvent getSeparationEvent() { diff --git a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java index 061edbb42..c4d2d35e9 100644 --- a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java +++ b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java @@ -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()) { diff --git a/swing/src/net/sf/openrocket/gui/configdialog/AxialStageConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/AxialStageConfig.java index 73994c763..1f4f551b6 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/AxialStageConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/AxialStageConfig.java @@ -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(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( + new EnumModel( 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"); diff --git a/swing/src/net/sf/openrocket/gui/configdialog/ParallelStageConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/ParallelStageConfig.java index 21286436d..9faf54ced 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/ParallelStageConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/ParallelStageConfig.java @@ -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[] values) { + @SuppressWarnings("unchecked") ComboBoxModel relativePositionMethodModel = new EnumModel(component, "RelativePositionMethod", new RocketComponent.Position[] { RocketComponent.Position.TOP, diff --git a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationSelectionDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationSelectionDialog.java index b488bb959..b2885c431 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationSelectionDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationSelectionDialog.java @@ -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(newConfiguration, "SeparationEvent")); + @SuppressWarnings("unchecked") + final JComboBox event = new JComboBox(new EnumModel(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 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); } diff --git a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/SeparationConfigurationPanel.java b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/SeparationConfigurationPanel.java index 123e66e75..3b7dc84b6 100644 --- a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/SeparationConfigurationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/SeparationConfigurationPanel.java @@ -24,7 +24,7 @@ import net.sf.openrocket.startup.Application; import net.sf.openrocket.unit.UnitGroup; public class SeparationConfigurationPanel extends FlightConfigurablePanel { - + 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(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.FlightConfigurableCellRenderer { - + private static final long serialVersionUID = -7066580803931938686L; + @Override protected JLabel format(AxialStage stage, FlightConfigurationID configId, JLabel label) { StageSeparationConfiguration sepConfig = stage.getSeparationConfigurations().get(configId);