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/file/rocksim/importt/RockSimHandler.java b/core/src/net/sf/openrocket/file/rocksim/importt/RockSimHandler.java index 52f0c8fe7..1aef79cd3 100644 --- a/core/src/net/sf/openrocket/file/rocksim/importt/RockSimHandler.java +++ b/core/src/net/sf/openrocket/file/rocksim/importt/RockSimHandler.java @@ -350,6 +350,9 @@ class StageHandler extends AbstractElementHandler { if (RockSimCommonConstants.TRANSITION.equals(element)) { return new TransitionHandler(context, component, warnings); } + if (RockSimCommonConstants.SUBASSEMBLY.equals(element)) { + return new SubAssemblyHandler(context, component); + } return null; } } diff --git a/core/src/net/sf/openrocket/file/rocksim/importt/SubAssemblyHandler.java b/core/src/net/sf/openrocket/file/rocksim/importt/SubAssemblyHandler.java index 476696a03..a80f3034d 100644 --- a/core/src/net/sf/openrocket/file/rocksim/importt/SubAssemblyHandler.java +++ b/core/src/net/sf/openrocket/file/rocksim/importt/SubAssemblyHandler.java @@ -10,18 +10,21 @@ import net.sf.openrocket.rocketcomponent.RocketComponent; import java.util.HashMap; /** - * This class handles Rocksim 'SubAssembly' elements. They are similar to 'AttachedParts' (which is why this class is subclassed from - * AttachedPartsHandler) with some key differences. In Rocksim, AttachedParts elements can contain SubAssembly elements, which can in turn + * This class handles RockSim 'SubAssembly' elements. They are similar to 'AttachedParts' (which is why this class is subclassed from + * AttachedPartsHandler) with some key differences. In RockSim, AttachedParts elements can contain SubAssembly elements, which can in turn * contain AttachedParts elements. To represent them in OR, SubAssembly elements are treated as children of the stage - much like a nose cone or * external body tube. */ public class SubAssemblyHandler extends AttachedPartsHandler { + /** + * Constructor + * @param c the parent component + * @throws IllegalArgumentException + */ public SubAssemblyHandler(final DocumentLoadingContext context, final RocketComponent c) throws IllegalArgumentException { - //A bit of a risk here, but assign the subassembly to the stage, not to the component. This is because typically the - //first component within the subassembly will be an external component. - super(context, c.getStage()); + super(context, c); } @Override @@ -33,9 +36,14 @@ public class SubAssemblyHandler extends AttachedPartsHandler { if (RockSimCommonConstants.ATTACHED_PARTS.equals(element)) { return this; } - // The key override of this class - treat body tubes as external body tubes. + // The key override of this class - treat body tubes, transitions, and nose cones as external components. + // note: this will only work if the parent component is a stage. else if (RockSimCommonConstants.BODY_TUBE.equals(element)) { return new BodyTubeHandler(getContext(), getComponent(), warnings); + } else if (RockSimCommonConstants.TRANSITION.equals(element)) { + return new TransitionHandler(getContext(), getComponent(), warnings); + } else if (RockSimCommonConstants.NOSE_CONE.equals(element)) { + return new NoseConeHandler(getContext(), getComponent(), warnings); } return super.openElement(element, attributes, warnings); } 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/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java index 177181168..339c0704b 100644 --- a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java +++ b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java @@ -221,25 +221,16 @@ public class BasicEventSimulationEngine implements SimulationEngine { // and thrust < THRUST_TUMBLE_CONDITION threshold if (!currentStatus.isTumbling()) { - final double t = currentStatus.getFlightData().getLast(FlightDataType.TYPE_THRUST_FORCE); final double cp = currentStatus.getFlightData().getLast(FlightDataType.TYPE_CP_LOCATION); final double cg = currentStatus.getFlightData().getLast(FlightDataType.TYPE_CG_LOCATION); final double aoa = currentStatus.getFlightData().getLast(FlightDataType.TYPE_AOA); final boolean wantToTumble = (cg > cp && aoa > AOA_TUMBLE_CONDITION); - - if (wantToTumble) { - final boolean tooMuchThrust = t > THRUST_TUMBLE_CONDITION; - final boolean isSustainer = currentStatus.getConfiguration().isStageActive(0); - final boolean isApogee = currentStatus.isApogeeReached(); - if (tooMuchThrust) { - currentStatus.getWarnings().add(Warning.TUMBLE_UNDER_THRUST); - } else if (isApogee || !isSustainer) { - addEvent(new FlightEvent(FlightEvent.Type.TUMBLE, currentStatus.getSimulationTime())); - currentStatus.setTumbling(true); - } - } - + final boolean isSustainer = currentStatus.getConfiguration().isStageActive(0); + final boolean isApogee = currentStatus.isApogeeReached(); + if (wantToTumble && (isApogee || !isSustainer)) { + addEvent(new FlightEvent(FlightEvent.Type.TUMBLE, currentStatus.getSimulationTime())); + } } // If I'm on the ground and have no events in the queue, I'm done @@ -535,6 +526,7 @@ public class BasicEventSimulationEngine implements SimulationEngine { currentStatus.getFlightData().addEvent(event); } + log.debug("deployed recovery devices: " + currentStatus.getDeployedRecoveryDevices().size() ); break; case GROUND_HIT: @@ -556,10 +548,19 @@ public class BasicEventSimulationEngine implements SimulationEngine { break; case TUMBLE: - if (!currentStatus.isLanded()) { - currentStepper = tumbleStepper; - currentStatus = currentStepper.initialize(currentStatus); - } + // Inhibit if we've deployed a parachute or we're on the ground + if ((currentStatus.getDeployedRecoveryDevices().size() > 0) || currentStatus.isLanded()) + break; + + currentStepper = tumbleStepper; + currentStatus = currentStepper.initialize(currentStatus); + + final boolean tooMuchThrust = currentStatus.getFlightData().getLast(FlightDataType.TYPE_THRUST_FORCE) > THRUST_TUMBLE_CONDITION; + if (tooMuchThrust) { + currentStatus.getWarnings().add(Warning.TUMBLE_UNDER_THRUST); + } + + currentStatus.setTumbling(true); currentStatus.getFlightData().addEvent(event); break; } 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 cbc82e30f..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; @@ -78,7 +81,7 @@ public class RockSimDocumentDTOTest extends RockSimTestBase { @Test public void testRoundTrip() throws Exception { // TODO need checks here to validate that correct things were done - OpenRocketDocument ord = RockSimLoaderTest.loadRockSimRocket3(new RockSimLoader()); + OpenRocketDocument ord = RockSimLoaderTest.loadRockSimRocket(new RockSimLoader(), "rocksimTestRocket3.rkt"); Assert.assertNotNull(ord); String result = new RockSimSaver().marshalToRockSim(ord); @@ -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/BodyTubeChildrenTest.rkt b/core/test/net/sf/openrocket/file/rocksim/importt/BodyTubeChildrenTest.rkt new file mode 100644 index 000000000..a678fd281 --- /dev/null +++ b/core/test/net/sf/openrocket/file/rocksim/importt/BodyTubeChildrenTest.rkt @@ -0,0 +1,483 @@ + + 4 + + + Body Tube Children Test + 1 + 7 + 0 + 3 + 0 + 3 + 0.0 + 0.0 + 0 + 0 + 0 + 0 + 0 + 0 + 18 + 0.0 + 0.0 + 0.0 + 426.6301716552979 + 0.0 + 0.0 + 0.0 + 0.0 + 1 + 1 + 0 + + + 6.107306539734526 + 1049.21 + Polystyrene PS + Nose cone + 0.0 + 0 + 0.0 + 6.107306539734526 + 53.68748632541546 + 0 + 0.0 + 0.0 + 0 + 76.2 + 0 + 1 + 3 + 1 + 1.00076 + 0.0 + + 24.8006 + 19.1008 + 23.5991 + + + 15.040422946044567 + 1121.29 + Paper + Forward Body tube + 0.0 + 0 + 0.0 + 15.040422946044567 + 228.6 + 0 + 0.0 + 0.0 + 0 + 457.2 + 0 + 2 + 24.892 + 24.13 + 0 + 24.13 + 0.0 + 0 + + + 0.0 + 1121.29 + Paper + Tube coupler + 0.0 + 0 + 120.65 + 0.0 + 31.75 + 0 + 0.0 + 0.0 + 0 + 63.5 + 0 + 3 + 27.8892 + 27.8892 + 4 + 0 + + + 10.038912051168 + 0.00664972 + Mylar + Streamer + 0.0 + 0 + 44.45 + 10.038912051168 + 57.15 + 1 + 0.0 + 0.0 + 0 + 114.3 + 0 + 4 + 114.3 + 0.138 + + + 1.2996672000000002 + 0.0 + + Shock Cord + 187.325 + 1 + 187.325 + 0.0 + 0.0 + 0 + 0.0 + 0.0 + 0 + 12.192000000000002 + 0 + 5 + 0 + + + 2.549 + 0.0 + + Mass object - 2.549 g + 282.575 + 1 + 282.575 + 0.0 + 0.0 + 0 + 0.0 + 0.0 + 0 + 0.0 + 0 + 6 + 0 + + + 1.1277286611933457 + 1121.29 + Paper + Centering ring + 0.0 + 0 + 384.175 + 1.1277286611933457 + 3.175 + 0 + 0.0 + 0.0 + 0 + 6.35 + 0 + 7 + 28.702 + 24.9428 + 0 + 0 + + + 1.1277286611933457 + 1121.29 + Paper + Centering ring + 0.0 + 0 + 358.775 + 1.1277286611933457 + 3.175 + 0 + 0.0 + 0.0 + 0 + 6.35 + 0 + 8 + 28.702 + 24.9428 + 0 + 0 + + + 1.1277286611933457 + 1121.29 + Paper + Centering ring + 0.0 + 0 + 288.925 + 1.1277286611933457 + 3.175 + 0 + 0.0 + 0.0 + 0 + 6.35 + 0 + 9 + 28.702 + 24.9428 + 0 + 0 + + + + + 13.498613632777841 + 1121.29 + Paper + Aft Body tube + 0.0 + 0 + 0.0 + 13.498613632777841 + 165.1 + 0 + 0.0 + 0.0 + 0 + 330.2 + 0 + 10 + 29.8704 + 29.083 + 1 + 29.083 + 12.7 + 0 + + + 1.25084668869137 + 1121.29 + Paper + Engine block + 0.0 + 0 + 252.73000000000002 + 1.25084668869137 + 3.175 + 0 + 0.0 + 0.0 + 0 + 6.35 + 0 + 11 + 29.083 + 24.9428 + 2 + 0 + + + 0.9977479979838839 + 128.148 + Balsa + Fin set-1 + 0.0 + 0 + 257.175 + 0.9977479979838839 + 54.72939060773481 + 0 + 0.0 + 0.0 + 0 + 0.0 + 0 + 12 + 1 + 66.675 + 29.8704 + 50.8 + 67.4141 + 3.175 + 0 + 0 + 0.0 + 0.0 + 0.0 + 1 + 0.0 + + + 2.8874580315239995 + 128.148 + Balsa + Fin set + 0.0 + 0 + 146.05 + 2.8874580315239995 + 61.383333333333326 + 0 + 0.0 + 0.785398 + 0 + 0.0 + 0 + 13 + 4 + 101.6 + 0.0 + 34.925 + 82.55 + 3.175 + 0 + 0 + 0.0 + 0.0 + 0.0 + 1 + 0.0 + + + 0.9977479979838839 + 128.148 + Balsa + Fin set-2 + 0.0 + 0 + 257.175 + 0.9977479979838839 + 54.72939060773481 + 0 + 0.0 + 1.5708 + 0 + 0.0 + 0 + 14 + 1 + 66.675 + 29.8704 + 50.8 + 67.4141 + 3.175 + 0 + 0 + 0.0 + 0.0 + 0.0 + 1 + 0.0 + + + 0.9977479979838839 + 128.148 + Balsa + Fin set-3 + 0.0 + 0 + 257.175 + 0.9977479979838839 + 54.72939060773481 + 0 + 0.0 + 3.14159 + 0 + 0.0 + 0 + 15 + 1 + 66.675 + 29.8704 + 50.8 + 67.4141 + 3.175 + 0 + 0 + 0.0 + 0.0 + 0.0 + 1 + 0.0 + + + 0.9977479979838839 + 128.148 + Balsa + Fin set-4 + 0.0 + 0 + 257.175 + 0.9977479979838839 + 54.72939060773481 + 0 + 0.0 + -1.5708 + 0 + 0.0 + 0 + 16 + 1 + 66.675 + 29.8704 + 50.8 + 67.4141 + 3.175 + 0 + 0 + 0.0 + 0.0 + 0.0 + 1 + 0.0 + + + 1.1277286611933457 + 1121.29 + Paper + Centering ring + 0.0 + 0 + 323.85 + 1.1277286611933457 + 3.175 + 0 + 0.0 + 0.0 + 2 + 6.35 + 0 + 17 + 28.702 + 24.9428 + 0 + 0 + + + 1.1277286611933457 + 1121.29 + Paper + Centering ring + 0.0 + 0 + 282.575 + 1.1277286611933457 + 3.175 + 0 + 0.0 + 0.0 + 2 + 6.35 + 0 + 18 + 28.702 + 24.9428 + 0 + 0 + + + + + + + + + \ No newline at end of file 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 598ba4f6f..1eac69a8a 100644 --- a/core/test/net/sf/openrocket/file/rocksim/importt/RockSimLoaderTest.java +++ b/core/test/net/sf/openrocket/file/rocksim/importt/RockSimLoaderTest.java @@ -7,11 +7,18 @@ package net.sf.openrocket.file.rocksim.importt; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.Arrays; +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; @@ -57,148 +64,10 @@ public class RockSimLoaderTest extends BaseTestCase { Assert.assertTrue(loader.getWarnings().size() == 2); } - /** - * Method: loadFromStream(InputStream source) - * - * @throws Exception thrown if something goes awry - */ - @org.junit.Test - public void testLoadFromStream() throws Exception { - RockSimLoader loader = new RockSimLoader(); - //Stupid single stage rocket - OpenRocketDocument doc = loadRockSimRocket(loader); - InputStream stream; - - Assert.assertNotNull(doc); - Rocket rocket = doc.getRocket(); - Assert.assertNotNull(rocket); - Assert.assertEquals("FooBar Test", doc.getRocket().getName()); - Assert.assertTrue(loader.getWarnings().isEmpty()); - - stream = this.getClass().getResourceAsStream("rocksimTestRocket2.rkt"); - Assert.assertNotNull("Could not open rocksimTestRocket2.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); - - //Do some simple asserts; the important thing here is just validating that the mass and cg were - //not overridden for each stage. - Assert.assertEquals("Three Stage Everything Included Rocket", doc.getRocket().getName()); - Assert.assertEquals(0, loader.getWarnings().size()); - Assert.assertEquals(3, rocket.getStageCount()); - AxialStage stage1 = (AxialStage) rocket.getChild(0); - Assert.assertFalse(stage1.isMassOverridden()); - Assert.assertFalse(stage1.isCGOverridden()); - AxialStage stage2 = (AxialStage) rocket.getChild(1); - Assert.assertFalse(stage2.isMassOverridden()); - Assert.assertFalse(stage2.isCGOverridden()); - AxialStage stage3 = (AxialStage) rocket.getChild(2); - Assert.assertFalse(stage3.isMassOverridden()); - Assert.assertFalse(stage3.isCGOverridden()); - - stream = this.getClass().getResourceAsStream("rocksimTestRocket3.rkt"); - Assert.assertNotNull("Could not open rocksimTestRocket3.rkt", stream); - - doc = OpenRocketDocumentFactory.createEmptyRocket(); - 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("Three Stage Everything Included Rocket - Override Total Mass/CG", doc.getRocket().getName()); - Assert.assertEquals(3, rocket.getStageCount()); - stage1 = (AxialStage) rocket.getChild(0); - stage2 = (AxialStage) rocket.getChild(1); - stage3 = (AxialStage) rocket.getChild(2); - - //Do some 1st level and simple asserts; the idea here is to not do a deep validation as that - //should have been covered elsewhere. Assert that the stage overrides are correct. - Assert.assertEquals(2, stage1.getChildCount()); - Assert.assertEquals("Nose cone", stage1.getChild(0).getName()); - Assert.assertEquals("Body tube", stage1.getChild(1).getName()); - Assert.assertTrue(stage1.isMassOverridden()); - 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(1, stage2.getChildCount()); - Assert.assertEquals("2nd Stage Tube", stage2.getChild(0).getName()); - Assert.assertTrue(stage2.isMassOverridden()); - Assert.assertEquals(0.21d, stage2.getOverrideMass(), 0.001); - 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); - Assert.assertEquals(1.22d, ll.getAngleOffset(), 0.001); - - Assert.assertEquals(2, stage3.getChildCount()); - Assert.assertEquals("Transition", stage3.getChild(0).getName()); - Assert.assertEquals("Body tube", stage3.getChild(1).getName()); - Assert.assertTrue(stage2.isMassOverridden()); - Assert.assertEquals(0.33d, stage3.getOverrideMass(), 0.001); - Assert.assertTrue(stage2.isCGOverridden()); - Assert.assertEquals(0.5d, stage3.getOverrideCG().x, 0.001); - } - - @org.junit.Test - public void testSubAssemblyRocket() throws IOException, RocketLoadException { - RockSimLoader loader = new RockSimLoader(); - //Stupid single stage rocket - OpenRocketDocument doc = loadRockSimSubassemblyRocket(loader); - InputStream stream; - - Assert.assertNotNull(doc); - Rocket rocket = doc.getRocket(); - Assert.assertNotNull(rocket); - Assert.assertEquals("SubAssembly Element Test", doc.getRocket().getName()); - Assert.assertTrue(loader.getWarnings().isEmpty()); - - stream = this.getClass().getResourceAsStream("SubAssemblyTest.rkt"); - Assert.assertNotNull("Could not open SubAssemblyTest.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("Nose cone", stage1.getChild(0).getName()); - Assert.assertEquals("Forward Body tube", stage1.getChild(1).getName()); - Assert.assertEquals("Aft Body tube", stage1.getChild(2).getName()); - - BodyTube subassemblyBodyTube = (BodyTube)stage1.getChild(2); - Assert.assertEquals(8, subassemblyBodyTube.getChildCount()); - Assert.assertEquals("Engine block", subassemblyBodyTube.getChild(0).getName()); - Assert.assertEquals("Fin set-1", subassemblyBodyTube.getChild(1).getName()); - Assert.assertEquals("Fin set", subassemblyBodyTube.getChild(2).getName()); - Assert.assertEquals("Fin set-2", subassemblyBodyTube.getChild(3).getName()); - Assert.assertEquals("Fin set-3", subassemblyBodyTube.getChild(4).getName()); - Assert.assertEquals("Fin set-4", subassemblyBodyTube.getChild(5).getName()); - Assert.assertEquals("Centering ring", subassemblyBodyTube.getChild(6).getName()); - Assert.assertEquals("Centering ring", subassemblyBodyTube.getChild(7).getName()); - } - @Test public void testFinsOnTransitions() throws IOException, RocketLoadException { RockSimLoader loader = new RockSimLoader(); - OpenRocketDocument doc = loadRockSimFinsOnTransitionsRocket(loader); + OpenRocketDocument doc = loadRockSimRocket(loader, "FinsOnTransitions.rkt"); Assert.assertNotNull(doc); Rocket rocket = doc.getRocket(); @@ -277,57 +146,337 @@ public class RockSimLoaderTest extends BaseTestCase { Assert.assertEquals(" Fin set 2 fin tab offset does not match", 0, freeformFinSet2.getTabOffset(), MathUtil.EPSILON); } - public static OpenRocketDocument loadRockSimRocket(RockSimLoader theLoader) throws IOException, RocketLoadException { - InputStream stream = RockSimLoaderTest.class.getResourceAsStream("rocksimTestRocket1.rkt"); - try { - Assert.assertNotNull("Could not open rocksimTestRocket1.rkt", stream); - OpenRocketDocument doc = OpenRocketDocumentFactory.createEmptyRocket(); - DocumentLoadingContext context = new DocumentLoadingContext(); - context.setOpenRocketDocument(doc); - context.setMotorFinder(new DatabaseMotorFinder()); - theLoader.loadFromStream(context, new BufferedInputStream(stream)); - return doc; - } - finally { - stream.close(); - } + /** + * Method: loadFromStream(InputStream source) + * + * @throws Exception thrown if something goes awry + */ + @org.junit.Test + public void testLoadFromStream() throws Exception { + RockSimLoader loader = new RockSimLoader(); + //Stupid single stage rocket + OpenRocketDocument doc = loadRockSimRocket(loader, "rocksimTestRocket1.rkt"); + InputStream stream; + + Assert.assertNotNull(doc); + Rocket rocket = doc.getRocket(); + Assert.assertNotNull(rocket); + Assert.assertEquals("FooBar Test", doc.getRocket().getName()); + Assert.assertTrue(loader.getWarnings().isEmpty()); + + stream = this.getClass().getResourceAsStream("rocksimTestRocket2.rkt"); + Assert.assertNotNull("Could not open rocksimTestRocket2.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); + + //Do some simple asserts; the important thing here is just validating that the mass and cg were + //not overridden for each stage. + Assert.assertEquals("Three Stage Everything Included Rocket", doc.getRocket().getName()); + Assert.assertEquals(0, loader.getWarnings().size()); + Assert.assertEquals(3, rocket.getStageCount()); + AxialStage stage1 = (AxialStage) rocket.getChild(0); + Assert.assertFalse(stage1.isMassOverridden()); + Assert.assertFalse(stage1.isCGOverridden()); + AxialStage stage2 = (AxialStage) rocket.getChild(1); + Assert.assertFalse(stage2.isMassOverridden()); + Assert.assertFalse(stage2.isCGOverridden()); + AxialStage stage3 = (AxialStage) rocket.getChild(2); + Assert.assertFalse(stage3.isMassOverridden()); + Assert.assertFalse(stage3.isCGOverridden()); + + stream = this.getClass().getResourceAsStream("rocksimTestRocket3.rkt"); + Assert.assertNotNull("Could not open rocksimTestRocket3.rkt", stream); + + doc = OpenRocketDocumentFactory.createEmptyRocket(); + 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("Three Stage Everything Included Rocket - Override Total Mass/CG", doc.getRocket().getName()); + Assert.assertEquals(3, rocket.getStageCount()); + stage1 = (AxialStage) rocket.getChild(0); + stage2 = (AxialStage) rocket.getChild(1); + stage3 = (AxialStage) rocket.getChild(2); + + //Do some 1st level and simple asserts; the idea here is to not do a deep validation as that + //should have been covered elsewhere. Assert that the stage overrides are correct. + Assert.assertEquals(2, stage1.getChildCount()); + Assert.assertEquals("Nose cone", stage1.getChild(0).getName()); + Assert.assertEquals("Body tube", stage1.getChild(1).getName()); + Assert.assertTrue(stage1.isMassOverridden()); + Assert.assertEquals(0.185d, stage1.getOverrideMass(), 0.001); + Assert.assertTrue(stage1.isCGOverridden()); + Assert.assertEquals(0.3d, stage1.getOverrideCG().x, 0.001); + 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()); + Assert.assertTrue(stage2.isMassOverridden()); + Assert.assertEquals(0.21d, stage2.getOverrideMass(), 0.001); + Assert.assertTrue(stage2.isCGOverridden()); + Assert.assertEquals(0.4d, stage2.getOverrideCG().x, 0.001); + + 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()); + Assert.assertEquals("Transition", stage3.getChild(0).getName()); + Assert.assertEquals("Body tube", stage3.getChild(1).getName()); + Assert.assertTrue(stage2.isMassOverridden()); + Assert.assertEquals(0.33d, stage3.getOverrideMass(), 0.001); + Assert.assertTrue(stage2.isCGOverridden()); + Assert.assertEquals(0.5d, stage3.getOverrideCG().x, 0.001); } - public static OpenRocketDocument loadRockSimRocket3(RockSimLoader theLoader) throws IOException, RocketLoadException { - InputStream stream = RockSimLoaderTest.class.getResourceAsStream("rocksimTestRocket3.rkt"); - try { - Assert.assertNotNull("Could not open rocksimTestRocket3.rkt", stream); - OpenRocketDocument doc = OpenRocketDocumentFactory.createEmptyRocket(); - DocumentLoadingContext context = new DocumentLoadingContext(); - context.setOpenRocketDocument(doc); - context.setMotorFinder(new DatabaseMotorFinder()); - theLoader.loadFromStream(context, new BufferedInputStream(stream)); - return doc; - } - finally { - stream.close(); - } + @org.junit.Test + public void testBodyTubeChildrenRocket() throws IOException, RocketLoadException { + RockSimLoader loader = new RockSimLoader(); + //Stupid single stage rocket + OpenRocketDocument doc = loadRockSimRocket(loader, "BodyTubeChildrenTest.rkt"); + InputStream stream; + + Assert.assertNotNull(doc); + Rocket rocket = doc.getRocket(); + Assert.assertNotNull(rocket); + Assert.assertEquals("Body Tube Children Test", doc.getRocket().getName()); + Assert.assertTrue(loader.getWarnings().isEmpty()); + + stream = this.getClass().getResourceAsStream("BodyTubeChildrenTest.rkt"); + Assert.assertNotNull("Could not open BodyTubeChildrenTest.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("Nose cone", stage1.getChild(0).getName()); + Assert.assertEquals("Forward Body tube", stage1.getChild(1).getName()); + Assert.assertEquals("Aft Body tube", stage1.getChild(2).getName()); + + BodyTube subassemblyBodyTube = (BodyTube)stage1.getChild(2); + Assert.assertEquals(8, subassemblyBodyTube.getChildCount()); + Assert.assertEquals("Engine block", subassemblyBodyTube.getChild(0).getName()); + Assert.assertEquals("Fin set-1", subassemblyBodyTube.getChild(1).getName()); + Assert.assertEquals("Fin set", subassemblyBodyTube.getChild(2).getName()); + Assert.assertEquals("Fin set-2", subassemblyBodyTube.getChild(3).getName()); + Assert.assertEquals("Fin set-3", subassemblyBodyTube.getChild(4).getName()); + Assert.assertEquals("Fin set-4", subassemblyBodyTube.getChild(5).getName()); + Assert.assertEquals("Centering ring", subassemblyBodyTube.getChild(6).getName()); + Assert.assertEquals("Centering ring", subassemblyBodyTube.getChild(7).getName()); } - public static OpenRocketDocument loadRockSimSubassemblyRocket(RockSimLoader theLoader) throws IOException, RocketLoadException { - InputStream stream = RockSimLoaderTest.class.getResourceAsStream("SubAssemblyTest.rkt"); - try { - Assert.assertNotNull("Could not open SubAssemblyTest.rkt", stream); - OpenRocketDocument doc = OpenRocketDocumentFactory.createEmptyRocket(); - DocumentLoadingContext context = new DocumentLoadingContext(); - context.setOpenRocketDocument(doc); - context.setMotorFinder(new DatabaseMotorFinder()); - theLoader.loadFromStream(context, new BufferedInputStream(stream)); - return doc; - } - finally { - stream.close(); - } + @Test + public void testSubAssemblyRocket() throws IOException, RocketLoadException { + RockSimLoader loader = new RockSimLoader(); + OpenRocketDocument doc = loadRockSimRocket(loader, "SubAssemblyTest.rkt"); + + Assert.assertNotNull(doc); + Rocket rocket = doc.getRocket(); + Assert.assertNotNull(rocket); + Assert.assertEquals("SubAssembly Test", doc.getRocket().getName()); + Assert.assertEquals(2, loader.getWarnings().size()); // can't add BodyTube to NoseCone, and can't add Transition to Transition + + InputStream stream = this.getClass().getResourceAsStream("SubAssemblyTest.rkt"); + Assert.assertNotNull("Could not open SubAssemblyTest.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(5, stage1.getChildCount()); + NoseCone noseCone1 = (NoseCone) stage1.getChild(0); + BodyTube bodyTube2 = (BodyTube) stage1.getChild(1); + Transition transition1 = (Transition) stage1.getChild(2); + Transition transition3 = (Transition) stage1.getChild(3); + BodyTube bodyTube3 = (BodyTube) stage1.getChild(4); + Assert.assertEquals("Nose cone 1", noseCone1.getName()); + Assert.assertEquals("Body tube 2", bodyTube2.getName()); + Assert.assertEquals("Transition 1", transition1.getName()); + Assert.assertEquals("Transition 3", transition3.getName()); + Assert.assertEquals("Body tube 3", bodyTube3.getName()); + + Assert.assertEquals(1, noseCone1.getChildCount()); + Assert.assertEquals("Mass object 1", noseCone1.getChild(0).getName()); + + Assert.assertEquals(12, bodyTube2.getChildCount()); + Assert.assertEquals("Mass object 2", bodyTube2.getChild(0).getName()); + Assert.assertEquals("Launch lug 1", bodyTube2.getChild(1).getName()); + Assert.assertEquals("Centering ring 1", bodyTube2.getChild(2).getName()); + Assert.assertEquals("Tube coupler 1", bodyTube2.getChild(3).getName()); + Assert.assertEquals("Fin set 1", bodyTube2.getChild(4).getName()); + Assert.assertEquals("Fin set 2", bodyTube2.getChild(5).getName()); + Assert.assertEquals("Parachute 1", bodyTube2.getChild(6).getName()); + Assert.assertEquals("Streamer 1", bodyTube2.getChild(7).getName()); + Assert.assertEquals("Bulkhead 1", bodyTube2.getChild(8).getName()); + Assert.assertEquals("Engine block 1", bodyTube2.getChild(9).getName()); + Assert.assertEquals("Tube fins 1", bodyTube2.getChild(10).getName()); + Assert.assertEquals("Sleeve 1", bodyTube2.getChild(11).getName()); + + Assert.assertEquals(3, transition1.getChildCount()); + Assert.assertEquals("Mass object 3", transition1.getChild(0).getName()); + Assert.assertEquals("Fin set 3", transition1.getChild(1).getName()); + Assert.assertEquals("Fin set 4", transition1.getChild(2).getName()); + + Assert.assertEquals(0, transition3.getChildCount()); + + Assert.assertEquals(0, bodyTube3.getChildCount()); } - public static OpenRocketDocument loadRockSimFinsOnTransitionsRocket(RockSimLoader theLoader) throws IOException, RocketLoadException { - try (InputStream stream = RockSimLoaderTest.class.getResourceAsStream("FinsOnTransitions.rkt")) { - Assert.assertNotNull("Could not open FinsOnTransitions.rkt", stream); + @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); OpenRocketDocument doc = OpenRocketDocumentFactory.createEmptyRocket(); DocumentLoadingContext context = new DocumentLoadingContext(); context.setOpenRocketDocument(doc); @@ -336,5 +485,4 @@ public class RockSimLoaderTest extends BaseTestCase { return doc; } } - } diff --git a/core/test/net/sf/openrocket/file/rocksim/importt/SubAssemblyTest.rkt b/core/test/net/sf/openrocket/file/rocksim/importt/SubAssemblyTest.rkt index 7bb84f148..06a226c9e 100644 --- a/core/test/net/sf/openrocket/file/rocksim/importt/SubAssemblyTest.rkt +++ b/core/test/net/sf/openrocket/file/rocksim/importt/SubAssemblyTest.rkt @@ -1,483 +1,1684 @@ - 4 - - - SubAssembly Element Test - 1 - 7 - 0 - 3 - 0 - 3 - 0.0 - 0.0 - 0 - 0 - 0 - 0 - 0 - 0 - 18 - 0.0 - 0.0 - 0.0 - 426.6301716552979 - 0.0 - 0.0 - 0.0 - 0.0 - 1 - 1 - 0 - - - 6.107306539734526 - 1049.21 - Polystyrene PS - Nose cone - 0.0 - 0 - 0.0 - 6.107306539734526 - 53.68748632541546 - 0 - 0.0 - 0.0 - 0 - 76.2 - 0 - 1 - 3 - 1 - 1.00076 - 0.0 - - 24.8006 - 19.1008 - 23.5991 - - - 15.040422946044567 - 1121.29 - Paper - Forward Body tube - 0.0 - 0 - 0.0 - 15.040422946044567 - 228.6 - 0 - 0.0 - 0.0 - 0 - 457.2 - 0 - 2 - 24.892 - 24.13 - 0 - 24.13 - 0.0 - 0 - - - 0.0 - 1121.29 - Paper - Tube coupler - 0.0 - 0 - 120.65 - 0.0 - 31.75 - 0 - 0.0 - 0.0 - 0 - 63.5 - 0 - 3 - 27.8892 - 27.8892 - 4 - 0 - - - 10.038912051168 - 0.00664972 - Mylar - Streamer - 0.0 - 0 - 44.45 - 10.038912051168 - 57.15 - 1 - 0.0 - 0.0 - 0 - 114.3 - 0 - 4 - 114.3 - 0.138 - - - 1.2996672000000002 - 0.0 - - Shock Cord - 187.325 - 1 - 187.325 - 0.0 - 0.0 - 0 - 0.0 - 0.0 - 0 - 12.192000000000002 - 0 - 5 - 0 - - - 2.549 - 0.0 - - Mass object - 2.549 g - 282.575 - 1 - 282.575 - 0.0 - 0.0 - 0 - 0.0 - 0.0 - 0 - 0.0 - 0 - 6 - 0 - - - 1.1277286611933457 - 1121.29 - Paper - Centering ring - 0.0 - 0 - 384.175 - 1.1277286611933457 - 3.175 - 0 - 0.0 - 0.0 - 0 - 6.35 - 0 - 7 - 28.702 - 24.9428 - 0 - 0 - - - 1.1277286611933457 - 1121.29 - Paper - Centering ring - 0.0 - 0 - 358.775 - 1.1277286611933457 - 3.175 - 0 - 0.0 - 0.0 - 0 - 6.35 - 0 - 8 - 28.702 - 24.9428 - 0 - 0 - - - 1.1277286611933457 - 1121.29 - Paper - Centering ring - 0.0 - 0 - 288.925 - 1.1277286611933457 - 3.175 - 0 - 0.0 - 0.0 - 0 - 6.35 - 0 - 9 - 28.702 - 24.9428 - 0 - 0 - - - - - 13.498613632777841 - 1121.29 - Paper - Aft Body tube - 0.0 - 0 - 0.0 - 13.498613632777841 - 165.1 - 0 - 0.0 - 0.0 - 0 - 330.2 - 0 - 10 - 29.8704 - 29.083 - 1 - 29.083 - 12.7 - 0 - - - 1.25084668869137 - 1121.29 - Paper - Engine block - 0.0 - 0 - 252.73000000000002 - 1.25084668869137 - 3.175 - 0 - 0.0 - 0.0 - 0 - 6.35 - 0 - 11 - 29.083 - 24.9428 - 2 - 0 - - - 0.9977479979838839 - 128.148 - Balsa - Fin set-1 - 0.0 - 0 - 257.175 - 0.9977479979838839 - 54.72939060773481 - 0 - 0.0 - 0.0 - 0 - 0.0 - 0 - 12 - 1 - 66.675 - 29.8704 - 50.8 - 67.4141 - 3.175 - 0 - 0 - 0.0 - 0.0 - 0.0 - 1 - 0.0 - - - 2.8874580315239995 - 128.148 - Balsa - Fin set - 0.0 - 0 - 146.05 - 2.8874580315239995 - 61.383333333333326 - 0 - 0.0 - 0.785398 - 0 - 0.0 - 0 - 13 - 4 - 101.6 - 0.0 - 34.925 - 82.55 - 3.175 - 0 - 0 - 0.0 - 0.0 - 0.0 - 1 - 0.0 - - - 0.9977479979838839 - 128.148 - Balsa - Fin set-2 - 0.0 - 0 - 257.175 - 0.9977479979838839 - 54.72939060773481 - 0 - 0.0 - 1.5708 - 0 - 0.0 - 0 - 14 - 1 - 66.675 - 29.8704 - 50.8 - 67.4141 - 3.175 - 0 - 0 - 0.0 - 0.0 - 0.0 - 1 - 0.0 - - - 0.9977479979838839 - 128.148 - Balsa - Fin set-3 - 0.0 - 0 - 257.175 - 0.9977479979838839 - 54.72939060773481 - 0 - 0.0 - 3.14159 - 0 - 0.0 - 0 - 15 - 1 - 66.675 - 29.8704 - 50.8 - 67.4141 - 3.175 - 0 - 0 - 0.0 - 0.0 - 0.0 - 1 - 0.0 - - - 0.9977479979838839 - 128.148 - Balsa - Fin set-4 - 0.0 - 0 - 257.175 - 0.9977479979838839 - 54.72939060773481 - 0 - 0.0 - -1.5708 - 0 - 0.0 - 0 - 16 - 1 - 66.675 - 29.8704 - 50.8 - 67.4141 - 3.175 - 0 - 0 - 0.0 - 0.0 - 0.0 - 1 - 0.0 - - - 1.1277286611933457 - 1121.29 - Paper - Centering ring - 0.0 - 0 - 323.85 - 1.1277286611933457 - 3.175 - 0 - 0.0 - 0.0 - 2 - 6.35 - 0 - 17 - 28.702 - 24.9428 - 0 - 0 - - - 1.1277286611933457 - 1121.29 - Paper - Centering ring - 0.0 - 0 - 282.575 - 1.1277286611933457 - 3.175 - 0 - 0.0 - 0.0 - 2 - 6.35 - 0 - 18 - 28.702 - 24.9428 - 0 - 0 - - - - - - - - - \ No newline at end of file +4 + + +SubAssembly 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 +48 +1 +0 +0,161.293,0,0 +0,33.4942,0,0 +0,172.472,0,0 +0,46.4108,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 +233.93 +78.74 +863.6 +863.6 +0. +863.6 +0,78.74,0,0 +0,863.6,0,0 + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + + +Apogee +23.5 +88.1015 +Flexible Urethane Foam - firm +Nose cone 1 +63.5 +1 +0. +9.28808 +39.6875 +0.00944361 +0.00944361 +0. +0 +14811 +56mm TARC Foam 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 +1 +1 +0 +0 +blue +2. +0.0211667 +2. +0.0211667 +1 +0 +8 +0 +0. +63.5 +56.31 +0 +3 +0 +0. +0. +0. +0. +0. +0. +0. + + +Custom +0. +0. +Custom +Subassembly 1 +0. +0 +0. +0. +0. +0. +0. +0. +0 +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 +7 +1 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +0. + + +Apogee +41.4 +0. +Mass object 1 +0. +1 +0. +0. +0. +0. +0. +0. +0 +29633 + +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 +0. +0. +0. +0. +1 +0 +8 +0 +0. +0 +0. + + + + +Apogee +0. +1121.29 +Paper +Body tube 1 +0. +0 +0. +80.3519 +431.8 +0.0833729 +0.0833729 +0. +0 +10251 + +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 +47 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +0. +30.73 +28.96 +863.6 +0 +0 +0. +0.5 +0. +0. +0 +0 + + + + + + + + +Apogee +0. +1121.29 +Paper +Body tube 2 +0. +0 +0. +11.621 +62.45 +0.012058 +0.012058 +0. +0 +10251 + +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 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +63.5 +30.73 +28.96 +124.9 +0 +0 +0. +0.5 +0. +0. +0 +0 + + +Custom +0. +0. +Custom +Subassembly 2 +0. +0 +0. +0. +0. +0. +0. +0. +0 +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 +0. +0. +0. +0. +1 +0 +8 +0 +63.5 + + +AeroPack +6.8 +0. +Aluminum +Mass object 2 +0. +1 +0. +0. +0. +0. +0. +0. +0 +24051 +24mm Aeropack Retainer - L +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 +18 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +63.5 +0 +0. + + + + +Public Missiles +0. +8553.86 +Brass +Launch lug 1 +0. +0 +0. +34.8781 +152.4 +0.0173643 +0.00912552 +0. +0 +LL-0.38 +3/8in Brass Launch Lug +20.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 +22 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +63.5 +9.53 +8.59 +304.8 +0 + + + + +Apogee +0. +400.462 +Cardstock +Centering ring 1 +0. +0 +0. +0.512713 +0.635 +0. +0. +0. +0 +13394 +CR 13-41.6 Cardstock +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 +24 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +63.5 +40.46 +13.87 +1.27 +0 +0 +0 + + + + +Apogee +63.786 +1121.29 +Paper +Tube coupler 1 +0. +1 +0. +2.40724 +31.75 +0. +0. +0. +0 +13010 +AC-29A +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 +27 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +63.5 +28.7 +27.94 +63.5 +0 +4 +0 + + + + +Apogee +0. +128.148 +Balsa +Fin set 1 +0. +0 +63.44 +2.55121 +27.6561 +0.00417366 +0.012521 +0. +0 +15645 +Avion Fins +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 +26 +0 +0 +0 +blue +5.24169 +0.144771 +7.498 +0.144771 +1 +0 +8 +0 +126.94 +3 +53.98 +19.05 +57.15 +57.172 +19.05 +3.18 +0 +0 +0 +0. +0. +0. +1 +0.320006 +0. +39.3842 +4.32897 +0.352908 +0. +0. + + + + +Public Missiles +0. +1905.24 +G10 fiberglass +Fin set 2 +0. +0 +63.44 +51.2497 +43.164 +0.0112786 +0.0338357 +0. +0 + +Fins +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 +rgb(126,150,121) +white +1 +29 +0 +0 +0 +rgb(61,177,187) +14.1955 +0.15664 +18.9793 +0.154953 +1 +0 +8 +0 +126.94 +3 +101.6 +8.21 +101.6 +102.231 +35.35 +1.59 +2 +0 +0 +0. +0. +0. +1 +0. +0. +51.7637 +10.9577 +0.0808071 +0. +0. +61.25 +8.20927 +101.6,0|76.2,61.46|25.4,101.6|0,0| +0,0,0,0,0,0,0 +10,10,10,10,10,10,10 +0,0,0,0,0,0,0 +0.5,10,0.5,0.5,0.00018939,0.001,1 +0.25,5,0.1,0.1,0.00018939,0.001,1 +0,0,0,0,0,0,0 +10,10,10,10,10,10,10 +0,0,0,0,0,0,0 +0.5,10,0.5,0.5,0.00018939,0.001,1 +0.25,5,0.1,0.1,0.00018939,0.001,1 + + + + +Apogee +7.5 +0. +Rip stop nylon +Parachute 1 +0. +1 +0. +0.75374 +31.75 +0. +0. +0. +0 +29091 + +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 +25 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +63.5 +381. +0. +6 +6 +0.76 +381. +1 +0.00032972 +Carpet String (Apogee 29500) +0.75 + + + + +Apogee +0. +1309. +Mylar +Streamer 1 +0. +0 +0. +1891.71 +50.8 +0. +0. +0. +0 +30305 +4in x 56in Mylar +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 +28 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +63.5 +1422.4 +101.6 +10. +1 +0.13 +0 +1 + + + + +Aerospace Speciality Products +0. +724.996 +Aircraft plywood (Birch) +Bulkhead 1 +0. +0 +0. +1.51385 +1.585 +0. +0. +0. +0 +PBH-70 +Plywood Bulkhead 70 (fits TC70 Coupler) +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 +30 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +63.5 +28.96 +0. +3.17 +0 +1 +1 + + + + +Apogee +1.8 +1121.29 +Paper +Engine block 1 +0. +1 +0. +1.12787 +3.175 +0. +0. +0. +0 +13035 +CR 24-29 ring +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 +32 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +63.5 +28.7 +24.94 +6.35 +0 +2 +0 + + + + +Custom +0. +1121.29 +Paper +Tube fins 1 +0. +0 +0. +5.17189 +38.1 +0.0264173 +0.0264173 +0. +0 +1 +Test tube fins save 1 +24.715 +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 +33 +0 +0 +0 +blue +4.7033 +0.637977 +1.08811 +0.071517 +1 +0 +8 +0 +63.5 +18.7 +18. +76.2 +0 +3 +0.775946 +8 + + + + +Apogee +5.4 +1121.29 +Paper +Sleeve 1 +0. +1 +0. +7.66959 +50.8 +0. +0. +0. +0 +10090 +AS-24 +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 +34 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +63.5 +26.8 +25.15 +101.6 +0 +3 +0 + + + + + + + + +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 +3 +1 +0 +0 +blue +1.83262 +0.230096 +1.83262 +0.230096 +1 +0 +8 +0 +188.4 +57.4 +78.74 +79.25 +0 +0. +0. +1 +3.18 +0. +0. +0. +0 +0. +292.389 +213.139 + + +Custom +0. +0. +Custom +Subassembly 3 +0. +0 +0. +0. +0. +0. +0. +0. +0 +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 +9 +1 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +188.4 + + +Apogee +8.5 +0. +Aluminum +Mass object 3 +0. +1 +0. +0. +0. +0. +0. +0. +0 +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 +39 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +188.4 +0 +0. + + + + +Aerospace Speciality Products +0. +1905.24 +G10 phenolic +Fin set 3 +0. +0 +0. +1.43908 +12.423 +0.00122818 +0.00368454 +0. +0 +FGST16 +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 +43 +0 +0 +0 +blue +1.98949 +0.195851 +3.35146 +0.195851 +1 +0 +8 +0 +188.4 +3 +25.4 +15.9 +31.8 +31.8 +4.76 +0.41 +0 +0 +0 +0. +0. +0. +1 +0.149994 +0. +43.3799 +1.93497 +0.625984 +0. +0. + + + + +Public Missiles +0. +1905.24 +G10 fiberglass +Fin set 4 +0. +0 +0. +64.1326 +118.675 +0.0140255 +0.0420765 +0. +0 +FIN-MBBX-LWR +Lower fins +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 +rgb(126,150,121) +white +1 +44 +0 +0 +0 +rgb(61,177,187) +9.81031 +0.275032 +14.3248 +0.278513 +1 +0 +8 +0 +188.4 +3 +146.05 +84.18 +69.84 +117.616 +125.57 +1.6 +2 +0 +0 +0. +0. +0. +1 +0. +0. +60.491 +8.27043 +0.576378 +0. +0. +118.44 +84.183 +146.05,0|165.1,9.525|200.025,69.84|120.65,69.633|0,0| +0,0,0,0,0,0,0 +10,10,10,10,10,10,10 +0,0,0,0,0,0,0 +0.5,10,0.5,0.5,0.00018939,0.001,1 +0.25,5,0.1,0.1,0.00018939,0.001,1 +0,0,0,0,0,0,0 +10,10,10,10,10,10,10 +0,0,0,0,0,0,0 +0.5,10,0.5,0.5,0.00018939,0.001,1 +0.25,5,0.1,0.1,0.00018939,0.001,1 + + + + +Apogee +0. +1049.21 +Polystyrene PS +Transition 2 +0. +0 +0. +13.106 +26.1291 +0.00980779 +0.00980779 +0. +0 +17081 +BT-70/BT-80 Blow Mold Transition +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 +48 +0 +0 +0 +blue +0.772815 +0.2138 +0.772815 +0.2138 +1 +0 +8 +0 +188.4 +56. +66.04 +50.8 +0 +0. +0. +1 +1.3 +0. +0. +0. +2 +0. +180.826 +130.026 + + + + + + + + +Custom +0. +0. +Custom +Subassembly 4 +0. +0 +0. +0. +0. +0. +0. +0. +0 +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 +0. +0. +0. +0. +1 +0 +8 +0 +267.65 + + +LOC Precision +0.238 +1049.21 +Polystyrene PS +Transition 3 +82.5 +0 +0. +190.756 +97.0467 +0.0593746 +0.0593746 +0. +0 +PTC-3.90 +Tail 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 +5 +0 +0 +0 +blue +-3.4363 +0.400114 +-3.4363 +0.400114 +1 +0 +8 +0 +267.65 +102. +70.4 +206. +0 +0. +0. +1 +3.17 +0. +0. +0. +1 +0. +367.667 +161.667 + + + + +Apogee +0. +1199.78 +Polycarbonate +Body tube 3 +0. +0 +0. +5.35012 +76.2 +0.0119168 +0.0119168 +0. +0 +10102 + +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 +6 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +473.65 +24.89 +24.13 +152.4 +0 +0 +0. +0.5 +0. +0. +0 +0 + + + + + + + + + + + + + + + + + + + + + diff --git a/swing/resources/datafiles/examples/TARC Payloader.ork b/swing/resources/datafiles/examples/TARC Payloader.ork index a62d4a8a1..0482ad09a 100644 Binary files a/swing/resources/datafiles/examples/TARC Payloader.ork and b/swing/resources/datafiles/examples/TARC Payloader.ork differ diff --git a/swing/src/net/sf/openrocket/gui/adaptors/IntegerModel.java b/swing/src/net/sf/openrocket/gui/adaptors/IntegerModel.java index 4703642d3..6a32355f9 100644 --- a/swing/src/net/sf/openrocket/gui/adaptors/IntegerModel.java +++ b/swing/src/net/sf/openrocket/gui/adaptors/IntegerModel.java @@ -13,6 +13,7 @@ import javax.swing.SpinnerNumberModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import net.sf.openrocket.util.MathUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -210,9 +211,16 @@ public class IntegerModel implements StateChangeListener { * Sets the value of the variable. */ public void setValue(int v) { + int clampedValue = MathUtil.clamp(v, minValue, maxValue); + if (clampedValue != v) { + log.debug("Clamped value " + v + " to " + clampedValue + " for " + this); + v = clampedValue; + } + log.debug("Setting value " + v + " for " + this); try { setMethod.invoke(source, v); + fireStateChanged(); } catch (IllegalArgumentException e) { throw new BugException(e); } catch (IllegalAccessException e) { diff --git a/swing/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java index 59ce8c45a..c963ae877 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; @@ -218,7 +219,7 @@ public class GeneralOptimizationDialog extends JDialog { selectedModifierTable.setDefaultRenderer(Double.class, new DoubleCellRenderer()); selectedModifierTable.setRowSelectionAllowed(true); selectedModifierTable.setColumnSelectionAllowed(false); - selectedModifierTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + selectedModifierTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); // Make sure spinner editor fits into the cell height selectedModifierTable.setRowHeight(new JSpinner().getPreferredSize().height - 4); @@ -264,9 +265,9 @@ public class GeneralOptimizationDialog extends JDialog { addButton = new SelectColorButton(Chars.LEFT_ARROW + " " + trans.get("btn.add") + " "); addButton.setToolTipText(trans.get("btn.add.ttip")); addButton.addActionListener(e -> { - SimulationModifier mod = getSelectedAvailableModifier(); - if (mod != null) { - addModifier(mod); + List mods = getSelectedAvailableModifiers(); + if (mods.size() > 0) { + addModifiers(mods); clearHistory(); } else { log.error("Attempting to add simulation modifier when none is selected"); @@ -281,8 +282,8 @@ public class GeneralOptimizationDialog extends JDialog { removeButton = new SelectColorButton(" " + trans.get("btn.delete") + " " + Chars.RIGHT_ARROW); removeButton.setToolTipText(trans.get("btn.delete.ttip")); removeButton.addActionListener(e -> { - SimulationModifier mod = getSelectedModifier(); - if (mod == null) { + List mods = getSelectedModifiers(); + if (mods.size() == 0) { log.error("Attempting to remove simulation modifier when none is selected"); return; } @@ -291,7 +292,7 @@ public class GeneralOptimizationDialog extends JDialog { selectedModifierTable.getCellEditor().stopCellEditing(); } - removeModifier(mod); + removeModifiers(mods); clearHistory(); }); disableComponents.add(removeButton); @@ -328,9 +329,9 @@ public class GeneralOptimizationDialog extends JDialog { @Override public void mousePressed(MouseEvent e) { if (e.getClickCount() == 2) { - SimulationModifier mod = getSelectedAvailableModifier(); - if (mod != null) { - addModifier(mod); + List mods = getSelectedAvailableModifiers(); + if (mods.size() == 1) { + addModifiers(mods); clearHistory(); } else { log.info(Markers.USER_MARKER, "Double-clicked non-available option"); @@ -1027,20 +1028,30 @@ public class GeneralOptimizationDialog extends JDialog { } - private void addModifier(SimulationModifier mod) { - if (!selectedModifiers.contains(mod)) { + private void addModifiers(List mods) { + if (mods == null || mods.size() == 0) { + return; + } + for (SimulationModifier mod : mods) { + if (selectedModifiers.contains(mod)) { + log.info(Markers.USER_MARKER, "Attempting to add an already existing simulation modifier " + mod); + continue; + } log.info(Markers.USER_MARKER, "Adding simulation modifier " + mod); selectedModifiers.add(mod); - selectedModifierTableModel.fireTableDataChanged(); - availableModifierTree.repaint(); - } else { - log.info(Markers.USER_MARKER, "Attempting to add an already existing simulation modifier " + mod); } + selectedModifierTableModel.fireTableDataChanged(); + availableModifierTree.repaint(); } - private void removeModifier(SimulationModifier mod) { - log.info(Markers.USER_MARKER, "Removing simulation modifier " + mod); - selectedModifiers.remove(mod); + private void removeModifiers(List mods) { + if (mods == null || mods.size() == 0) { + return; + } + log.info(Markers.USER_MARKER, "Removing simulation modifiers " + mods); + for (SimulationModifier mod : mods) { + selectedModifiers.remove(mod); + } selectedModifierTableModel.fireTableDataChanged(); availableModifierTree.repaint(); } @@ -1069,8 +1080,8 @@ public class GeneralOptimizationDialog extends JDialog { } // "Add" button - SimulationModifier mod = getSelectedAvailableModifier(); - state = (mod != null && !selectedModifiers.contains(mod)); + List mods = getSelectedAvailableModifiers(); + state = (mods.size() > 0 && !new HashSet<>(selectedModifiers).containsAll(mods)); log.debug("addButton enabled: " + state); addButton.setEnabled(state); @@ -1122,9 +1133,9 @@ public class GeneralOptimizationDialog extends JDialog { } // Update description text - mod = getSelectedModifier(); - if (mod != null) { - selectedModifierDescription.setText(mod.getDescription()); + List selectedMods = getSelectedModifiers(); + if (selectedMods.size() == 1) { + selectedModifierDescription.setText(selectedMods.get(0).getDescription()); } else { selectedModifierDescription.setText(""); } @@ -1221,18 +1232,20 @@ public class GeneralOptimizationDialog extends JDialog { } /** - * Return the currently selected available simulation modifier from the modifier tree, - * or null if none selected. + * Return the currently selected available simulation modifier from the modifier tree. */ - private SimulationModifier getSelectedAvailableModifier() { - TreePath treepath = availableModifierTree.getSelectionPath(); - if (treepath != null) { - Object o = ((DefaultMutableTreeNode) treepath.getLastPathComponent()).getUserObject(); - if (o instanceof SimulationModifier) { - return (SimulationModifier) o; + private List getSelectedAvailableModifiers() { + List result = new ArrayList<>(); + TreePath[] treepaths = availableModifierTree.getSelectionPaths(); + if (treepaths != null) { + for (TreePath treepath : treepaths) { + Object obj = ((DefaultMutableTreeNode) treepath.getLastPathComponent()).getUserObject(); + if (obj instanceof SimulationModifier) { + result.add((SimulationModifier) obj); + } } } - return null; + return result; } /** @@ -1257,17 +1270,17 @@ public class GeneralOptimizationDialog extends JDialog { } /** - * Return the currently selected simulation modifier from the table, - * or null if none selected. - * @return the selected modifier or null. + * Return the currently selected simulation modifiers from the table. + * @return the selected modifier. */ - private SimulationModifier getSelectedModifier() { - int row = selectedModifierTable.getSelectedRow(); - if (row < 0) { - return null; + private List getSelectedModifiers() { + List result = new ArrayList<>(); + int[] rows = selectedModifierTable.getSelectedRows(); + for (int row : rows) { + int idx = selectedModifierTable.convertRowIndexToModel(row); + result.add(selectedModifiers.get(idx)); } - row = selectedModifierTable.convertRowIndexToModel(row); - return selectedModifiers.get(row); + return result; } /** diff --git a/swing/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java b/swing/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java index 0fb5106ad..38769db88 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java @@ -321,6 +321,8 @@ public class RocketFigure3d extends JPanel implements GLEventListener { gl.glEnable(GL.GL_MULTISAMPLE); gl.glEnable(GLLightingFunc.GL_LIGHTING); + + updateFigure(); } rr.render(drawable, configuration, selection); diff --git a/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java b/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java index 2accd4702..bda631bc3 100644 --- a/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java +++ b/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java @@ -609,7 +609,11 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change List selectedComponents = Arrays.stream(selectionModel.getSelectionPaths()) .map(c -> (RocketComponent) c.getLastPathComponent()).collect(Collectors.toList()); - if (clicked == null || clicked.length == 0) return; + if (clicked == null || clicked.length == 0) { + selectionModel.setSelectionPaths(null); + ComponentConfigDialog.disposeDialog(); + return; + } // Check for double-click. // If the shift/meta key is not pressed and the component was not already selected, ignore the double click and treat it as a single click