diff --git a/core/src/net/sf/openrocket/file/rocksim/RockSimCommonConstants.java b/core/src/net/sf/openrocket/file/rocksim/RockSimCommonConstants.java index c76df9977..24ae530a5 100644 --- a/core/src/net/sf/openrocket/file/rocksim/RockSimCommonConstants.java +++ b/core/src/net/sf/openrocket/file/rocksim/RockSimCommonConstants.java @@ -29,6 +29,8 @@ public class RockSimCommonConstants { public static final String DENSITY_TYPE = "DensityType"; public static final String RADIAL_LOC = "RadialLoc"; public static final String RADIAL_ANGLE = "RadialAngle"; + public static final String AUTO_CALC_RADIAL_DISTANCE = "AutoCalcRadialDistance"; + public static final String AUTO_CALC_RADIAL_ANGLE = "AutoCalcRadialAngle"; public static final String LOCATION_MODE = "LocationMode"; public static final String FINISH_CODE = "FinishCode"; public static final String SERIAL_NUMBER = "SerialNo"; diff --git a/core/src/net/sf/openrocket/file/rocksim/export/BodyTubeDTO.java b/core/src/net/sf/openrocket/file/rocksim/export/BodyTubeDTO.java index 479b35132..0eeb7c8f3 100644 --- a/core/src/net/sf/openrocket/file/rocksim/export/BodyTubeDTO.java +++ b/core/src/net/sf/openrocket/file/rocksim/export/BodyTubeDTO.java @@ -11,6 +11,7 @@ import net.sf.openrocket.rocketcomponent.InnerTube; import net.sf.openrocket.rocketcomponent.LaunchLug; import net.sf.openrocket.rocketcomponent.MassObject; import net.sf.openrocket.rocketcomponent.Parachute; +import net.sf.openrocket.rocketcomponent.PodSet; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.Streamer; import net.sf.openrocket.rocketcomponent.Transition; @@ -50,6 +51,7 @@ public class BodyTubeDTO extends BasePartDTO implements AttachableParts { @XmlElementRefs({ @XmlElementRef(name = RockSimCommonConstants.BODY_TUBE, type = BodyTubeDTO.class), @XmlElementRef(name = RockSimCommonConstants.BODY_TUBE, type = InnerBodyTubeDTO.class), + @XmlElementRef(name = RockSimCommonConstants.TRANSITION, type = TransitionDTO.class), @XmlElementRef(name = RockSimCommonConstants.RING, type = CenteringRingDTO.class), @XmlElementRef(name = RockSimCommonConstants.LAUNCH_LUG, type = LaunchLugDTO.class), @XmlElementRef(name = RockSimCommonConstants.FIN_SET, type = FinSetDTO.class), @@ -57,7 +59,8 @@ public class BodyTubeDTO extends BasePartDTO implements AttachableParts { @XmlElementRef(name = RockSimCommonConstants.TUBE_FIN_SET, type = TubeFinSetDTO.class), @XmlElementRef(name = RockSimCommonConstants.STREAMER, type = StreamerDTO.class), @XmlElementRef(name = RockSimCommonConstants.PARACHUTE, type = ParachuteDTO.class), - @XmlElementRef(name = RockSimCommonConstants.MASS_OBJECT, type = MassObjectDTO.class)}) + @XmlElementRef(name = RockSimCommonConstants.MASS_OBJECT, type = MassObjectDTO.class), + @XmlElementRef(name = RockSimCommonConstants.EXTERNAL_POD, type = PodSetDTO.class)}) List attachedParts = new ArrayList(); /** @@ -125,6 +128,8 @@ public class BodyTubeDTO extends BasePartDTO implements AttachableParts { addAttachedPart(new FinSetDTO((FinSet) rocketComponents)); } else if (rocketComponents instanceof TubeFinSet) { addAttachedPart(new TubeFinSetDTO((TubeFinSet) rocketComponents)); + } else if (rocketComponents instanceof PodSet) { + addAttachedPart(new PodSetDTO((PodSet) rocketComponents)); } } } diff --git a/core/src/net/sf/openrocket/file/rocksim/export/PodSetDTO.java b/core/src/net/sf/openrocket/file/rocksim/export/PodSetDTO.java new file mode 100644 index 000000000..7baa9b56f --- /dev/null +++ b/core/src/net/sf/openrocket/file/rocksim/export/PodSetDTO.java @@ -0,0 +1,110 @@ +package net.sf.openrocket.file.rocksim.export; + +import net.sf.openrocket.file.rocksim.RockSimCommonConstants; +import net.sf.openrocket.rocketcomponent.BodyTube; +import net.sf.openrocket.rocketcomponent.NoseCone; +import net.sf.openrocket.rocketcomponent.PodSet; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.Transition; +import net.sf.openrocket.rocketcomponent.position.AxialMethod; +import net.sf.openrocket.rocketcomponent.position.RadiusMethod; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementRef; +import javax.xml.bind.annotation.XmlElementRefs; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * Models the XML element for a RockSim pod. + */ +@XmlRootElement(name = RockSimCommonConstants.EXTERNAL_POD) +@XmlAccessorType(XmlAccessType.FIELD) +public class PodSetDTO extends BasePartDTO implements AttachableParts { + @XmlElement(name = RockSimCommonConstants.AUTO_CALC_RADIAL_DISTANCE) + private int autoCalcRadialDistance = 0; + @XmlElement(name = RockSimCommonConstants.AUTO_CALC_RADIAL_ANGLE) + private int autoCalcRadialAngle = 0; + @XmlElementWrapper(name = RockSimCommonConstants.ATTACHED_PARTS) + @XmlElementRefs({ + @XmlElementRef(name = RockSimCommonConstants.BODY_TUBE, type = BodyTubeDTO.class), + @XmlElementRef(name = RockSimCommonConstants.NOSE_CONE, type = NoseConeDTO.class), + @XmlElementRef(name = RockSimCommonConstants.TRANSITION, type = TransitionDTO.class), + @XmlElementRef(name = RockSimCommonConstants.EXTERNAL_POD, type = PodSetDTO.class)}) + List attachedParts = new ArrayList(); + + /** + * Default constructor. + */ + public PodSetDTO() { + } + + /** + * Copy constructor. Fully populates this instance with values taken from the OR PodSet. + * + * @param theORPodSet + */ + public PodSetDTO(PodSet theORPodSet) { + super(theORPodSet); + // OR should always override the radial angle and distance + setAutoCalcRadialDistance(false); + setAutoCalcRadialAngle(false); + setRadialAngle(theORPodSet.getAngleOffset()); + setRadialLoc(theORPodSet.getRadiusMethod().getRadius( + theORPodSet.getParent(), theORPodSet, + theORPodSet.getRadiusOffset()) * RockSimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH); + setXb(theORPodSet.getAxialOffset(AxialMethod.TOP) * RockSimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH); + + for (RocketComponent child : theORPodSet.getChildren()) { + if (child instanceof PodSet) { + addAttachedPart(new PodSetDTO((PodSet) child)); + } else if (child instanceof BodyTube) { + addAttachedPart(new BodyTubeDTO((BodyTube) child)); + } else if (child instanceof NoseCone) { + addAttachedPart(new NoseConeDTO((NoseCone) child)); + } else if (child instanceof Transition) { + addAttachedPart(new TransitionDTO((Transition) child)); + } + } + } + + public int getAutoCalcRadialDistance() { + return autoCalcRadialDistance; + } + + public void setAutoCalcRadialDistance(boolean motorMount) { + if (motorMount) { + this.autoCalcRadialDistance = 1; + } else { + this.autoCalcRadialDistance = 0; + } + } + + public int getAutoCalcRadialAngle() { + return autoCalcRadialAngle; + } + + public void setAutoCalcRadialAngle(boolean motorMount) { + if (motorMount) { + this.autoCalcRadialAngle = 1; + } else { + this.autoCalcRadialAngle = 0; + } + } + + @Override + public void addAttachedPart(BasePartDTO part) { + if (!attachedParts.contains(part)) { + attachedParts.add(part); + } + } + + @Override + public void removeAttachedPart(BasePartDTO part) { + attachedParts.remove(part); + } +} diff --git a/core/src/net/sf/openrocket/file/rocksim/importt/AttachedPartsHandler.java b/core/src/net/sf/openrocket/file/rocksim/importt/AttachedPartsHandler.java index 03563fd3d..d90b8b7c5 100644 --- a/core/src/net/sf/openrocket/file/rocksim/importt/AttachedPartsHandler.java +++ b/core/src/net/sf/openrocket/file/rocksim/importt/AttachedPartsHandler.java @@ -8,6 +8,7 @@ import net.sf.openrocket.file.DocumentLoadingContext; import net.sf.openrocket.file.rocksim.RockSimCommonConstants; import net.sf.openrocket.file.simplesax.AbstractElementHandler; import net.sf.openrocket.file.simplesax.ElementHandler; +import net.sf.openrocket.rocketcomponent.PodSet; import net.sf.openrocket.rocketcomponent.RocketComponent; import java.util.HashMap; @@ -68,23 +69,32 @@ class AttachedPartsHandler extends AbstractElementHandler { return new RingHandler(context, component, warnings); } if (RockSimCommonConstants.BODY_TUBE.equals(element)) { - return new InnerBodyTubeHandler(context, component, warnings); + // Pods can have BodyTubes as attached parts, but not inner tubes. All other components can't have BodyTubes as + // attached parts. + if (component instanceof PodSet) { + return new BodyTubeHandler(context, component, warnings); + } else { + return new InnerBodyTubeHandler(context, component, warnings); + } } if (RockSimCommonConstants.TRANSITION.equals(element)) { return new TransitionHandler(context, component, warnings); } + if (RockSimCommonConstants.NOSE_CONE.equals(element)) { + return new NoseConeHandler(context, component, warnings); + } if (RockSimCommonConstants.SUBASSEMBLY.equals(element)) { return new SubAssemblyHandler(context, component); } if (RockSimCommonConstants.TUBE_FIN_SET.equals(element)) { return new TubeFinSetHandler(context, component, warnings); } + if (RockSimCommonConstants.EXTERNAL_POD.equals(element)) { + return new PodHandler(context, component, warnings); + } if (RockSimCommonConstants.RING_TAIL.equals(element)) { warnings.add("Ring tails are not currently supported. Ignoring."); } - if (RockSimCommonConstants.EXTERNAL_POD.equals(element)) { - warnings.add("Pods are not currently supported. Ignoring."); - } return null; } } diff --git a/core/src/net/sf/openrocket/file/rocksim/importt/BodyTubeHandler.java b/core/src/net/sf/openrocket/file/rocksim/importt/BodyTubeHandler.java index 84ed5a8ce..093858955 100644 --- a/core/src/net/sf/openrocket/file/rocksim/importt/BodyTubeHandler.java +++ b/core/src/net/sf/openrocket/file/rocksim/importt/BodyTubeHandler.java @@ -25,6 +25,7 @@ class BodyTubeHandler extends BaseHandler { * The OpenRocket BodyTube. */ private final BodyTube bodyTube; + private int isInsideTube = 0; /** * Constructor. @@ -80,6 +81,9 @@ class BodyTubeHandler extends BaseHandler { if (RockSimCommonConstants.MATERIAL.equals(element)) { setMaterialName(content); } + if (RockSimCommonConstants.IS_INSIDE_TUBE.equals(element)) { + isInsideTube = Integer.parseInt(content); + } } catch (NumberFormatException nfe) { warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); } @@ -104,4 +108,11 @@ class BodyTubeHandler extends BaseHandler { public Material.Type getMaterialType() { return Material.Type.BULK; } + + /** + * Returns 0 if this is a body tube, 1 if it is an inside tube. + */ + public int isInsideTube() { + return isInsideTube; + } } diff --git a/core/src/net/sf/openrocket/file/rocksim/importt/PodHandler.java b/core/src/net/sf/openrocket/file/rocksim/importt/PodHandler.java new file mode 100644 index 000000000..ffec3d0b5 --- /dev/null +++ b/core/src/net/sf/openrocket/file/rocksim/importt/PodHandler.java @@ -0,0 +1,66 @@ +package net.sf.openrocket.file.rocksim.importt; + +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.file.DocumentLoadingContext; +import net.sf.openrocket.file.rocksim.RockSimCommonConstants; +import net.sf.openrocket.file.simplesax.ElementHandler; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.PodSet; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.position.RadiusMethod; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +public class PodHandler extends PositionDependentHandler { + /** + * The OpenRocket BodyTube. + */ + private final PodSet podSet; + + public PodHandler(DocumentLoadingContext context, RocketComponent c, WarningSet warnings) { + super(context); + if (c == null) { + throw new IllegalArgumentException("The parent component of a pod set may not be null."); + } + podSet = new PodSet(); + podSet.setInstanceCount(1); // RockSim only supports one pod instance + podSet.setRadiusMethod(RadiusMethod.FREE); // RockSim radial offset is relative to the center of the parent + if (isCompatible(c, PodSet.class, warnings)) { + c.addChild(podSet); + } + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) throws SAXException { + if (RockSimCommonConstants.BODY_TUBE.equals(element)) { // RockSim pods allow body tubes, not inner tubes + return new BodyTubeHandler(context, podSet, warnings); + } + if (RockSimCommonConstants.ATTACHED_PARTS.equals(element)) { + return new AttachedPartsHandler(context, podSet); + } + return PlainTextHandler.INSTANCE; + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { + super.closeElement(element, attributes, content, warnings); + if (RockSimCommonConstants.RADIAL_ANGLE.equals(element)) { + podSet.setAngleOffset(Double.parseDouble(content)); + } + if (RockSimCommonConstants.RADIAL_LOC.equals(element)) { + podSet.setRadiusOffset(Double.parseDouble(content) / RockSimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH); + } + } + + @Override + protected PodSet getComponent() { + return podSet; + } + + @Override + protected Material.Type getMaterialType() { + return Material.Type.BULK; + } +} diff --git a/core/src/net/sf/openrocket/file/rocksim/importt/PositionDependentHandler.java b/core/src/net/sf/openrocket/file/rocksim/importt/PositionDependentHandler.java index c5c5ae7ba..2bdd3a674 100644 --- a/core/src/net/sf/openrocket/file/rocksim/importt/PositionDependentHandler.java +++ b/core/src/net/sf/openrocket/file/rocksim/importt/PositionDependentHandler.java @@ -9,6 +9,8 @@ import net.sf.openrocket.aerodynamics.WarningSet; import net.sf.openrocket.file.DocumentLoadingContext; import net.sf.openrocket.file.rocksim.RockSimCommonConstants; import net.sf.openrocket.file.rocksim.RockSimLocationMode; +import net.sf.openrocket.rocketcomponent.ComponentAssembly; +import net.sf.openrocket.rocketcomponent.ParallelStage; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.position.AxialMethod; @@ -70,6 +72,10 @@ public abstract class PositionDependentHandler extend * Set the axialMethod of a component. */ protected void setLocation() { + if ((getComponent() instanceof ComponentAssembly || getComponent() instanceof ParallelStage) && + getComponent().getParent() == null) { + return; + } getComponent().setAxialMethod(axialMethod); if (axialMethod.equals(AxialMethod.BOTTOM)) { getComponent().setAxialOffset(-1d * positionValue); diff --git a/core/src/net/sf/openrocket/rocketcomponent/PodSet.java b/core/src/net/sf/openrocket/rocketcomponent/PodSet.java index 18744d671..0c163a50a 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/PodSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/PodSet.java @@ -121,19 +121,23 @@ public class PodSet extends ComponentAssembly implements RingInstanceable { @Override public double getAxialOffset() { + return getAxialOffset(this.axialMethod); + } + @Override + public double getAxialOffset(AxialMethod method) { double returnValue; - + if (this.isAfter()){ // remember the implicit (this instanceof Stage) throw new BugException("found a pod positioned via: AFTER, but is not on the centerline?!: " + this.getName() + " is " + this.getAxialMethod().name() ); } else { - returnValue = super.getAxialOffset(this.axialMethod); + returnValue = super.getAxialOffset(method); } - + if (MathUtil.EPSILON > Math.abs(returnValue)) { returnValue = 0.0; } - + return returnValue; } diff --git a/core/test/net/sf/openrocket/file/rocksim/export/RockSimDocumentDTOTest.java b/core/test/net/sf/openrocket/file/rocksim/export/RockSimDocumentDTOTest.java index afaeef030..242a62c7f 100644 --- a/core/test/net/sf/openrocket/file/rocksim/export/RockSimDocumentDTOTest.java +++ b/core/test/net/sf/openrocket/file/rocksim/export/RockSimDocumentDTOTest.java @@ -31,11 +31,14 @@ import net.sf.openrocket.rocketcomponent.InnerTube; import net.sf.openrocket.rocketcomponent.MassComponent; import net.sf.openrocket.rocketcomponent.NoseCone; import net.sf.openrocket.rocketcomponent.Parachute; +import net.sf.openrocket.rocketcomponent.PodSet; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.ShockCord; import net.sf.openrocket.rocketcomponent.Streamer; import net.sf.openrocket.rocketcomponent.TubeCoupler; +import net.sf.openrocket.rocketcomponent.position.AxialMethod; +import net.sf.openrocket.rocketcomponent.position.RadiusMethod; import org.junit.Assert; import static org.junit.Assert.assertEquals; import org.junit.Test; @@ -94,6 +97,72 @@ public class RockSimDocumentDTOTest extends RockSimTestBase { output.delete(); } + /** + * Tests exporting a rocket with pods, and whether importing that same file results in the same pod configuration. + */ + @Test + public void testPodsExport() throws Exception { + OpenRocketDocument originalDocument = makePodsRocket(); + Rocket originalRocket = originalDocument.getRocket(); + + // Convert to RockSim XML + String result = new RockSimSaver().marshalToRockSim(originalDocument); + + // Write to .rkt file + Path output = Files.createTempFile("podsRocket", ".rkt"); + Files.write(output, result.getBytes(StandardCharsets.UTF_8)); + + // Read the file + RockSimLoader loader = new RockSimLoader(); + InputStream stream = new FileInputStream(output.toFile()); + Assert.assertNotNull("Could not open podsRocket.rkt", stream); + OpenRocketDocument importedDocument = OpenRocketDocumentFactory.createEmptyRocket(); + DocumentLoadingContext context = new DocumentLoadingContext(); + context.setOpenRocketDocument(importedDocument); + context.setMotorFinder(new DatabaseMotorFinder()); + loader.loadFromStream(context, new BufferedInputStream(stream)); + Rocket importedRocket = importedDocument.getRocket(); + + // Test children counts + List originalChildren = originalRocket.getAllChildren(); + List importedChildren = importedRocket.getAllChildren(); + assertEquals(" Number of total children doesn't match", + originalChildren.size(), importedChildren.size()); + assertEquals(" Number of rocket children doesn't match", 1, importedRocket.getChildCount()); + AxialStage stage = (AxialStage) importedRocket.getChild(0); + assertEquals(" Number of stage children doesn't match", 2, stage.getChildCount()); + BodyTube tube = (BodyTube) stage.getChild(1); + assertEquals(" Number of body tube children doesn't match", 3, tube.getChildCount()); + PodSet pod1 = (PodSet) tube.getChild(0); + assertEquals(" Number of pod 1 children doesn't match", 1, pod1.getChildCount()); + PodSet pod2 = (PodSet) tube.getChild(1); + assertEquals(" Number of pod 2 children doesn't match", 2, pod2.getChildCount()); + PodSet pod3 = (PodSet) tube.getChild(2); + assertEquals(" Number of pod 3 children doesn't match", 0, pod3.getChildCount()); + + // Test component names + for (int i = 1; i < originalChildren.size(); i++) { + assertEquals(" Child " + i + " does not match", + originalChildren.get(i).getName(), importedChildren.get(i).getName()); + } + + // Test pod parameters + assertEquals(-0.14, pod1.getAxialOffset(), 0.0001); + assertEquals(0.065, pod1.getRadiusOffset(), 0.0001); + assertEquals(Math.PI, pod1.getAngleOffset(), 0.0001); + assertEquals(1, pod1.getInstanceCount()); + assertEquals(0.02, pod2.getAxialOffset(), 0.0001); + assertEquals(0.025, pod2.getRadiusOffset(), 0.0001); + assertEquals(- Math.PI / 2, pod2.getAngleOffset(), 0.0001); + assertEquals(1, pod2.getInstanceCount()); + assertEquals(0.23, pod3.getAxialOffset(), 0.0001); + assertEquals(0.06, pod3.getRadiusOffset(), 0.0001); + assertEquals(Math.PI / 3, pod3.getAngleOffset(), 0.0001); + assertEquals(1, pod3.getInstanceCount()); + + stream.close(); + Files.delete(output); + } /** * Tests exporting a design where a tube coupler has children, which is not supported by RockSim, so the children * need to be moved outside the tube coupler. @@ -142,19 +211,91 @@ public class RockSimDocumentDTOTest extends RockSimTestBase { Files.delete(output); } - private OpenRocketDocument makeTubeCouplerRocket() { + private OpenRocketDocument makePodsRocket() { OpenRocketDocument document = OpenRocketDocumentFactory.createNewRocket(); Rocket rocket = document.getRocket(); AxialStage stage = rocket.getStage(0); + + // Stage children NoseCone noseCone = new NoseCone(); noseCone.setName("Nose Cone"); stage.addChild(noseCone); BodyTube tube = new BodyTube(); tube.setName("Body Tube"); stage.addChild(tube); + + // Body tube children + PodSet pod1 = new PodSet(); + pod1.setName("Pod 1"); + tube.addChild(pod1); + PodSet pod2 = new PodSet(); + pod2.setName("Pod 2"); + tube.addChild(pod2); + PodSet pod3 = new PodSet(); + pod2.setName("Pod 3"); + tube.addChild(pod3); + + // Pod 1 children + NoseCone noseCone1 = new NoseCone(); + noseCone1.setName("Nose Cone 1"); + pod1.addChild(noseCone1); + + // Pod 2 children + NoseCone noseCone2 = new NoseCone(); + noseCone2.setName("Nose Cone 2"); + pod2.addChild(noseCone2); + BodyTube tube2 = new BodyTube(); + tube2.setName("Body Tube 2"); + pod2.addChild(tube2); + + // Set pod parameters + pod1.setInstanceCount(1); + pod2.setInstanceCount(2); + pod3.setInstanceCount(3); + + pod1.setAxialMethod(AxialMethod.ABSOLUTE); + pod1.setAxialOffset(0.01); + pod2.setAxialMethod(AxialMethod.TOP); + pod2.setAxialOffset(0.02); + pod3.setAxialMethod(AxialMethod.BOTTOM); + pod3.setAxialOffset(0.03); + + pod1.setRadiusMethod(RadiusMethod.RELATIVE); + pod1.setRadiusOffset(0.015); + pod2.setRadiusMethod(RadiusMethod.FREE); + pod2.setRadiusOffset(0.025); + pod3.setRadiusMethod(RadiusMethod.RELATIVE); + pod3.setRadiusOffset(0.035); + + pod1.setAngleOffset(Math.PI); + pod2.setAngleOffset(- Math.PI / 2); + pod3.setAngleOffset(Math.PI / 3); + + return document; + } + + private OpenRocketDocument makeTubeCouplerRocket() { + OpenRocketDocument document = OpenRocketDocumentFactory.createNewRocket(); + Rocket rocket = document.getRocket(); + AxialStage stage = rocket.getStage(0); + + // Stage children + NoseCone noseCone = new NoseCone(); + noseCone.setName("Nose Cone"); + stage.addChild(noseCone); + BodyTube tube = new BodyTube(); + tube.setName("Body Tube"); + stage.addChild(tube); + + // Body tube children TubeCoupler coupler = new TubeCoupler(); coupler.setName("Tube coupler 1"); tube.addChild(coupler); + TubeCoupler coupler3 = new TubeCoupler(); + coupler3.setName("Tube Coupler 3"); + tube.addChild(coupler3); + + // Tube coupler 1 children InnerTube innerTube = new InnerTube(); innerTube.setName("Inner Tube"); coupler.addChild(innerTube); @@ -182,9 +323,8 @@ public class RockSimDocumentDTOTest extends RockSimTestBase { MassComponent massComponent = new MassComponent(); massComponent.setName("Mass Component"); coupler.addChild(massComponent); - TubeCoupler coupler3 = new TubeCoupler(); - coupler3.setName("Tube Coupler 3"); - tube.addChild(coupler3); + + // Tube coupler 3 children Parachute parachute2 = new Parachute(); parachute2.setName("Parachute 2"); coupler3.addChild(parachute2); diff --git a/core/test/net/sf/openrocket/file/rocksim/importt/PodTest.rkt b/core/test/net/sf/openrocket/file/rocksim/importt/PodTest.rkt new file mode 100644 index 000000000..16820a168 --- /dev/null +++ b/core/test/net/sf/openrocket/file/rocksim/importt/PodTest.rkt @@ -0,0 +1,1277 @@ + +4 + + +Pod Test +1 +1 +1 +0.75 +0.8 +0.81 +0.95 +0.95 +1 +0. +0. +0. +0. +0. +0. +0. +0. +4 +914.4 +0 +0 +0 +1 +0 +4 +22 +1 +0 +0,458.248,0,0 +0,19.4182,0,0 +0,412.178,0,0 +0,23.8755,0,0 +0,0,0,0 +0,0,0,0 +0 +1 +0 +1 +0. +0. +0 +0 +0 +0 +0 +0 +0 +0 +0. +10. +10. +10. +10. +0 +0 +0 +10. +0.15 +black +263.6 +78.74 +1062.8 +1062.8 +0. +1062.8 +0,78.74,0,0 +0,1062.8,0,0 + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + + +Aerotech +48.194 +1049.21 +Polystyrene PS +Nose cone 1 +152.4 +1 +0. +74.3632 +154. +0.0245355 +0.0245355 +0. +0 +11191 +1.9in Nose Cone +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +8 +1 +0 +0 +blue +2. +0.11224 +2. +0.11224 +1 +0 +8 +0 +0. +241.3 +48.26 +0 +1 +1 +0. +3.18 +0. +0. +0. +0. +0. + + +Custom +0. +0. +Custom +Pod 1 +0. +0 +0. +0. +0. +0. +0. +0. +0 +24.13 +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +9 +1 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +0. +1 +1 +1 + + +Aerospace Speciality Products +0. +1905.24 +G10 phenolic +Fin set 1 +0. +0 +0. +1.53887 +12.7046 +0.00131334 +0.00394002 +0. +0 +FGST20 +G10 Fin Sm Trap (0.016) +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +10 +0 +0 +0 +blue +1.83709 +0.00745107 +4.44342 +0.00745107 +1 +0 +8 +0 +0. +3 +25.4 +15.9 +31.8 +31.8 +4.76 +0.41 +0 +0 +0 +0. +0. +0. +1 +0.149994 +0. +38.8109 +2.56541 +0.625984 +0. +0. + + + + + + +Apogee +30. +0. +Mass object 1 +0. +1 +0. +0. +0. +0. +0. +0. +0 +29623 + +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +16 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +0. +0 +0. + + + + + + +Apogee +0. +1121.29 +Paper +Body tube 1 +0. +0 +0. +352.264 +125. +0.0392699 +0.0392699 +0. +0 +10131 + +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +2 +1 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +241.3 +50. +30. +250. +0 +0 +0. +0.5 +0. +0. +0 +0 + + +Custom +0. +0. +Pod 2 +0. +0 +50. +0. +0. +0. +0. +0. +0 +75. +-0.18963 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +3 +1 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +291.3 +1 +1 +1 + + +Aerotech +141. +924.265 +Polyethylene LDPE +Nose cone 2 +254. +1 +0. +42.8643 +126.345 +0.0211082 +0.0211082 +0. +0 +11401 +4in Nose Cone 4:1 Ogive +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +4 +1 +0 +0 +blue +2. +0.384158 +2. +0.384158 +1 +0 +8 +0 +291.3 +200. +50. +0 +1 +1 +0. +2.36 +0. +0. +0. +0. +0. + + +Apogee +5.3 +0.00112861 +300lb Kevlar (Apogee 29506) +Mass object 2 +0. +1 +0. +0. +0. +0. +0. +0. +2 +29625 +Screw Eye (Large) - For Mid-power rockets +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +17 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +291.3 +0 +0. + + + + + + +Apogee +0. +1121.29 +Paper +Body tube 2 +0. +0 +200. +79.2595 +50. +0.015708 +0.015708 +0. +0 +10064 + +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +13 +1 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +491.3 +50. +40. +100. +0 +0 +0. +0.5 +0. +0. +0 +0 + + +Aerospace Speciality Products +0. +1905.24 +G10 phenolic +Fin set 2 +0. +0 +0. +1.53887 +12.7046 +0.00131334 +0.00394002 +0. +0 +FGST20 +G10 Fin Sm Trap (0.016) +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +14 +0 +0 +0 +blue +2.64567 +0.498751 +4.49664 +0.498751 +1 +0 +8 +0 +491.3 +3 +25.4 +15.9 +31.8 +31.8 +4.76 +0.41 +0 +0 +0 +0. +0. +0. +1 +0.149994 +0. +39.6809 +2.59614 +0.625984 +0. +0. + + + + +Custom +0. +0. +Custom +Pod 3 +0. +0 +40. +0. +0. +0. +0. +0. +0 +50. +1.5708 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +18 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +531.3 +1 +0 +0 + + +Apogee +0. +1121.29 +Paper +Body tube 3 +0. +0 +0. +17.3079 +165.1 +0.0310895 +0.0310895 +0. +0 +10110 + +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +19 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +531.3 +29.97 +28.96 +330.2 +0 +0 +0. +0.5 +0. +0. +0 +0 + + + + + + +Apogee +0. +1121.29 +Paper +Launch lug 1 +0. +0 +0. +2.796 +12.7 +0.00209309 +0.00119695 +0. +0 +13051 +1/8in X 1in Launch Lug +32.5 +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +21 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +491.3 +15. +10. +50. +0 + + + + + + +LOC Precision +0.375 +1049.21 +Polystyrene PS +Transition 2 +120.65 +0 +300. +51.2048 +35.4462 +0.0160582 +0.0160582 +0. +0 +AR-3.90-3.00 +Airframe Reducer from 3.90 to 3.00 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +15 +0 +0 +0 +blue +6.44046 +0.626578 +6.44046 +0.626578 +1 +0 +8 +0 +591.3 +50. +100. +63.5 +0 +0. +0. +1 +3.18 +0. +0. +0. +0 +0. +127. +63.5 + + + + + + +Aerospace Speciality Products +0. +128.148 +Balsa +Bulkhead 1 +0. +0 +0. +9.23939 +51. +0. +0. +0. +0 +BH60 + +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +22 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +241.3 +30. +0. +102. +0 +1 +1 + + + + + + +LOC Precision +0.25 +1049.21 +Polystyrene PS +Transition 1 +107.95 +0 +0. +54.365 +41.7981 +0.0170804 +0.0170804 +0. +0 +AR-3.00-2.14 +Airframe Reducer from 3.00 to 2.14 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +5 +1 +0 +0 +blue +2.49499 +0.532996 +2.49499 +0.532996 +1 +0 +8 +0 +491.3 +57.4 +78.74 +79.25 +0 +0. +0. +1 +3.18 +0. +0. +0. +0 +0. +292.389 +213.139 + + +Apogee +8.5 +0.00112861 +300lb Kevlar (Apogee 29506) +Mass object 3 +0. +1 +0. +0. +0. +0. +0. +0. +2 +29620 + +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +20 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +491.3 +0 +0. + + + + +Custom +0. +0. +Custom +Pod 4 +0. +0 +0. +0. +0. +0. +0. +0. +0 +63.5 +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +7 +1 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +491.3 +1 +1 +1 + + +Aerotech +48.194 +1049.21 +Polystyrene PS +Nose cone 3 +152.4 +1 +0. +74.3632 +154. +0.0245355 +0.0245355 +0. +0 +11191 +1.9in Nose Cone +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +12 +0 +0 +0 +blue +2. +0.60354 +2. +0.60354 +1 +0 +8 +0 +491.3 +241.3 +48.26 +0 +1 +1 +0. +3.18 +0. +0. +0. +0. +0. + + + + +Apogee +0. +1121.29 +Paper +Body tube 4 +0. +0 +241.3 +17.3079 +165.1 +0.0310895 +0.0310895 +0. +0 +10110 + +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr=(0)|flips=(0)|flipt=(0)|preventseam=(1)|rotate=(0) +1. +0. +1. +0. +1. +blue +blue +white +1 +11 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +732.6 +29.97 +28.96 +330.2 +0 +0 +0. +0.5 +0. +0. +0 +0 + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/test/net/sf/openrocket/file/rocksim/importt/RockSimLoaderTest.java b/core/test/net/sf/openrocket/file/rocksim/importt/RockSimLoaderTest.java index c6d3cbbb8..1eac69a8a 100644 --- a/core/test/net/sf/openrocket/file/rocksim/importt/RockSimLoaderTest.java +++ b/core/test/net/sf/openrocket/file/rocksim/importt/RockSimLoaderTest.java @@ -8,10 +8,17 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import net.sf.openrocket.rocketcomponent.Bulkhead; +import net.sf.openrocket.rocketcomponent.CenteringRing; import net.sf.openrocket.rocketcomponent.FreeformFinSet; +import net.sf.openrocket.rocketcomponent.InnerTube; +import net.sf.openrocket.rocketcomponent.MassComponent; import net.sf.openrocket.rocketcomponent.NoseCone; +import net.sf.openrocket.rocketcomponent.Parachute; +import net.sf.openrocket.rocketcomponent.PodSet; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.Transition; +import net.sf.openrocket.rocketcomponent.TrapezoidFinSet; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; import org.junit.Assert; @@ -212,7 +219,41 @@ public class RockSimLoaderTest extends BaseTestCase { Assert.assertEquals(0.185d, stage1.getOverrideMass(), 0.001); Assert.assertTrue(stage1.isCGOverridden()); Assert.assertEquals(0.3d, stage1.getOverrideCG().x, 0.001); - Assert.assertEquals(3, loader.getWarnings().size()); + Assert.assertEquals(2, loader.getWarnings().size()); + + NoseCone nc = (NoseCone) stage1.getChild(0); + Assert.assertEquals(2, nc.getChildCount()); + Assert.assertEquals("Clay", nc.getChild(0).getName()); + RocketComponent it = nc.getChild(1); + Assert.assertEquals(InnerTube.class, it.getClass()); + Assert.assertEquals("Attachment Rod", it.getName()); + + Assert.assertEquals(3, it.getChildCount()); + RocketComponent c = it.getChild(0); + Assert.assertEquals(CenteringRing.class, c.getClass()); + Assert.assertEquals("Plate", c.getName()); + c = it.getChild(1); + Assert.assertEquals(CenteringRing.class, c.getClass()); + Assert.assertEquals("Sleeve ", c.getName()); + c = it.getChild(2); + Assert.assertEquals(Parachute.class, c.getClass()); + Assert.assertEquals("Nose Cone Parachute", c.getName()); + + BodyTube bt1 = (BodyTube) stage1.getChild(1); + Assert.assertEquals(5, bt1.getChildCount()); + Assert.assertEquals("Centering ring", bt1.getChild(0).getName()); + Assert.assertEquals("Centering ring", bt1.getChild(1).getName()); + c = bt1.getChild(2); + Assert.assertEquals(InnerTube.class, c.getClass()); + Assert.assertEquals("Body tube", c.getName()); + Assert.assertEquals("Launch lug", bt1.getChild(3).getName()); + Assert.assertEquals("Pod", bt1.getChild(4).getName()); + + PodSet pod = (PodSet) bt1.getChild(4); + Assert.assertEquals(1, pod.getChildCount()); + c = pod.getChild(0); + Assert.assertEquals(BodyTube.class, c.getClass()); + Assert.assertEquals("Body tube", pod.getChild(0).getName()); Assert.assertEquals(1, stage2.getChildCount()); Assert.assertEquals("2nd Stage Tube", stage2.getChild(0).getName()); @@ -221,8 +262,8 @@ public class RockSimLoaderTest extends BaseTestCase { Assert.assertTrue(stage2.isCGOverridden()); Assert.assertEquals(0.4d, stage2.getOverrideCG().x, 0.001); - BodyTube bt = (BodyTube) stage2.getChild(0); - LaunchLug ll = (LaunchLug) bt.getChild(6); + BodyTube bt2 = (BodyTube) stage2.getChild(0); + LaunchLug ll = (LaunchLug) bt2.getChild(6); Assert.assertEquals(1.22d, ll.getAngleOffset(), 0.001); Assert.assertEquals(2, stage3.getChildCount()); @@ -342,6 +383,97 @@ public class RockSimLoaderTest extends BaseTestCase { Assert.assertEquals(0, bodyTube3.getChildCount()); } + @Test + public void testPodRocket() throws IOException, RocketLoadException{ + RockSimLoader loader = new RockSimLoader(); + OpenRocketDocument doc = loadRockSimRocket(loader, "PodTest.rkt"); + + Assert.assertNotNull(doc); + Rocket rocket = doc.getRocket(); + Assert.assertNotNull(rocket); + Assert.assertEquals("Pod Test", doc.getRocket().getName()); + Assert.assertEquals(3, loader.getWarnings().size()); + + InputStream stream = this.getClass().getResourceAsStream("PodTest.rkt"); + Assert.assertNotNull("Could not open PodTest.rkt", stream); + + doc = OpenRocketDocumentFactory.createEmptyRocket(); + DocumentLoadingContext context = new DocumentLoadingContext(); + context.setOpenRocketDocument(doc); + context.setMotorFinder(new DatabaseMotorFinder()); + loader.loadFromStream(context, new BufferedInputStream(stream)); + + Assert.assertNotNull(doc); + rocket = doc.getRocket(); + Assert.assertNotNull(rocket); + Assert.assertEquals(1, rocket.getStageCount()); + AxialStage stage1 = (AxialStage) rocket.getChild(0); + + Assert.assertEquals(3, stage1.getChildCount()); + RocketComponent noseCone1 = stage1.getChild(0); + RocketComponent bodyTube1 = stage1.getChild(1); + RocketComponent transition1 = stage1.getChild(2); + Assert.assertEquals(NoseCone.class, noseCone1.getClass()); + Assert.assertEquals(BodyTube.class, bodyTube1.getClass()); + Assert.assertEquals(Transition.class, transition1.getClass()); + Assert.assertEquals("Nose cone 1", noseCone1.getName()); + Assert.assertEquals("Body tube 1", bodyTube1.getName()); + Assert.assertEquals("Transition 1", transition1.getName()); + + Assert.assertEquals(1, noseCone1.getChildCount()); + RocketComponent component = noseCone1.getChild(0); + Assert.assertEquals(MassComponent.class, component.getClass()); + Assert.assertEquals("Mass object 1", component.getName()); + + Assert.assertEquals(2, bodyTube1.getChildCount()); + RocketComponent pod2 = bodyTube1.getChild(0); + Assert.assertEquals(PodSet.class, pod2.getClass()); + Assert.assertEquals("Pod 2", pod2.getName()); + component = bodyTube1.getChild(1); + Assert.assertEquals(Bulkhead.class, component.getClass()); + Assert.assertEquals("Bulkhead 1", component.getName()); + + Assert.assertEquals(3, pod2.getChildCount()); + RocketComponent noseCone2 = pod2.getChild(0); + Assert.assertEquals(NoseCone.class, noseCone2.getClass()); + Assert.assertEquals("Nose cone 2", noseCone2.getName()); + RocketComponent bodyTube2 = pod2.getChild(1); + Assert.assertEquals(BodyTube.class, bodyTube2.getClass()); + Assert.assertEquals("Body tube 2", bodyTube2.getName()); + component = pod2.getChild(2); + Assert.assertEquals(Transition.class, component.getClass()); + Assert.assertEquals("Transition 2", component.getName()); + + Assert.assertEquals(1, noseCone2.getChildCount()); + component = noseCone2.getChild(0); + Assert.assertEquals(MassComponent.class, component.getClass()); + Assert.assertEquals("Mass object 2", component.getName()); + + Assert.assertEquals(3, bodyTube2.getChildCount()); + component = bodyTube2.getChild(0); + Assert.assertEquals(TrapezoidFinSet.class, component.getClass()); + Assert.assertEquals("Fin set 2", component.getName()); + RocketComponent pod3 = bodyTube2.getChild(1); + Assert.assertEquals(PodSet.class, pod3.getClass()); + Assert.assertEquals("Pod 3", pod3.getName()); + component = bodyTube2.getChild(2); + Assert.assertEquals(LaunchLug.class, component.getClass()); + Assert.assertEquals("Launch lug 1", component.getName()); + + Assert.assertEquals(1, pod3.getChildCount()); + component = pod3.getChild(0); + Assert.assertEquals(BodyTube.class, component.getClass()); + Assert.assertEquals("Body tube 3", component.getName()); + Assert.assertEquals(0.04, pod3.getAxialOffset(), MathUtil.EPSILON); + Assert.assertEquals(Math.PI / 2, pod3.getAngleOffset(), 0.0001); + Assert.assertEquals(0.05, pod3.getRadiusOffset(), MathUtil.EPSILON); + + Assert.assertEquals(1, transition1.getChildCount()); + component = transition1.getChild(0); + Assert.assertEquals(MassComponent.class, component.getClass()); + Assert.assertEquals("Mass object 3", component.getName()); + } + public static OpenRocketDocument loadRockSimRocket(RockSimLoader theLoader, String fileName) throws IOException, RocketLoadException { try (InputStream stream = RockSimLoaderTest.class.getResourceAsStream(fileName)) { Assert.assertNotNull("Could not open " + fileName, stream);