diff --git a/core/src/net/sf/openrocket/document/Simulation.java b/core/src/net/sf/openrocket/document/Simulation.java index a695a1165..09d118dc3 100644 --- a/core/src/net/sf/openrocket/document/Simulation.java +++ b/core/src/net/sf/openrocket/document/Simulation.java @@ -225,7 +225,14 @@ public class Simulation implements ChangeSource, Cloneable { this.configId = fcid; fireChangeEvent(); } - + + /** + * Applies the simulation options to the simulation. + * @param options the simulation options to apply. + */ + public void copySimulationOptionsFrom(SimulationOptions options) { + this.options.copyConditionsFrom(options); + } // /** // * Return a newly created Configuration for this simulation. The configuration diff --git a/core/src/net/sf/openrocket/file/rasaero/importt/BoosterHandler.java b/core/src/net/sf/openrocket/file/rasaero/importt/BoosterHandler.java index d0f5a54cf..0272e06e6 100644 --- a/core/src/net/sf/openrocket/file/rasaero/importt/BoosterHandler.java +++ b/core/src/net/sf/openrocket/file/rasaero/importt/BoosterHandler.java @@ -23,7 +23,7 @@ public class BoosterHandler extends BodyTubeHandler { private double boatTailLength; private double boatTailRearDiameter; - public BoosterHandler(DocumentLoadingContext context, RocketComponent parent, WarningSet warnings) { + public BoosterHandler(DocumentLoadingContext context, RocketComponent parent) { super(context); if (parent == null) { throw new IllegalArgumentException("The parent component of a body tube may not be null."); diff --git a/core/src/net/sf/openrocket/file/rasaero/importt/FinCanHandler.java b/core/src/net/sf/openrocket/file/rasaero/importt/FinCanHandler.java index a35de9929..2806ba7cc 100644 --- a/core/src/net/sf/openrocket/file/rasaero/importt/FinCanHandler.java +++ b/core/src/net/sf/openrocket/file/rasaero/importt/FinCanHandler.java @@ -22,13 +22,12 @@ import java.util.HashMap; * @author Sibo Van Gool */ public class FinCanHandler extends BodyTubeHandler { - private final BodyTube parentBodyTube; private final PodSet finCan = new PodSet(); private double insideDiameter; private double shoulderLength; - public FinCanHandler(DocumentLoadingContext context, RocketComponent parent, WarningSet warnings) { + public FinCanHandler(DocumentLoadingContext context, RocketComponent parent) { super(context); if (parent == null) { throw new IllegalArgumentException("The parent component of a body tube may not be null."); @@ -43,8 +42,8 @@ public class FinCanHandler extends BodyTubeHandler { } // The fin can is a pod set child of the parent body tube. - this.parentBodyTube = (BodyTube) lastChild; - this.parentBodyTube.addChild(this.finCan); + BodyTube parentBodyTube = (BodyTube) lastChild; + parentBodyTube.addChild(this.finCan); this.finCan.setInstanceCount(1); this.finCan.setRadius(RadiusMethod.FREE, 0); this.finCan.addChild(this.bodyTube); diff --git a/core/src/net/sf/openrocket/file/rasaero/importt/LaunchSiteHandler.java b/core/src/net/sf/openrocket/file/rasaero/importt/LaunchSiteHandler.java index 0d83e65a3..197af5269 100644 --- a/core/src/net/sf/openrocket/file/rasaero/importt/LaunchSiteHandler.java +++ b/core/src/net/sf/openrocket/file/rasaero/importt/LaunchSiteHandler.java @@ -1,8 +1,6 @@ package net.sf.openrocket.file.rasaero.importt; import net.sf.openrocket.aerodynamics.WarningSet; -import net.sf.openrocket.document.Simulation; -import net.sf.openrocket.file.DocumentLoadingContext; import net.sf.openrocket.file.simplesax.AbstractElementHandler; import net.sf.openrocket.file.simplesax.ElementHandler; import net.sf.openrocket.file.simplesax.PlainTextHandler; @@ -18,15 +16,10 @@ import java.util.HashMap; * @author Sibo Van Gool */ public class LaunchSiteHandler extends AbstractElementHandler { - private final DocumentLoadingContext context; - private final SimulationOptions simulationOptions; + private final SimulationOptions launchSiteSettings; - public LaunchSiteHandler(DocumentLoadingContext context) { - this.context = context; - Simulation simulation = new Simulation(context.getOpenRocketDocument().getRocket()); - simulation.setName("RASAero II Launch Site"); - this.simulationOptions = simulation.getOptions(); - this.context.getOpenRocketDocument().addSimulation(simulation); + public LaunchSiteHandler(final SimulationOptions launchSiteSettings) { + this.launchSiteSettings = launchSiteSettings; } @Override public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) throws SAXException { @@ -43,18 +36,18 @@ public class LaunchSiteHandler extends AbstractElementHandler { public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { try { if (RASAeroCommonConstants.LAUNCH_ALTITUDE.equals(element)) { - simulationOptions.setLaunchAltitude(Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_ALTITUDE); + launchSiteSettings.setLaunchAltitude(Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_ALTITUDE); } else if (RASAeroCommonConstants.LAUNCH_PRESSURE.equals(element)) { - simulationOptions.setLaunchPressure(Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_PRESSURE); + launchSiteSettings.setLaunchPressure(Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_PRESSURE); } else if (RASAeroCommonConstants.LAUNCH_ROD_ANGLE.equals(element)) { - simulationOptions.setLaunchRodAngle(Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_ANGLE); + launchSiteSettings.setLaunchRodAngle(Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_ANGLE); } else if (RASAeroCommonConstants.LAUNCH_ROD_LENGTH.equals(element)) { - simulationOptions.setLaunchRodLength(Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_ALTITUDE); + launchSiteSettings.setLaunchRodLength(Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_ALTITUDE); } else if (RASAeroCommonConstants.LAUNCH_TEMPERATURE.equals(element)) { - simulationOptions.setLaunchTemperature( + launchSiteSettings.setLaunchTemperature( RASAeroCommonConstants.RASAERO_TO_OPENROCKET_TEMPERATURE(Double.parseDouble(content))); } else if (RASAeroCommonConstants.LAUNCH_WIND_SPEED.equals(element)) { - simulationOptions.setWindSpeedAverage(Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_SPEED); + launchSiteSettings.setWindSpeedAverage(Double.parseDouble(content) / RASAeroCommonConstants.RASAERO_TO_OPENROCKET_SPEED); } } catch (NumberFormatException e) { warnings.add("Invalid number format for element " + element + ", ignoring."); diff --git a/core/src/net/sf/openrocket/file/rasaero/importt/RASAeroCommonConstants.java b/core/src/net/sf/openrocket/file/rasaero/importt/RASAeroCommonConstants.java index fb4dc94ba..c58a11b7a 100644 --- a/core/src/net/sf/openrocket/file/rasaero/importt/RASAeroCommonConstants.java +++ b/core/src/net/sf/openrocket/file/rasaero/importt/RASAeroCommonConstants.java @@ -39,7 +39,7 @@ public class RASAeroCommonConstants { // Nose cone settings public static final String SHAPE = "Shape"; public static final String POWER_LAW = "PowerLaw"; - public static final String BLUNT_RADIUS = "BluntRadius"; + //public static final String BLUNT_RADIUS = "BluntRadius"; private static final Map RASAeroNoseConeShapeMap = new HashMap<>(); // Transition settings @@ -107,6 +107,21 @@ public class RASAeroCommonConstants { public static final String DEPLOYMENT_APOGEE = "Apogee"; public static final String DEPLOYMENT_ALTITUDE = "Altitude"; + // Simulation settings + public static final String SIMULATION_LIST = "SimulationList"; + public static final String SIMULATION = "Simulation"; + public static final String SUSTAINER_ENGINE = "SustainerEngine"; + // TODO: SustainerLaunchWt, SustainerCG? + public static final String SUSTAINER_IGNITION_DELAY = "SustainerIgnitionDelay"; + public static final String BOOSTER1_ENGINE = "Booster1Engine"; + public static final String BOOSTER1_SEPARATION_DELAY = "Booster1SeparationDelay"; // Delay after booster burnout to separate + public static final String BOOSTER1_IGNITION_DELAY = "Booster1IgnitionDelay"; + public static final String INCLUDE_BOOSTER1 = "IncludeBooster1"; + public static final String BOOSTER2_ENGINE = "Booster2Engine"; + public static final String BOOSTER2_SEPARATION_DELAY = "Booster2SeparationDelay"; // Delay after booster burnout to separate + public static final String BOOSTER2_IGNITION_DELAY = "Booster2IgnitionDelay"; + public static final String INCLUDE_BOOSTER2 = "IncludeBooster2"; + /** * Length conversion. RASAero is in inches, OpenRocket in meters. diff --git a/core/src/net/sf/openrocket/file/rasaero/importt/RASAeroHandler.java b/core/src/net/sf/openrocket/file/rasaero/importt/RASAeroHandler.java index cb885d960..6c7825787 100644 --- a/core/src/net/sf/openrocket/file/rasaero/importt/RASAeroHandler.java +++ b/core/src/net/sf/openrocket/file/rasaero/importt/RASAeroHandler.java @@ -9,6 +9,7 @@ import net.sf.openrocket.file.simplesax.PlainTextHandler; import net.sf.openrocket.rocketcomponent.AxialStage; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.simulation.SimulationOptions; import org.xml.sax.SAXException; import java.util.HashMap; @@ -64,7 +65,7 @@ public class RASAeroHandler extends AbstractElementHandler { /** * A SAX handler for the RASAeroDocument element. */ - private class RocketDocumentHandler extends AbstractElementHandler { + private static class RocketDocumentHandler extends AbstractElementHandler { /** * The DocumentLoadingContext */ @@ -75,6 +76,11 @@ public class RASAeroHandler extends AbstractElementHandler { */ private final Rocket rocket; + /** + * The RASAero launch site settings to be used for all the OpenRocket simulations. + */ + private final SimulationOptions launchSiteSettings = new SimulationOptions(); + /** * The RASAero file version. */ @@ -102,11 +108,15 @@ public class RASAeroHandler extends AbstractElementHandler { } // LaunchSite else if (RASAeroCommonConstants.LAUNCH_SITE.equals(element)) { - return new LaunchSiteHandler(context); + return new LaunchSiteHandler(launchSiteSettings); } // Recovery else if (RASAeroCommonConstants.RECOVERY.equals(element)) { - return new RecoveryHandler(context, rocket); + return new RecoveryHandler(rocket); + } + // SimulationList + else if (RASAeroCommonConstants.SIMULATION_LIST.equals(element)) { + return new SimulationListHandler(context, rocket, launchSiteSettings); } return null; @@ -128,7 +138,7 @@ public class RASAeroHandler extends AbstractElementHandler { /** * A SAX handler for the RocketDesign element. */ - private class RocketDesignHandler extends AbstractElementHandler { + private static class RocketDesignHandler extends AbstractElementHandler { /** * The DocumentLoadingContext */ @@ -161,11 +171,11 @@ public class RASAeroHandler extends AbstractElementHandler { } // Fin can else if (RASAeroCommonConstants.FIN_CAN.equals(element)) { - return new FinCanHandler(context, component, warnings); + return new FinCanHandler(context, component); } // Booster else if (RASAeroCommonConstants.BOOSTER.equals(element)) { - return new BoosterHandler(context, component, warnings); + return new BoosterHandler(context, component); } // BoatTail else if (RASAeroCommonConstants.BOATTAIL.equals(element)) { diff --git a/core/src/net/sf/openrocket/file/rasaero/importt/RASAeroMotorsLoader.java b/core/src/net/sf/openrocket/file/rasaero/importt/RASAeroMotorsLoader.java new file mode 100644 index 000000000..cb608674b --- /dev/null +++ b/core/src/net/sf/openrocket/file/rasaero/importt/RASAeroMotorsLoader.java @@ -0,0 +1,95 @@ +package net.sf.openrocket.file.rasaero.importt; + +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.database.motor.ThrustCurveMotorSet; +import net.sf.openrocket.motor.ThrustCurveMotor; +import net.sf.openrocket.startup.Application; + +import java.util.ArrayList; +import java.util.List; + +public abstract class RASAeroMotorsLoader { + private static List allMotors = null; + + /** + * Returns a RASAero motor from the motor string of its RASAero file. + * @param motorString The motor string of the RASAero file, e.g. "1/4A2 (AP)". + * @param warnings The warning set to add import warnings to. + * @return The motor, or null if not found. + */ + public static ThrustCurveMotor getMotorFromRASAero(String motorString, WarningSet warnings) { + if (motorString == null) { + return null; + } + if (allMotors == null) { + loadAllMotors(); + } + /* + RASAero file motor strings are formatted as " ()" + */ + String[] split = motorString.split("\\s{2}"); + if (split.length != 2) { + return null; + } + String motorName = split[0]; + String manufacturer = split[1].replaceAll("^\\(|\\)$", ""); // Remove beginning and ending parenthesis + for (ThrustCurveMotor motor : allMotors) { + if (motorName.equals(motor.getDesignation()) && motor.getManufacturer().matches(manufacturer)) { + return motor; + } + } + warnings.add("Could not find motor '" + motorString + "' in the OpenRocket motors database. Please add it manually."); + return null; + } + + /** + * Call this method when you don't need the RASAero motors anymore to free memory. + */ + public static void clearAllMotors() { + if (allMotors != null) { + allMotors.clear(); + allMotors = null; + } + } + + // Not currently used, because it causes some compatibility issues when e.g. wanting to open the RASAero motor + // in the motor selection table (because it is not present there). + // It's probably also better to load OR-native motors. + // But I'll leave this in, in case it's needed in the future. + /* + * Loads all original RASAero motors. + * @param warnings The warning set to add import warnings to. + * @throws RuntimeException If the RASAero motors file could not be found. + * + private static void loadAllRASAeroMotors(WarningSet warnings) throws RuntimeException { + allMotors = new ArrayList<>(); + + GeneralMotorLoader loader = new GeneralMotorLoader(); + ClassLoader classloader = Thread.currentThread().getContextClassLoader(); + String fileName = "RASAero_Motors.eng"; + InputStream is = classloader.getResourceAsStream("datafiles/thrustcurves/RASAero/" + fileName); + if (is == null) { + throw new RuntimeException("Could not find " + fileName); + } + try { + List motors = loader.load(is, fileName); + for (ThrustCurveMotor.Builder builder : motors) { + allMotors.add(builder.build()); + } + } catch (IOException e) { + warnings.add("Error during motor loading: " + e.getMessage()); + } + }*/ + + /** + * Loads the OpenRocket motors database. + */ + private static void loadAllMotors() { + allMotors = new ArrayList<>(); + List database = Application.getThrustCurveMotorSetDatabase().getMotorSets(); + for (ThrustCurveMotorSet set : database) { + allMotors.addAll(set.getMotors()); + } + } + +} diff --git a/core/src/net/sf/openrocket/file/rasaero/importt/RecoveryHandler.java b/core/src/net/sf/openrocket/file/rasaero/importt/RecoveryHandler.java index 2b1c9de73..c6c47a4ad 100644 --- a/core/src/net/sf/openrocket/file/rasaero/importt/RecoveryHandler.java +++ b/core/src/net/sf/openrocket/file/rasaero/importt/RecoveryHandler.java @@ -25,7 +25,6 @@ import java.util.Map; * @author Sibo Van Gool */ public class RecoveryHandler extends AbstractElementHandler { - private final DocumentLoadingContext context; private final Rocket rocket; // Recovery parameters @@ -37,8 +36,7 @@ public class RecoveryHandler extends AbstractElementHandler { private final String[] eventType = new String[NR_OF_RECOVERY_DEVICES]; // When to deploy private final Double[] CD = new Double[NR_OF_RECOVERY_DEVICES]; // Coefficient of drag - public RecoveryHandler(DocumentLoadingContext context, Rocket rocket) { - this.context = context; + public RecoveryHandler(Rocket rocket) { this.rocket = rocket; } @Override diff --git a/core/src/net/sf/openrocket/file/rasaero/importt/SimulationListHandler.java b/core/src/net/sf/openrocket/file/rasaero/importt/SimulationListHandler.java new file mode 100644 index 000000000..06d5145c0 --- /dev/null +++ b/core/src/net/sf/openrocket/file/rasaero/importt/SimulationListHandler.java @@ -0,0 +1,170 @@ +package net.sf.openrocket.file.rasaero.importt; + +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.document.Simulation; +import net.sf.openrocket.file.DocumentLoadingContext; +import net.sf.openrocket.file.simplesax.AbstractElementHandler; +import net.sf.openrocket.file.simplesax.ElementHandler; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.motor.Motor; +import net.sf.openrocket.motor.MotorConfiguration; +import net.sf.openrocket.motor.ThrustCurveMotor; +import net.sf.openrocket.rocketcomponent.FlightConfigurationId; +import net.sf.openrocket.rocketcomponent.MotorMount; +import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.simulation.SimulationOptions; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +/** + * A SAX handler for simulation importing from a RASAero file. + * A SimulationList is a collection of RASAero simulations. + * + * @author Sibo Van Gool + */ +public class SimulationListHandler extends AbstractElementHandler { + private final DocumentLoadingContext context; + private final Rocket rocket; + private final SimulationOptions launchSiteSettings; + private int nrOfSimulations = 0; + + + public SimulationListHandler(DocumentLoadingContext context, Rocket rocket, SimulationOptions launchSiteSettings) { + this.context = context; + this.rocket = rocket; + this.launchSiteSettings = launchSiteSettings; + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) throws SAXException { + if (RASAeroCommonConstants.SIMULATION.equals(element)) { + nrOfSimulations++; + return new SimulationHandler(context, rocket, launchSiteSettings, nrOfSimulations); + } + return null; + } + + @Override + public void endHandler(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { + RASAeroMotorsLoader.clearAllMotors(); + } + + /** + * Handles RASAero simulation elements. + * We will only import the motor information from it. + */ + private static class SimulationHandler extends AbstractElementHandler { + private final DocumentLoadingContext context; + private final Rocket rocket; + private final SimulationOptions launchSiteSettings; + private final int simulationNr; + + // Motor information + private ThrustCurveMotor sustainerEngine; + private Double sustainerIgnitionDelay; + private ThrustCurveMotor booster1Engine; + private Double booster1IgnitionDelay; + private Double booster1SeparationDelay; + private Boolean includeBooster1; + private ThrustCurveMotor booster2Engine; + private Double booster2IgnitionDelay; + private Double booster2SeparationDelay; + private Boolean includeBooster2; + + public SimulationHandler(DocumentLoadingContext context, Rocket rocket, SimulationOptions launchSiteSettings, int simulationNr) { + this.context = context; + this.rocket = rocket; + this.launchSiteSettings = launchSiteSettings; + this.simulationNr = simulationNr; + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) throws SAXException { + if (RASAeroCommonConstants.SUSTAINER_ENGINE.equals(element) || RASAeroCommonConstants.SUSTAINER_IGNITION_DELAY.equals(element) + || RASAeroCommonConstants.BOOSTER1_ENGINE.equals(element) || RASAeroCommonConstants.BOOSTER1_IGNITION_DELAY.equals(element) + || RASAeroCommonConstants.BOOSTER1_SEPARATION_DELAY.equals(element) || RASAeroCommonConstants.INCLUDE_BOOSTER1.equals(element) + || RASAeroCommonConstants.BOOSTER2_ENGINE.equals(element) || RASAeroCommonConstants.BOOSTER2_IGNITION_DELAY.equals(element) + || RASAeroCommonConstants.BOOSTER2_SEPARATION_DELAY.equals(element) || RASAeroCommonConstants.INCLUDE_BOOSTER2.equals(element)) { + return PlainTextHandler.INSTANCE; + } + return null; + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { + if (RASAeroCommonConstants.SUSTAINER_ENGINE.equals(element)) { + sustainerEngine = RASAeroMotorsLoader.getMotorFromRASAero(content, warnings); + } else if (RASAeroCommonConstants.SUSTAINER_IGNITION_DELAY.equals(element)) { + sustainerIgnitionDelay = Double.parseDouble(content); + } else if (RASAeroCommonConstants.BOOSTER1_ENGINE.equals(element)) { + booster1Engine = RASAeroMotorsLoader.getMotorFromRASAero(content, warnings); + } else if (RASAeroCommonConstants.BOOSTER1_IGNITION_DELAY.equals(element)) { + booster1IgnitionDelay = Double.parseDouble(content); + } else if (RASAeroCommonConstants.BOOSTER1_SEPARATION_DELAY.equals(element)) { + booster1SeparationDelay = Double.parseDouble(content); + } else if (RASAeroCommonConstants.INCLUDE_BOOSTER1.equals(element)) { + includeBooster1 = Boolean.parseBoolean(content); + } else if (RASAeroCommonConstants.BOOSTER2_ENGINE.equals(element)) { + booster2Engine = RASAeroMotorsLoader.getMotorFromRASAero(content, warnings); + } else if (RASAeroCommonConstants.BOOSTER2_IGNITION_DELAY.equals(element)) { + booster2IgnitionDelay = Double.parseDouble(content); + } else if (RASAeroCommonConstants.BOOSTER2_SEPARATION_DELAY.equals(element)) { + booster2SeparationDelay = Double.parseDouble(content); + } else if (RASAeroCommonConstants.INCLUDE_BOOSTER2.equals(element)) { + includeBooster2 = Boolean.parseBoolean(content); + } + } + + @Override + public void endHandler(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { + FlightConfigurationId id = new FlightConfigurationId(); + rocket.createFlightConfiguration(id); + + // Add motors to the rocket + double separationDelay = includeBooster1 && (booster1SeparationDelay != null) ? booster1SeparationDelay : 0.0; + addMotorToStage(0, sustainerEngine, sustainerIgnitionDelay, separationDelay, id, warnings); + separationDelay = includeBooster2 && (booster2SeparationDelay != null) ? booster2SeparationDelay : 0.0; + if (includeBooster1) { + addMotorToStage(1, booster1Engine, booster1IgnitionDelay, separationDelay, id, warnings); + } + if (includeBooster2) { + addMotorToStage(2, booster2Engine, booster2IgnitionDelay, 0.0, id, warnings); + } + + // Add a new simulation + Simulation sim = new Simulation(rocket); + sim.setFlightConfigurationId(id); + sim.setName("Simulation " + simulationNr); + sim.copySimulationOptionsFrom(launchSiteSettings); + context.getOpenRocketDocument().addSimulation(sim); + } + + private void addMotorToStage(final int stageNr, final Motor motor, final double ignitionDelay, final double separationDelay, + final FlightConfigurationId id, final WarningSet warnings) { + MotorMount mount = getMotorMountForStage(stageNr); + if (mount == null) { + warnings.add("No motor mount found for stage " + stageNr + ". Ignoring motor."); + return; + } + MotorConfiguration motorConfig = new MotorConfiguration(mount, id); + motorConfig.setMotor(motor); + motorConfig.setIgnitionDelay(ignitionDelay + separationDelay); // Just add the separation delay to the ignition delay + mount.setMotorConfig(motorConfig, id); + } + + private MotorMount getMotorMountForStage(int stage) { + MotorMount mount = null; + for (RocketComponent component : rocket.getStage(stage)) { + if (component instanceof MotorMount) { + mount = (MotorMount) component; + } + } + if (mount != null) { + mount.setMotorMount(true); + } + return mount; + } + } +}