diff --git a/core/src/net/sf/openrocket/file/rocksim/export/ParallelStageDTO.java b/core/src/net/sf/openrocket/file/rocksim/export/ParallelStageDTO.java index 510673fd1..9ee1b88c2 100644 --- a/core/src/net/sf/openrocket/file/rocksim/export/ParallelStageDTO.java +++ b/core/src/net/sf/openrocket/file/rocksim/export/ParallelStageDTO.java @@ -1,6 +1,7 @@ package net.sf.openrocket.file.rocksim.export; import net.sf.openrocket.rocketcomponent.ParallelStage; +import net.sf.openrocket.rocketcomponent.RocketComponent; public class ParallelStageDTO extends PodSetDTO { @@ -12,11 +13,12 @@ public class ParallelStageDTO extends PodSetDTO { /** * Copy constructor. Fully populates this instance with values taken from the OR PodSet. + * This constructor should not be called directly. Instead, use {@link #generateParallelStageDTOs}. * - * @param theORParallelStage + * @param theORParallelStage the single-instance OR ParallelStage */ - protected ParallelStageDTO(ParallelStage theORParallelStage, double angle) { - super(theORParallelStage, angle); + protected ParallelStageDTO(ParallelStage theORParallelStage) { + super(theORParallelStage); setDetachable(true); setEjected(false); } @@ -30,8 +32,8 @@ public class ParallelStageDTO extends PodSetDTO { public static ParallelStageDTO[] generateParallelStageDTOs(ParallelStage theORParallelStage) { ParallelStageDTO[] set = new ParallelStageDTO[theORParallelStage.getInstanceCount()]; int i = 0; - for (double angle : theORParallelStage.getInstanceAngles()) { - set[i] = new ParallelStageDTO(theORParallelStage, angle); + for (RocketComponent stageInstance : theORParallelStage.splitInstances(false)) { + set[i] = new ParallelStageDTO((ParallelStage) stageInstance); i++; } return set; diff --git a/core/src/net/sf/openrocket/file/rocksim/export/PodSetDTO.java b/core/src/net/sf/openrocket/file/rocksim/export/PodSetDTO.java index a9470fefc..fbf66a910 100644 --- a/core/src/net/sf/openrocket/file/rocksim/export/PodSetDTO.java +++ b/core/src/net/sf/openrocket/file/rocksim/export/PodSetDTO.java @@ -8,6 +8,7 @@ import net.sf.openrocket.rocketcomponent.ParallelStage; import net.sf.openrocket.rocketcomponent.PodSet; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.Transition; +import net.sf.openrocket.rocketcomponent.position.AnglePositionable; import net.sf.openrocket.rocketcomponent.position.AxialMethod; import javax.xml.bind.annotation.XmlAccessType; @@ -57,8 +58,8 @@ public class PodSetDTO extends BasePartDTO implements AttachableParts { public static PodSetDTO[] generatePodSetDTOs(ComponentAssembly theORPodSet) { PodSetDTO[] set = new PodSetDTO[theORPodSet.getInstanceCount()]; int i = 0; - for (double angle : theORPodSet.getInstanceAngles()) { - set[i] = new PodSetDTO(theORPodSet, angle); + for (RocketComponent podInstance : theORPodSet.splitInstances()) { + set[i] = new PodSetDTO((PodSet) podInstance); i++; } return set; @@ -66,22 +67,27 @@ public class PodSetDTO extends BasePartDTO implements AttachableParts { /** * Copy constructor. Fully populates this instance with values taken from the OR PodSet. - * - * @param theORPodSet + * This constructor should not be called directly. Instead, use {@link #generatePodSetDTOs}. + * @param theORPodSet the single-instance OR PodSet */ - protected PodSetDTO(ComponentAssembly theORPodSet, double angleOffset) { + protected PodSetDTO(ComponentAssembly theORPodSet) { super(theORPodSet); // OR should always override the radial angle and distance setAutoCalcRadialDistance(false); setAutoCalcRadialAngle(false); setDetachable(false); setEjected(false); + final double angleOffset = theORPodSet.getAngleOffset(); setRadialAngle(angleOffset); setRadialLoc(theORPodSet.getRadiusMethod().getRadius( theORPodSet.getParent(), theORPodSet, theORPodSet.getRadiusOffset()) * RockSimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH); setXb(theORPodSet.getAxialOffset(AxialMethod.TOP) * RockSimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH); + // Children of a PodSet in RockSim do not use angles relative to their PodSet parent, but instead use absolute angle. + // Therefore, we must apply those angles to the children of the PodSet. + addAngleOffsetToChildren(theORPodSet, angleOffset); + for (RocketComponent child : theORPodSet.getChildren()) { if (child instanceof PodSet) { for (PodSetDTO podSetDTO : generatePodSetDTOs((PodSet) child)) { @@ -105,6 +111,20 @@ public class PodSetDTO extends BasePartDTO implements AttachableParts { } } + private void addAngleOffsetToChildren(RocketComponent component, double angleOffset) { + for (RocketComponent child : component.getChildren()) { + if (child instanceof AnglePositionable anglePositionable) { + anglePositionable.setAngleOffset(anglePositionable.getAngleOffset() + angleOffset); + } + // No need to add an offset to the children of a component assembly. When the component assembly is + // converted to a PodSetDTO, its angle offset will be applied to the children (and that angle offset already + // includes the angle offset of the parent). + if (!(child instanceof ComponentAssembly)) { + addAngleOffsetToChildren(child, angleOffset); + } + } + } + public int getAutoCalcRadialDistance() { return autoCalcRadialDistance; } diff --git a/core/src/net/sf/openrocket/file/rocksim/export/RockSimSaver.java b/core/src/net/sf/openrocket/file/rocksim/export/RockSimSaver.java index a04ea25b1..e99dc705b 100644 --- a/core/src/net/sf/openrocket/file/rocksim/export/RockSimSaver.java +++ b/core/src/net/sf/openrocket/file/rocksim/export/RockSimSaver.java @@ -12,6 +12,7 @@ import javax.xml.bind.Marshaller; import net.sf.openrocket.logging.ErrorSet; import net.sf.openrocket.logging.WarningSet; +import net.sf.openrocket.util.MemoryManagement; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -124,6 +125,10 @@ public class RockSimSaver extends RocketSaver { //Set the last serial number element and reset it. result.setLastSerialNumber(BasePartDTO.getCurrentSerialNumber()); BasePartDTO.resetCurrentSerialNumber(); + + // Clean up + MemoryManagement.collectable(rocket); + return result; } diff --git a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java index 0dd0994af..8bc22cfbf 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java +++ b/core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java @@ -2462,7 +2462,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab int count = getInstanceCount(); double angleOffset = getAngleOffset(); - List splitComponents = null; // List of all the split components + List splitComponents = new java.util.ArrayList<>(); // List of all the split components try { // Freeze rocket @@ -2473,7 +2473,6 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab // Split the components if (count > 1) { parent.removeChild(index, true); // Remove the original component - splitComponents = new java.util.ArrayList<>(); for (int i = 0; i < count; i++) { RocketComponent copy = this.copy(); copy.setInstanceCount(1); @@ -2486,6 +2485,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab splitComponents.add(copy); } + } else { + splitComponents.add(this); } // Split components for listeners