]> git.gag.com Git - debian/openrocket/commitdiff
DGP - First pass at Rocksim export
authorrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Sun, 8 Jan 2012 01:43:37 +0000 (01:43 +0000)
committerrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Sun, 8 Jan 2012 01:43:37 +0000 (01:43 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@280 180e2498-e6e9-4542-8430-84ac67f01cd8

101 files changed:
src/net/sf/openrocket/file/GeneralRocketLoader.java
src/net/sf/openrocket/file/rocksim/AttachedPartsHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/BaseHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/BodyTubeHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/FinSetHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/InnerBodyTubeHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/LaunchLugHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/MassObjectHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/NoseConeHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/ParachuteHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/PositionDependentHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/RecoveryDeviceHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/RingHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/RocksimDensityType.java [deleted file]
src/net/sf/openrocket/file/rocksim/RocksimFinishCode.java [deleted file]
src/net/sf/openrocket/file/rocksim/RocksimHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/RocksimLoader.java [deleted file]
src/net/sf/openrocket/file/rocksim/RocksimLocationMode.java [deleted file]
src/net/sf/openrocket/file/rocksim/RocksimNoseConeCode.java [deleted file]
src/net/sf/openrocket/file/rocksim/StreamerHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/TipShapeCode.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/TransitionHandler.java [deleted file]
src/net/sf/openrocket/file/rocksim/export/AbstractTransitionDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/BasePartDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/BodyTubeDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/BulkheadDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/CenteringRingDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/CustomFinSetDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/EngineBlockDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/FinSetDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/InnerBodyTubeDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/LaunchLugDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/MassObjectDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/NoseConeDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/ParachuteDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/RocketDesignDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/RocksimDesignDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/RocksimDocumentDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/RocksimSaver.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/StageDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/StreamerDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/TransitionDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/export/TubeCouplerDTO.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/AttachedPartsHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/BodyTubeHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/FinSetHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/InnerBodyTubeHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/LaunchLugHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/MassObjectHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/NoseConeHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/ParachuteHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/PositionDependentHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/RecoveryDeviceHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/RingHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/RocksimDensityType.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/RocksimFinishCode.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/RocksimHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/RocksimLoader.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/RocksimLocationMode.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/RocksimNoseConeCode.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/StreamerHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/importt/TransitionHandler.java [new file with mode: 0644]
src/net/sf/openrocket/gui/main/BasicFrame.java
src/net/sf/openrocket/rocketcomponent/TrapezoidFinSet.java
src/net/sf/openrocket/utils/RocksimConverter.java
test/net/sf/openrocket/file/rocksim/BodyTubeHandlerTest.java [deleted file]
test/net/sf/openrocket/file/rocksim/FinSetHandlerTest.java [deleted file]
test/net/sf/openrocket/file/rocksim/InnerBodyTubeHandlerTest.java [deleted file]
test/net/sf/openrocket/file/rocksim/LaunchLugHandlerTest.java [deleted file]
test/net/sf/openrocket/file/rocksim/MassObjectHandlerTest.java [deleted file]
test/net/sf/openrocket/file/rocksim/NoseConeHandlerTest.java [deleted file]
test/net/sf/openrocket/file/rocksim/ParachuteHandlerTest.java [deleted file]
test/net/sf/openrocket/file/rocksim/PodFins.rkt [deleted file]
test/net/sf/openrocket/file/rocksim/RingHandlerTest.java [deleted file]
test/net/sf/openrocket/file/rocksim/RocksimContentHandlerTest.java [deleted file]
test/net/sf/openrocket/file/rocksim/RocksimLoaderTest.java [deleted file]
test/net/sf/openrocket/file/rocksim/RocksimTestBase.java [deleted file]
test/net/sf/openrocket/file/rocksim/StreamerHandlerTest.java [deleted file]
test/net/sf/openrocket/file/rocksim/TransitionHandlerTest.java [deleted file]
test/net/sf/openrocket/file/rocksim/export/RocksimDocumentDTOTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/BodyTubeHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/FinSetHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/InnerBodyTubeHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/LaunchLugHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/MassObjectHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/NoseConeHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/ParachuteHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/PodFins.rkt [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/RingHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/RocksimContentHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/RocksimLoaderTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/RocksimTestBase.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/StreamerHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/TransitionHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/rocksimTestRocket1.rkt [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/rocksimTestRocket2.rkt [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/importt/rocksimTestRocket3.rkt [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/rocksimTestRocket1.rkt [deleted file]
test/net/sf/openrocket/file/rocksim/rocksimTestRocket2.rkt [deleted file]
test/net/sf/openrocket/file/rocksim/rocksimTestRocket3.rkt [deleted file]

index c2246a4d3a61e195b31d627f924031a82dbc3173..b6117f787e56409914747ef79730f8b242747063 100644 (file)
@@ -1,15 +1,14 @@
 package net.sf.openrocket.file;
 
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.file.openrocket.OpenRocketLoader;
+
 import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.Charset;
-import java.util.zip.GZIPInputStream;
 import java.util.Arrays;
-
-import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.file.openrocket.OpenRocketLoader;
-import net.sf.openrocket.file.rocksim.RocksimLoader;
+import java.util.zip.GZIPInputStream;
 
 
 /**
@@ -31,7 +30,7 @@ public class GeneralRocketLoader extends RocketLoader {
        
        private final OpenRocketLoader openRocketLoader = new OpenRocketLoader();
     
-    private final RocksimLoader rocksimLoader = new RocksimLoader();
+    private final net.sf.openrocket.file.rocksim.importt.RocksimLoader rocksimLoader = new net.sf.openrocket.file.rocksim.importt.RocksimLoader();
        
        @Override
        protected OpenRocketDocument loadFromStream(InputStream source) throws IOException,
diff --git a/src/net/sf/openrocket/file/rocksim/AttachedPartsHandler.java b/src/net/sf/openrocket/file/rocksim/AttachedPartsHandler.java
deleted file mode 100644 (file)
index 2ced5a7..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * AttachedPartsHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.file.simplesax.ElementHandler;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-
-import java.util.HashMap;
-
-/**
- * A SAX handler for the Rocksim AttachedParts XML type.  
- */
-class AttachedPartsHandler extends ElementHandler {
-    /** The parent component. */
-    private final RocketComponent component;
-
-    /**
-     * Constructor.
-     * 
-     * @param c  the parent
-     * 
-     * @throws IllegalArgumentException   thrown if <code>c</code> is null
-     */
-    public AttachedPartsHandler(RocketComponent c) throws IllegalArgumentException {
-        if (c == null) {
-            throw new IllegalArgumentException("The parent component of any attached part may not be null.");
-        }
-        component = c;
-    }
-
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
-        if ("FinSet".equals(element)) {
-            return new FinSetHandler(component);
-        }
-        if ("CustomFinSet".equals(element)) {
-            return new FinSetHandler(component);
-        }
-        if ("LaunchLug".equals(element)) {
-            return new LaunchLugHandler(component, warnings);
-        }
-        if ("Parachute".equals(element)) {
-            return new ParachuteHandler(component, warnings);
-        }
-        if ("Streamer".equals(element)) {
-            return new StreamerHandler(component, warnings);
-        }
-        if ("MassObject".equals(element)) {
-            return new MassObjectHandler(component, warnings);
-        }
-        if ("Ring".equals(element)) {
-            return new RingHandler(component, warnings);
-        }
-        if ("BodyTube".equals(element)) {
-            return new InnerBodyTubeHandler(component, warnings);
-        }
-        if ("Transition".equals(element)) {
-            return new TransitionHandler(component, warnings);
-        }
-        if ("TubeFinSet".equals(element)) {
-            warnings.add("Tube fins are not currently supported. Ignoring.");
-        }
-        if ("RingTail".equals(element)) {
-            warnings.add("Ring tails are not currently supported. Ignoring.");
-        }
-        if ("ExternalPod".equals(element)) {
-            warnings.add("Pods are not currently supported. Ignoring.");
-        }
-        return null;
-    }
-}
-
diff --git a/src/net/sf/openrocket/file/rocksim/BaseHandler.java b/src/net/sf/openrocket/file/rocksim/BaseHandler.java
deleted file mode 100644 (file)
index 0f648eb..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * BaseHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.file.simplesax.ElementHandler;
-import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.xml.sax.SAXException;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-
-/**
- * An abstract base class that handles common parsing.  All Rocksim component handlers are subclassed from here.
- *
- * @param <C>   the specific RocketComponent subtype for which the concrete handler can create
- */
-public abstract class BaseHandler<C extends RocketComponent> extends ElementHandler {
-
-    /**
-     * The overridden mass.
-     */
-    private Double mass = 0d;
-    /**
-     * The overridden Cg.
-     */
-    private Double cg = 0d;
-    /**
-     * The density of the material in the component.
-     */
-    private Double density = 0d;
-    /**
-     * The internal Rocksim density type.
-     */
-    private RocksimDensityType densityType = RocksimDensityType.ROCKSIM_BULK;
-
-    /**
-     * The material name.
-     */
-    private String materialName = "";
-
-    /**
-     * The SAX method called when the closing element tag is reached.
-     *
-     * @param element        the element name.
-     * @param attributes    attributes of the element.
-     * @param content        the textual content of the element.
-     * @param warnings        the warning set to store warnings in.
-     * @throws SAXException
-     */
-
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        final C component = getComponent();
-        try {
-            if ("Name".equals(element)) {
-                component.setName(content);
-            }
-            if ("KnownMass".equals(element)) {
-                mass = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
-            }
-            if ("Density".equals(element)) {
-                density = Math.max(0d, Double.parseDouble(content) );
-            }
-            if ("KnownCG".equals(element)) {
-                cg = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
-            }
-            if ("UseKnownCG".equals(element)) {  //Rocksim sets UseKnownCG to true to control the override of both cg and mass
-                boolean override = "1".equals(content);
-                setOverride(component, override, mass, cg);
-            }
-            if ("DensityType".equals(element)) {
-                densityType = RocksimDensityType.fromCode(Integer.parseInt(content));
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        /* Because of the order of XML elements in Rocksim, not all information is known at the time it really needs
-           to be acted upon.  So we keep temporary instance variables to be used here at the end of the parsing.
-         */
-        density = computeDensity(densityType, density);
-        RocketComponent component = getComponent();
-        updateComponentMaterial(component, materialName, getMaterialType(), density);
-    }
-
-    /**
-     * Compute the density.  Rocksim does strange things with densities.  For some streamer material it's in cubic,
-     * rather than square, units.  In those cases it needs to be converted to an appropriate SURFACE material density.
-     * Some G10 fiberglass materials are in cubic units, other G10 fiberglass is in square units.  And due to a
-     * Rocksim bug, some densities are 0 when they clearly should not be.
-     *
-     * This may be overridden for specific component density computations.
-     *
-     * @param type       the rocksim density
-     * @param rawDensity the density as specified in the Rocksim design file
-     * @return a value in OpenRocket SURFACE density units
-     */
-    protected double computeDensity(RocksimDensityType type, double rawDensity) {
-        return rawDensity / type.asOpenRocket();
-    }
-
-    /**
-     * If the Rocksim component does not override the mass, then create a Material based upon the density defined
-     * for that component.  This *should* result in a consistent representation of Cg between Rocksim and OpenRocket.
-     *
-     * @param component       the component
-     * @param type            the type of the material
-     * @param density         the density in g/cm^3
-     * @param definedMaterial the material that is currently defined on the component; used only to get the name
-     *                        as it appears in Rocksim
-     */
-    public static void updateComponentMaterial(RocketComponent component, String definedMaterial, Material.Type type,
-                                               double density) {
-        if (definedMaterial != null) {
-            Material custom = createCustomMaterial(type, definedMaterial, density);
-            setMaterial(component, custom);
-        }
-    }
-
-    /**
-     * Override the mass and Cg of the component.
-     *
-     * @param component  the component
-     * @param override   true if any override should happen
-     * @param mass       the override mass
-     * @param cg         the override cg
-     */
-    public static void setOverride(RocketComponent component, boolean override, double mass, double cg) {
-        if (override) {
-            component.setCGOverridden(override);
-            component.setMassOverridden(override);
-            component.setOverrideSubcomponents(false); //Rocksim does not support this type of override
-            component.setOverrideMass(mass);
-            component.setOverrideCGX(cg);
-        }
-    }
-
-    /**
-     * Get the component this handler is working upon.
-     *
-     * @return a component
-     */
-    protected abstract C getComponent();
-
-    /**
-     * Get the required type of material for this component.
-     *
-     * @return the required material type
-     */
-    protected abstract Material.Type getMaterialType();
-
-    /**
-     * Some CG positions in Rocksim do not correspond to the CG position reference in OpenRocket.
-     *
-     * @param theCG  the CG value to really use when overriding CG on the OpenRocket component
-     */
-    protected void setCG(double theCG) {
-        cg = theCG;
-    }
-
-    /**
-     * Set the material name as specified in the Rocksim design file.
-     *
-     * @param content  the material name
-     */
-    protected void setMaterialName(String content) {
-        materialName = content;
-    }
-
-    /**
-     * Add child to parent only if the child is compatible.  Otherwise add to warning set.
-     * 
-     * @param parent  the parent component
-     * @param child   the child component
-     * @param warnings the warning set
-     * 
-     * @return true if the child is compatible with parent
-     */
-    protected static boolean isCompatible(RocketComponent parent, Class<? extends RocketComponent> child, WarningSet warnings) {
-        if (!parent.isCompatible(child)) {
-            warnings.add(child.getName() + " can not be attached to "
-                         + parent.getComponentName() + ", ignoring component.");
-            return false;
-        }
-        else {
-            return true;
-        }
-    }
-    
-    /**
-     * Create a custom material based on the density.  The name of the material is prepended with 'RS: ' to
-     * indicate it came from a RockSim material.
-     *
-     * @param type    the type of the material
-     * @param name    the name of the component
-     * @param density the density
-     *
-     * @return a Material instance
-     */
-    public static Material createCustomMaterial(Material.Type type, String name, double density) {
-        return Material.newMaterial(type, "RS: " + name, density, true);
-    }
-
-    /**
-     * Set the material onto an instance of RocketComponent.  This is done because only some subtypes of RocketComponent
-     * have the setMaterial method.  Unfortunately the supertype cannot be used.
-     *
-     * @param component  the component who's material is to be set
-     * @param material the material to be set on the component (defined by getComponent())
-     */
-    private static void setMaterial(RocketComponent component, Material material) {
-        try {
-            final Method method = getMethod(component, "setMaterial", new Class[]{Material.class});
-            if (method != null) {
-                method.invoke(component, material);
-            }
-        }
-        catch (IllegalAccessException ignored) {
-        }
-        catch (InvocationTargetException ignored) {
-        }
-    }
-
-    /**
-     * Find a method by name and argument list.
-     *
-     * @param component  the component who's material is to be seta
-     * @param name the method name
-     * @param args the class types of the parameters
-     *
-     * @return the Method instance, or null
-     */
-    private static Method getMethod(RocketComponent component, String name, Class[] args) {
-        Method method = null;
-        try {
-            method = component.getClass().getMethod(name, args);
-        }
-        catch (NoSuchMethodException ignored) {
-        }
-        return method;
-    }
-
-}
diff --git a/src/net/sf/openrocket/file/rocksim/BodyTubeHandler.java b/src/net/sf/openrocket/file/rocksim/BodyTubeHandler.java
deleted file mode 100644 (file)
index f8bc483..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * BodyTubeHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-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.BodyTube;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.xml.sax.SAXException;
-
-import java.util.HashMap;
-
-/**
- * A SAX handler for Rocksim Body Tubes.
- */
-class BodyTubeHandler extends BaseHandler<BodyTube> {
-    /**
-     * The OpenRocket BodyTube.
-     */
-    private final BodyTube bodyTube;
-
-    /**
-     * Constructor.
-     *
-     * @param c parent component
-     * @param warnings  the warning set
-     * @throws IllegalArgumentException thrown if <code>c</code> is null
-     */
-    public BodyTubeHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
-        if (c == null) {
-            throw new IllegalArgumentException("The parent component of a body tube may not be null.");
-        }
-        bodyTube = new BodyTube();
-        if (isCompatible(c, BodyTube.class, warnings)) {
-            c.addChild(bodyTube);
-        }
-    }
-
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
-        if ("AttachedParts".equals(element)) {
-            return new AttachedPartsHandler(bodyTube);
-        }
-        return PlainTextHandler.INSTANCE;
-    }
-
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        super.closeElement(element, attributes, content, warnings);
-
-        try {
-            if ("OD".equals(element)) {
-                bodyTube.setOuterRadius(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
-            }
-            if ("ID".equals(element)) {
-                final double r = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS;
-                bodyTube.setInnerRadius(r);
-            }
-            if ("Len".equals(element)) {
-                bodyTube.setLength(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
-            }
-            if ("FinishCode".equals(element)) {
-                bodyTube.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket());
-            }
-            if ("IsMotorMount".equals(element)) {
-                bodyTube.setMotorMount("1".equals(content));
-            }
-            if ("EngineOverhang".equals(element)) {
-                bodyTube.setMotorOverhang(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
-            }
-            if ("Material".equals(element)) {
-                setMaterialName(content);
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    /**
-     * Get the component this handler is working upon.
-     * 
-     * @return a component
-     */
-    @Override
-    public BodyTube getComponent() {
-        return bodyTube;
-    }
-
-    /**
-     * Get the required type of material for this component.
-     *
-     * @return BULK
-     */
-    public Material.Type getMaterialType() {
-        return Material.Type.BULK;
-    }
-}
-
diff --git a/src/net/sf/openrocket/file/rocksim/FinSetHandler.java b/src/net/sf/openrocket/file/rocksim/FinSetHandler.java
deleted file mode 100644 (file)
index 08c9177..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * FinSetHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-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.EllipticalFinSet;
-import net.sf.openrocket.rocketcomponent.ExternalComponent;
-import net.sf.openrocket.rocketcomponent.FinSet;
-import net.sf.openrocket.rocketcomponent.FreeformFinSet;
-import net.sf.openrocket.rocketcomponent.IllegalFinPointException;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
-import net.sf.openrocket.util.Coordinate;
-import org.xml.sax.SAXException;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * A SAX handler for Rocksim fin sets.  Because the type of fin may not be known first (in Rocksim file format, the fin
- * shape type is in the middle of the XML structure), and because we're using SAX not DOM, all of the fin
- * characteristics are kept here until the closing FinSet tag. At that point, <code>asOpenRocket</code> method is called
- * to construct the corresponding OpenRocket FinSet.
- */
-class FinSetHandler extends ElementHandler {
-    /**
-     * The parent component.
-     */
-    private final RocketComponent component;
-
-    /**
-     * The name of the fin.
-     */
-    private String name;
-    /**
-     * The Rocksim fin shape code.
-     */
-    private int shapeCode;
-    /**
-     * The location of the fin on its parent.
-     */
-    private double location = 0.0d;
-    /**
-     * The OpenRocket Position which gives the absolute/relative positioning for location.
-     */
-    private RocketComponent.Position position;
-    /**
-     * The number of fins in this fin set.
-     */
-    private int finCount;
-    /**
-     * The length of the root chord.
-     */
-    private double rootChord = 0.0d;
-    /**
-     * The length of the tip chord.
-     */
-    private double tipChord = 0.0d;
-    /**
-     * The length of the mid-chord (aka height).
-     */
-    private double midChordLen = 0.0d;
-    /**
-     * The distance of the leading edge from root to top.
-     */
-    private double sweepDistance = 0.0d;
-    /**
-     * The angle the fins have been rotated from the y-axis, if looking down the tube, in radians.
-     */
-    private double radialAngle = 0.0d;
-    /**
-     * The thickness of the fins.
-     */
-    private double thickness;
-    /**
-     * The finish of the fins.
-     */
-    private ExternalComponent.Finish finish;
-    /**
-     * The shape of the tip.
-     */
-    private int tipShapeCode;
-    /**
-     * The length of the TTW tab.
-     */
-    private double tabLength = 0.0d;
-    /**
-     * The depth of the TTW tab.
-     */
-    private double tabDepth = 0.0d;
-    /**
-     * The offset of the tab, from the front of the fin.
-     */
-    private double taboffset = 0.0d;
-    /**
-     * The elliptical semi-span (height).
-     */
-    private double semiSpan;
-    /**
-     * The list of custom points.
-     */
-    private String pointList;
-    /**
-     * Override the Cg and mass.
-     */
-    private boolean override = false;
-    /**
-     * The overridden mass.
-     */
-    private Double mass = 0d;
-    /**
-     * The overridden Cg.
-     */
-    private Double cg = 0d;
-    /**
-     * The density of the material in the component.
-     */
-    private Double density = 0d;
-    /**
-     * The material name.
-     */
-    private String materialName = "";
-    /**
-     * The Rocksim calculated mass.
-     */
-    private Double calcMass = 0d;
-    /**
-     * The Rocksim calculated cg.
-     */
-    private Double calcCg = 0d;
-
-
-    /**
-     * Constructor.
-     *
-     * @param c the parent
-     *
-     * @throws IllegalArgumentException thrown if <code>c</code> is null
-     */
-    public FinSetHandler (RocketComponent c) throws IllegalArgumentException {
-        if (c == null) {
-            throw new IllegalArgumentException("The parent component of a fin set may not be null.");
-        }
-        component = c;
-    }
-
-    @Override
-    public ElementHandler openElement (String element, HashMap<String, String> attributes, WarningSet warnings) {
-        return PlainTextHandler.INSTANCE;
-    }
-
-    @Override
-    public void closeElement (String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        try {
-            if ("Name".equals(element)) {
-                name = content;
-            }
-            if ("Material".equals(element)) {
-                materialName = content;
-            }
-            if ("FinishCode".equals(element)) {
-                finish = RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket();
-            }
-            if ("Xb".equals(element)) {
-                location = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("LocationMode".equals(element)) {
-                position = RocksimLocationMode.fromCode(Integer.parseInt(content)).asOpenRocket();
-            }
-            if ("FinCount".equals(element)) {
-                finCount = Integer.parseInt(content);
-            }
-            if ("RootChord".equals(element)) {
-                rootChord = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("TipChord".equals(element)) {
-                tipChord = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("SemiSpan".equals(element)) {
-                semiSpan = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("MidChordLen".equals(element)) {
-                midChordLen = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("SweepDistance".equals(element)) {
-                sweepDistance = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("Thickness".equals(element)) {
-                thickness = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("TipShapeCode".equals(element)) {
-                tipShapeCode = Integer.parseInt(content);
-            }
-            if ("TabLength".equals(element)) {
-                tabLength = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("TabDepth".equals(element)) {
-                tabDepth = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("TabOffset".equals(element)) {
-                taboffset = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("RadialAngle".equals(element)) {
-                radialAngle = Double.parseDouble(content);
-            }
-            if ("ShapeCode".equals(element)) {
-                shapeCode = Integer.parseInt(content);
-            }
-            if ("PointList".equals(element)) {
-                pointList = content;
-            }
-            if ("KnownMass".equals(element)) {
-                mass = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
-            }
-            if ("Density".equals(element)) {
-                density = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_BULK_DENSITY);
-            }
-            if ("KnownCG".equals(element)) {
-                cg = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
-            }
-            if ("UseKnownCG".equals(element)) {
-                override = "1".equals(content);
-            }
-            if ("CalcMass".equals(element)) {
-                calcMass = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS;
-            }
-            if ("CalcCg".equals(element)) {
-                calcCg = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    @Override
-    public void endHandler (String element, HashMap<String, String> attributes,
-            String content, WarningSet warnings) throws SAXException {
-        //Create the fin set and correct for overrides and actual material densities
-        final FinSet finSet = asOpenRocket(warnings);
-        if (component.isCompatible(finSet)) {
-            BaseHandler.setOverride(finSet, override, mass, cg);
-            if (!override && finSet.getCrossSection().equals(FinSet.CrossSection.AIRFOIL)) {
-                //Override mass anyway.  This is done only for AIRFOIL because Rocksim does not compute different
-                //mass/cg for different cross sections, but OpenRocket does.  This can lead to drastic differences
-                //in mass.  To counteract that, the cross section value is retained but the mass/cg is overridden
-                //with the calculated values from Rocksim.  This will best approximate the Rocksim design in OpenRocket.
-                BaseHandler.setOverride(finSet, true, calcMass, calcCg);
-            }
-            BaseHandler.updateComponentMaterial(finSet, materialName, Material.Type.BULK, density);
-            component.addChild(finSet);
-        }
-        else {
-            warnings.add(finSet.getComponentName() + " can not be attached to "
-                         + component.getComponentName() + ", ignoring component.");
-        }
-    }
-
-
-    /**
-     * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's FinSet.
-     *
-     * @param warnings the warning set to convey incompatibilities to the user
-     *
-     * @return a FinSet instance
-     */
-    public FinSet asOpenRocket (WarningSet warnings) {
-        FinSet result;
-
-        if (shapeCode == 0) {
-            //Trapezoidal
-            result = new TrapezoidFinSet();
-            ((TrapezoidFinSet) result).setFinShape(rootChord, tipChord, sweepDistance, semiSpan, thickness);
-        }
-        else if (shapeCode == 1) {
-            //Elliptical
-            result = new EllipticalFinSet();
-            ((EllipticalFinSet) result).setHeight(semiSpan);
-            ((EllipticalFinSet) result).setLength(rootChord);
-        }
-        else if (shapeCode == 2) {
-
-            result = new FreeformFinSet();
-            try {
-                ((FreeformFinSet) result).setPoints(toCoordinates(pointList, warnings));
-            }
-            catch (IllegalFinPointException e) {
-                warnings.add("Illegal fin point set. " + e.getMessage() + " Ignoring.");
-            }
-        }
-        else {
-            return null;
-        }
-        result.setThickness(thickness);
-        result.setName(name);
-        result.setFinCount(finCount);
-        result.setFinish(finish);
-        //All TTW tabs in Rocksim are relative to the front of the fin.
-        result.setTabRelativePosition(FinSet.TabRelativePosition.FRONT);
-        result.setTabHeight(tabDepth);
-        result.setTabLength(tabLength);
-        result.setTabShift(taboffset);
-        result.setBaseRotation(radialAngle);
-        result.setCrossSection(convertTipShapeCode(tipShapeCode));
-        result.setRelativePosition(position);
-        PositionDependentHandler.setLocation(result, position, location);
-        return result;
-
-    }
-
-    /**
-     * Convert a Rocksim string that represents fin plan points into an array of OpenRocket coordinates.
-     *
-     * @param pointList a comma and pipe delimited string of X,Y coordinates from Rocksim.  This is of the format:
-     *                  <pre>x0,y0|x1,y1|x2,y2|... </pre>
-     * @param warnings  the warning set to convey incompatibilities to the user
-     *
-     * @return an array of OpenRocket Coordinates
-     */
-    private Coordinate[] toCoordinates (String pointList, WarningSet warnings) {
-        List<Coordinate> result = new ArrayList<Coordinate>();
-        if (pointList != null && !pointList.isEmpty()) {
-            String[] points = pointList.split("\\Q|\\E");
-            for (String point : points) {
-                String[] aPoint = point.split(",");
-                try {
-                    if (aPoint.length > 1) {
-                        Coordinate c = new Coordinate(
-                                Double.parseDouble(aPoint[0]) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH,
-                                Double.parseDouble(aPoint[1]) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
-                        result.add(c);
-                    }
-                    else {
-                        warnings.add("Invalid fin point pair.");
-                    }
-                }
-                catch (NumberFormatException nfe) {
-                    warnings.add("Fin point not in numeric format.");
-                }
-            }
-            if (!result.isEmpty()) {
-                //OpenRocket requires fin plan points be ordered from leading root chord to trailing root chord in the
-                //Coordinate array.
-                Coordinate last = result.get(result.size() - 1);
-                if (last.x == 0 && last.y == 0) {
-                    Collections.reverse(result);
-                }
-            }
-        }
-        final Coordinate[] coords = new Coordinate[result.size()];
-        return result.toArray(coords);
-    }
-
-
-    /**
-     * Convert a Rocksim tip shape to an OpenRocket CrossSection.
-     *
-     * @param tipShape the tip shape code from Rocksim
-     *
-     * @return a CrossSection instance
-     */
-    private FinSet.CrossSection convertTipShapeCode (int tipShape) {
-        switch (tipShape) {
-            case 0:
-                return FinSet.CrossSection.SQUARE;
-            case 1:
-                return FinSet.CrossSection.ROUNDED;
-            case 2:
-                return FinSet.CrossSection.AIRFOIL;
-            default:
-                return FinSet.CrossSection.SQUARE;
-        }
-    }
-
-}
-
diff --git a/src/net/sf/openrocket/file/rocksim/InnerBodyTubeHandler.java b/src/net/sf/openrocket/file/rocksim/InnerBodyTubeHandler.java
deleted file mode 100644 (file)
index eaa1014..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * InnerBodyTubeHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-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.InnerTube;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.xml.sax.SAXException;
-
-import java.util.HashMap;
-
-/**
- * A SAX handler for Rocksim inside tubes.
- */
-class InnerBodyTubeHandler extends PositionDependentHandler<InnerTube> {
-
-    /**
-     * The OpenRocket InnerTube instance.
-     */
-    private final InnerTube bodyTube;
-
-    /**
-     * Constructor.
-     *
-     * @param c the parent component
-     * @param warnings  the warning set
-     * @throws IllegalArgumentException thrown if <code>c</code> is null
-     */
-    public InnerBodyTubeHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
-        if (c == null) {
-            throw new IllegalArgumentException("The parent component of an inner tube may not be null.");
-        }
-        bodyTube = new InnerTube();
-        if (isCompatible(c, InnerTube.class, warnings)) {
-            c.addChild(bodyTube);
-        }
-    }
-
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
-        if ("AttachedParts".equals(element)) {
-            return new AttachedPartsHandler(bodyTube);
-        }
-        return PlainTextHandler.INSTANCE;
-    }
-
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        super.closeElement(element, attributes, content, warnings);
-
-        try {
-            if ("OD".equals(element)) {
-                bodyTube.setOuterRadius(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
-            }
-            if ("ID".equals(element)) {
-                final double r = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS;
-                bodyTube.setInnerRadius(r);
-            }
-            if ("Len".equals(element)) {
-                bodyTube.setLength(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
-            }
-            if ("IsMotorMount".equals(element)) {
-                bodyTube.setMotorMount("1".equals(content));
-            }
-            if ("EngineOverhang".equals(element)) {
-                bodyTube.setMotorOverhang(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
-            }
-            if ("Material".equals(element)) {
-                setMaterialName(content);
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    /**
-     * Get the InnerTube component this handler is working upon.
-     * 
-     * @return an InnerTube component
-     */
-    @Override
-    public InnerTube getComponent() {
-        return bodyTube;
-    }
-
-    /**
-     * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not 
-     * public in all components.
-     * 
-     * @param position  the OpenRocket position
-     */
-    @Override
-    public void setRelativePosition(RocketComponent.Position position) {
-        bodyTube.setRelativePosition(position);
-    }
-
-    /**
-     * Get the required type of material for this component.
-     *
-     * @return BULK
-     */
-    @Override
-    public Material.Type getMaterialType() {
-        return Material.Type.BULK;
-    }
-
-}
diff --git a/src/net/sf/openrocket/file/rocksim/LaunchLugHandler.java b/src/net/sf/openrocket/file/rocksim/LaunchLugHandler.java
deleted file mode 100644 (file)
index 60c5b49..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * LaunchLugHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-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.LaunchLug;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.xml.sax.SAXException;
-
-import java.util.HashMap;
-
-/**
- * The SAX handler for Rocksim Launch Lugs.
- */
-class LaunchLugHandler extends PositionDependentHandler<LaunchLug> {
-
-    /**
-     * The OpenRocket LaunchLug instance.
-     */
-    private final LaunchLug lug;
-
-    /**
-     * Constructor.
-     *
-     * @param c the parent
-     * @param warnings  the warning set
-     * 
-     * @throws IllegalArgumentException thrown if <code>c</code> is null
-     */
-    public LaunchLugHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
-        if (c == null) {
-            throw new IllegalArgumentException("The parent component of a launch lug may not be null.");
-        }
-        lug = new LaunchLug();
-        if (isCompatible(c, LaunchLug.class, warnings)) {
-            c.addChild(lug);
-        }
-    }
-
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
-        return PlainTextHandler.INSTANCE;
-    }
-
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        super.closeElement(element, attributes, content, warnings);
-
-        try {
-            if ("OD".equals(element)) {
-                lug.setOuterRadius(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
-            }
-            if ("ID".equals(element)) {
-                lug.setInnerRadius(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
-            }
-            if ("Len".equals(element)) {
-                lug.setLength(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
-            }
-            if ("Material".equals(element)) {
-                setMaterialName(content);
-            }
-            if ("RadialAngle".equals(element)) {
-                lug.setRadialDirection(Double.parseDouble(content));
-            }
-            if ("FinishCode".equals(element)) {
-                lug.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket());
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    /**
-     * Get the LaunchLug component this handler is working upon.
-     * 
-     * @return a LaunchLug component
-     */
-    @Override
-    public LaunchLug getComponent() {
-        return lug;
-    }
-
-    /**
-     * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not 
-     * public in all components.
-     * 
-     * @param position  the OpenRocket position
-     */
-    @Override
-    public void setRelativePosition(RocketComponent.Position position) {
-        lug.setRelativePosition(position);
-    }
-
-    /**
-     * Get the required type of material for this component.
-     *
-     * @return BULK
-     */
-    @Override
-    public Material.Type getMaterialType() {
-        return Material.Type.BULK;
-    }
-}
-
diff --git a/src/net/sf/openrocket/file/rocksim/MassObjectHandler.java b/src/net/sf/openrocket/file/rocksim/MassObjectHandler.java
deleted file mode 100644 (file)
index 479242d..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * MassObjectHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-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.MassComponent;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.xml.sax.SAXException;
-
-import java.util.HashMap;
-
-/**
- * A SAX handler for Rocksim's MassObject XML type.
- */
-class MassObjectHandler extends PositionDependentHandler<MassComponent> {
-
-    /** 
-     * The Rocksim Mass length fudge factor.  Rocksim completely exaggerates the length of a mass object to the point
-     * that it looks ridiculous in OpenRocket.  This fudge factor is here merely to get the typical mass object to
-     * render in the OpenRocket UI with it's bounds mostly inside it's parent.  The odd thing about it is that 
-     * Rocksim does not expose the length of a mass object in the UI and actually treats mass objects as point objects -
-     * not 3 or even 2 dimensional.
-     */
-    public static final int MASS_LEN_FUDGE_FACTOR = 100;
-
-    /**
-     * The OpenRocket MassComponent - counterpart to the RS MassObject.
-     */
-    private final MassComponent mass;
-
-    /**
-     * Constructor.
-     *l
-     * @param c the parent component
-     * @param warnings  the warning set
-     * 
-     * @throws IllegalArgumentException  thrown if <code>c</code> is null
-     */
-    public MassObjectHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
-        if (c == null) {
-            throw new IllegalArgumentException("The parent component of a mass component may not be null.");
-        }
-        mass = new MassComponent();
-        if (isCompatible(c, MassComponent.class, warnings)) {
-            c.addChild(mass);
-        }
-    }
-
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
-        return PlainTextHandler.INSTANCE;
-    }
-
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        super.closeElement(element, attributes, content, warnings);
-        try {
-            if ("Len".equals(element)) {
-                mass.setLength(Double.parseDouble(content) / (RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH * MASS_LEN_FUDGE_FACTOR));
-            }
-            if ("KnownMass".equals(element)) {
-                mass.setComponentMass(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
-            }
-            if ("KnownCG".equals(element)) {
-                //Setting the CG of the Mass Object to 0 is important because of the different ways that Rocksim and
-                //OpenRocket treat mass objects.  Rocksim treats them as points (even though the data file contains a
-                //length) and because Rocksim sets the CG of the mass object to really be relative to the front of
-                //the parent.  But that value is already assumed in the position and position value for the component.
-                //Thus it needs to be set to 0 to say that the mass object's CG is at the point of the mass object.
-                super.setCG(0); 
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    /**
-     * Get the component this handler is working upon.
-     *
-     * @return a component
-     */
-    @Override
-    public MassComponent getComponent() {
-        return mass;
-    }
-
-    /**
-     * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not
-     * public in all components.
-     *
-     * @param position the OpenRocket position
-     */
-    public void setRelativePosition(RocketComponent.Position position) {
-        mass.setRelativePosition(position);
-    }
-
-    /**
-     * Get the required type of material for this component.  Does not apply to MassComponents.
-     *
-     * @return BULK
-     */
-    @Override
-    public Material.Type getMaterialType() {
-        return Material.Type.BULK;
-    }
-
-}
diff --git a/src/net/sf/openrocket/file/rocksim/NoseConeHandler.java b/src/net/sf/openrocket/file/rocksim/NoseConeHandler.java
deleted file mode 100644 (file)
index ec5c2df..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * NoseConeHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-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.NoseCone;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.Transition;
-import org.xml.sax.SAXException;
-
-import java.util.HashMap;
-
-/**
- * The SAX nose cone handler for Rocksim NoseCones.
- */
-class NoseConeHandler extends BaseHandler<NoseCone> {
-
-    /**
-     * The OpenRocket NoseCone.
-     */
-    private final NoseCone noseCone = new NoseCone();
-
-    /**
-     * The wall thickness.  Used for hollow nose cones.  
-     */
-    private double thickness = 0d;
-    
-    /**
-     * Constructor.
-     *
-     * @param c the parent component to the nosecone
-     * @param warnings  the warning set
-     * 
-     * @throws IllegalArgumentException thrown if <code>c</code> is null
-     */
-    public NoseConeHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
-        if (c == null) {
-            throw new IllegalArgumentException("The parent component of a nose cone may not be null.");
-        }
-        if (isCompatible(c, NoseCone.class, warnings)) {
-            c.addChild(noseCone);
-            noseCone.setAftRadiusAutomatic(false);
-        }
-    }
-
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
-        //Nose cones in Rocksim may have attached parts - namely Mass Objects - as children.
-        if ("AttachedParts".equals(element)) {
-            return new AttachedPartsHandler(noseCone);
-        }
-        return PlainTextHandler.INSTANCE;
-    }
-
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes,
-                             String content, WarningSet warnings) throws SAXException {
-        super.closeElement(element, attributes, content, warnings);
-
-        try {
-            if ("ShapeCode".equals(element)) {
-                noseCone.setType(RocksimNoseConeCode.fromCode(Integer.parseInt(content)).asOpenRocket());
-            }
-            if ("Len".equals(element)) {
-                noseCone.setLength(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
-            }
-            if ("BaseDia".equals(element)) {
-                noseCone.setAftRadius(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
-            }
-            if ("WallThickness".equals(element)) {
-                thickness = Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
-            }
-            if ("ShoulderOD".equals(element)) {
-                noseCone.setAftShoulderRadius(Math.max(0, Double.parseDouble(
-                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
-            }
-            if ("ShoulderLen".equals(element)) {
-                noseCone.setAftShoulderLength(Math.max(0, Double.parseDouble(
-                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
-            }
-            if ("ShapeParameter".equals(element)) {
-                //The Rocksim ShapeParameter only applies to certain shapes, although it is included
-                //in the design file for all nose cones.  Applying it when it should not be causes oddities so 
-                //a check is made for the allowable shapes.
-                if (Transition.Shape.POWER.equals(noseCone.getType()) ||
-                    Transition.Shape.HAACK.equals(noseCone.getType()) ||
-                    Transition.Shape.PARABOLIC.equals(noseCone.getType())) {
-                    noseCone.setShapeParameter(Double.parseDouble(content));
-                }
-            }
-            if ("ConstructionType".equals(element)) {
-                int typeCode = Integer.parseInt(content);
-                if (typeCode == 0) {
-                    //SOLID
-                    noseCone.setFilled(true);
-                }
-                else if (typeCode == 1) {
-                    //HOLLOW
-                    noseCone.setFilled(false);
-                }
-            }
-            if ("FinishCode".equals(element)) {
-                noseCone.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket());
-            }
-            if ("Material".equals(element)) {
-                setMaterialName(content);
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    @Override
-    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        super.endHandler(element, attributes, content, warnings);
-        
-        if (noseCone.isFilled()) {
-            noseCone.setAftShoulderThickness(noseCone.getAftShoulderRadius());                    
-        }
-        else {
-            noseCone.setThickness(thickness);
-            noseCone.setAftShoulderThickness(thickness);
-        }
-    }
-    
-    /**
-     * Get the nose cone component this handler is working upon.
-     *
-     * @return a nose cone component
-     */
-    @Override
-    public NoseCone getComponent() {
-        return noseCone;
-    }
-
-    /**
-     * Get the required type of material for this component.
-     *
-     * @return BULK
-     */
-    public Material.Type getMaterialType() {
-        return Material.Type.BULK;
-    }
-
-}
diff --git a/src/net/sf/openrocket/file/rocksim/ParachuteHandler.java b/src/net/sf/openrocket/file/rocksim/ParachuteHandler.java
deleted file mode 100644 (file)
index 6d739eb..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * ParachuteHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-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.BodyTube;
-import net.sf.openrocket.rocketcomponent.InnerTube;
-import net.sf.openrocket.rocketcomponent.Parachute;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.xml.sax.SAXException;
-
-import java.util.HashMap;
-
-/**
- * A SAX handler for Rocksim's Parachute XML type.
- */
-class ParachuteHandler extends RecoveryDeviceHandler<Parachute> {
-    /**
-     * The OpenRocket Parachute instance
-     */
-    private final Parachute chute;
-    /**
-     * The shroud line density.
-     */
-    private double shroudLineDensity = 0.0d;
-
-    /**
-     * Constructor.
-     *
-     * @param c the parent component
-     * @param warnings  the warning set
-     * 
-     * @throws IllegalArgumentException thrown if <code>c</code> is null
-     */
-    public ParachuteHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
-        if (c == null) {
-            throw new IllegalArgumentException("The parent of a parachute may not be null.");
-        }
-        chute = new Parachute();
-        if (isCompatible(c, Parachute.class, warnings)) {
-            c.addChild(chute);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
-        return PlainTextHandler.INSTANCE;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        super.closeElement(element, attributes, content, warnings);
-        try {
-            if ("Dia".equals(element)) {
-                chute.setDiameter(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
-                /* Rocksim doesn't have a packed parachute radius, so we approximate it. */
-                double packed;
-                RocketComponent parent = chute.getParent();
-                if (parent instanceof BodyTube) {
-                    packed = ((BodyTube) parent).getOuterRadius() * 0.9;
-                }
-                else if (parent instanceof InnerTube) {
-                    packed = ((InnerTube) parent).getInnerRadius() * 0.9;
-                }
-                else {
-                    packed = chute.getDiameter() * 0.025;
-                }
-                chute.setRadius(packed);
-            }
-            if ("ShroudLineCount".equals(element)) {
-                chute.setLineCount(Math.max(0, Integer.parseInt(content)));
-            }
-            if ("ShroudLineLen".equals(element)) {
-                chute.setLineLength(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
-            }
-            if ("SpillHoleDia".equals(element)) {
-                //Not supported in OpenRocket
-                double spillHoleRadius = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS;
-                warnings.add("Parachute spill holes are not supported. Ignoring.");
-            }
-            if ("ShroudLineMassPerMM".equals(element)) {
-                shroudLineDensity = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LINE_DENSITY;
-            }
-            if ("ShroudLineMaterial".equals(element)) {
-                chute.setLineMaterial(BaseHandler.createCustomMaterial(Material.Type.LINE, content, shroudLineDensity));
-            }
-            if ("DragCoefficient".equals(element)) {
-                chute.setCD(Double.parseDouble(content));
-            }
-            if ("Material".equals(element)) {
-                setMaterialName(content);
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    /**
-     * Get the component this handler is working upon.
-     *
-     * @return a component
-     */
-    public Parachute getComponent() {
-        return chute;
-    }
-
-}
-
diff --git a/src/net/sf/openrocket/file/rocksim/PositionDependentHandler.java b/src/net/sf/openrocket/file/rocksim/PositionDependentHandler.java
deleted file mode 100644 (file)
index 076f46a..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * PositionDependentHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.xml.sax.SAXException;
-
-import java.util.HashMap;
-
-/**
- * An abstract base class that handles position dependencies for all lower level components that
- * are position aware.
- *
- * @param <C>   the specific position dependent RocketComponent subtype for which the concrete handler can create
- */
-public abstract class PositionDependentHandler<C extends RocketComponent> extends BaseHandler<C> {
-
-    /** Temporary position value. */
-    private Double positionValue = 0d;
-
-    /** Temporary position. */
-    private RocketComponent.Position position = RocketComponent.Position.TOP;
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        super.closeElement(element, attributes, content, warnings);
-        if ("Xb".equals(element)) {
-            positionValue = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-        }
-        if ("LocationMode".equals(element)) {
-            position = RocksimLocationMode.fromCode(Integer.parseInt(
-                    content)).asOpenRocket();
-        }
-    }
-
-    /**
-     * This method sets the position information onto the component.  Rocksim splits the location/position
-     * information into two disparate data elements.  Both pieces of data are necessary to map into OpenRocket's
-     * position model.
-     *
-     * @param element     the element name
-     * @param attributes  the attributes
-     * @param content     the content of the element
-     * @param warnings        the warning set to store warnings in.
-     * @throws org.xml.sax.SAXException  not thrown
-     */
-    @Override
-    public void endHandler(String element, HashMap<String, String> attributes,
-                           String content, WarningSet warnings) throws SAXException {
-        super.endHandler(element, attributes, content, warnings);
-        setRelativePosition(position);
-        setLocation(getComponent(), position, positionValue);
-    }
-
-    /**
-     * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not
-     * public in all components.
-     *
-     * @param position  the OpenRocket position
-     */
-    protected abstract void setRelativePosition(RocketComponent.Position position);
-
-    /**
-     * Set the position of a component.
-     *
-     * @param component  the component
-     * @param position   the relative position
-     * @param location   the actual position value
-     */
-    public static void setLocation(RocketComponent component, RocketComponent.Position position, double location) {
-        if (position.equals(RocketComponent.Position.BOTTOM)) {
-            component.setPositionValue(-1d * location);
-        }
-        else {
-            component.setPositionValue(location);
-        }
-    }
-
-}
diff --git a/src/net/sf/openrocket/file/rocksim/RecoveryDeviceHandler.java b/src/net/sf/openrocket/file/rocksim/RecoveryDeviceHandler.java
deleted file mode 100644 (file)
index 387e29b..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * RecoveryDeviceHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.RecoveryDevice;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.xml.sax.SAXException;
-
-import java.util.HashMap;
-
-/**
- * A handler specific to streamers and parachutes.  This is done because Rocksim allows any type of material to be
- * used as a recovery device, which causes oddities with respect to densities.  Density computation is overridden
- * here to try to correctly compute a material's density in OpenRocket units.
- *
- * @param <C>  either a Streamer or Parachute
- */
-public abstract class RecoveryDeviceHandler<C extends RecoveryDevice> extends PositionDependentHandler<C> {
-
-    /**
-     * The thickness.  Not used by every component, and some component handlers may parse it for their own purposes.
-     */
-    private double thickness = 0d;
-    /**
-     * The Rocksim calculated mass.  Used only when not overridden and when Rocksim says density == 0 (Rocksim bug).
-     */
-    private Double calcMass = 0d;
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        super.closeElement(element, attributes, content, warnings);
-
-        try {
-            if ("Thickness".equals(element)) {
-                thickness = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("CalcMass".equals(element)) {
-                calcMass = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-
-    /**
-     * Compute the density.  Rocksim does strange things with densities.  For some streamer material it's in cubic,
-     * rather than square, units.  In those cases it needs to be converted to an appropriate SURFACE material density.
-     *
-     * @param type       the rocksim density
-     * @param rawDensity the density as specified in the Rocksim design file
-     * @return a value in OpenRocket SURFACE density units
-     */
-    protected double computeDensity(RocksimDensityType type, double rawDensity) {
-
-        double result;
-
-        if (rawDensity > 0d) {
-            //ROCKSIM_SURFACE is a square area density; compute normally
-            //ROCKSIM_LINE is a single length dimension (kg/m) but Rocksim ignores thickness for this type and treats
-            //it like a SURFACE.
-            if (RocksimDensityType.ROCKSIM_SURFACE.equals(type) || RocksimDensityType.ROCKSIM_LINE.equals(type)) {
-                result = rawDensity / RocksimDensityType.ROCKSIM_SURFACE.asOpenRocket();
-            }
-            //ROCKSIM_BULK is a cubic area density; multiple by thickness to make per square area; the result, when
-            //multiplied by the area will then equal Rocksim's computed mass.
-            else {
-                result = (rawDensity / type.asOpenRocket()) * thickness;
-            }
-        }
-        else {
-            result = calcMass / getComponent().getArea();
-            //A Rocksim bug on streamers/parachutes results in a 0 density at times.  When that is detected, try
-            //to compute an approximate density from Rocksim's computed mass.
-            if (RocksimDensityType.ROCKSIM_BULK.equals(type)) {
-                //ROCKSIM_BULK is a cubic area density; multiple by thickness to make per square area
-                result *= thickness;
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not
-     * public in all components.
-     *
-     * @param position the OpenRocket position
-     */
-    @Override
-    public void setRelativePosition(RocketComponent.Position position) {
-        getComponent().setRelativePosition(position);
-    }
-
-    /**
-     * Get the required type of material for this component.  This is the OpenRocket type, which does NOT always
-     * correspond to Rocksim.  Some streamer material is defined as BULK in the Rocksim file.  In those cases
-     * it is adjusted in this handler.
-     *
-     * @return SURFACE
-     */
-    @Override
-    public Material.Type getMaterialType() {
-        return Material.Type.SURFACE;
-    }
-
-}
diff --git a/src/net/sf/openrocket/file/rocksim/RingHandler.java b/src/net/sf/openrocket/file/rocksim/RingHandler.java
deleted file mode 100644 (file)
index e3d6134..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * RingHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-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.Bulkhead;
-import net.sf.openrocket.rocketcomponent.CenteringRing;
-import net.sf.openrocket.rocketcomponent.EngineBlock;
-import net.sf.openrocket.rocketcomponent.RingComponent;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.TubeCoupler;
-import org.xml.sax.SAXException;
-
-import java.util.HashMap;
-
-/**
- * A SAX handler for centering rings, tube couplers, and bulkheads.
- */
-class RingHandler extends PositionDependentHandler<CenteringRing> {
-
-    /**
-     * The OpenRocket Ring.
-     */
-    private final CenteringRing ring = new CenteringRing();
-
-    /**
-     * The parent component.
-     */
-    private final RocketComponent parent;
-
-    /**
-     * The parsed Rocksim UsageCode.
-     */
-    private int usageCode = 0;
-
-    /**
-     * Constructor.
-     *
-     * @param theParent the parent component
-     * @param warnings  the warning set
-     * @throws IllegalArgumentException thrown if <code>c</code> is null
-     */
-    public RingHandler(RocketComponent theParent, WarningSet warnings) throws IllegalArgumentException {
-        if (theParent == null) {
-            throw new IllegalArgumentException("The parent of a ring may not be null.");
-        }
-        parent = theParent;
-    }
-
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
-        return PlainTextHandler.INSTANCE;
-    }
-
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        super.closeElement(element, attributes, content, warnings);
-
-        try {
-            if ("OD".equals(element)) {
-                ring.setOuterRadius(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
-            }
-            if ("ID".equals(element)) {
-                ring.setInnerRadius(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
-            }
-            if ("Len".equals(element)) {
-                ring.setLength(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
-            }
-            if ("Material".equals(element)) {
-                setMaterialName(content);
-            }
-            if ("UsageCode".equals(element)) {
-                usageCode = Integer.parseInt(content);
-            }
-        } catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    /**
-     * Get the ring component this handler is working upon.
-     *
-     * @return a component
-     */
-    @Override
-    public CenteringRing getComponent() {
-        return ring;
-    }
-
-    /**
-     * This method adds the CenteringRing as a child of the parent rocket component.
-     *
-     * @param warnings the warning set
-     */
-    public void asCenteringRing(WarningSet warnings) {
-
-        if (isCompatible(parent, CenteringRing.class, warnings)) {
-            parent.addChild(ring);
-        }
-    }
-
-    /**
-     * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's Bulkhead.
-     * <p/>
-     * Side Effect Warning: This method adds the resulting Bulkhead as a child of the parent rocket component!
-     *
-     * @param warnings the warning set
-     */
-    public void asBulkhead(WarningSet warnings) {
-
-        Bulkhead result = new Bulkhead();
-
-        copyValues(result);
-
-        if (isCompatible(parent, Bulkhead.class, warnings)) {
-            parent.addChild(result);
-        }
-    }
-
-    /**
-     * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's TubeCoupler.
-     * <p/>
-     * Side Effect Warning: This method adds the resulting TubeCoupler as a child of the parent rocket component!
-     *
-     * @param warnings the warning set
-     */
-    public void asTubeCoupler(WarningSet warnings) {
-
-        TubeCoupler result = new TubeCoupler();
-
-        copyValues(result);
-
-        if (isCompatible(parent, TubeCoupler.class, warnings)) {
-            parent.addChild(result);
-        }
-    }
-
-    /**
-     * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's Engine Block.
-     * <p/>
-     * Side Effect Warning: This method adds the resulting EngineBlock as a child of the parent rocket component!
-     *
-     * @param warnings the warning set
-     */
-    public void asEngineBlock(WarningSet warnings) {
-
-        EngineBlock result = new EngineBlock();
-
-        copyValues(result);
-
-        if (isCompatible(parent, EngineBlock.class, warnings)) {
-            parent.addChild(result);
-        }
-    }
-
-    /**
-     * Copy values from the base ring to the specific component.
-     *
-     * @param result the target to which ring values will be copied
-     */
-    private void copyValues(RingComponent result) {
-        result.setOuterRadius(ring.getOuterRadius());
-        result.setInnerRadius(ring.getInnerRadius());
-        result.setLength(ring.getLength());
-        result.setName(ring.getName());
-        PositionDependentHandler.setOverride(result, ring.isOverrideSubcomponentsEnabled(), ring.getOverrideMass(), ring.getOverrideCGX());
-        result.setRelativePosition(ring.getRelativePosition());
-        result.setPositionValue(ring.getPositionValue());
-        result.setMaterial(ring.getMaterial());
-    }
-
-    /**
-     * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not
-     * public in all components.
-     *
-     * @param position the OpenRocket position
-     */
-    @Override
-    public void setRelativePosition(RocketComponent.Position position) {
-        ring.setRelativePosition(position);
-    }
-
-    @Override
-    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
-        super.endHandler(element, attributes, content, warnings);
-
-        // The <Ring> XML element in Rocksim design file is used for many types of components, unfortunately.
-        // Additional subelements are used to indicate the type of the rocket component. When parsing using SAX
-        // this poses a problem because we can't "look ahead" to see what type is being represented at the start
-        // of parsing - something that would be nice to do so that we can instantiate the correct OR component
-        // at the start, then just call setters for the appropriate data.
-
-        // To overcome that, a CenteringRing is instantiated at the start of parsing, it's mutators are called,
-        // and then at the end (this method) converts the CenteringRing to a more appropriate type.  CenteringRing
-        // is generic enough to support the representation of all similar types without loss of data.
-
-        //UsageCode
-        // 0 == Centering Ring
-        // 1 == Bulkhead
-        // 2 == Engine Block
-        // 3 == Sleeve
-        // 4 == Tube Coupler
-
-        if (usageCode == 1) {
-            //Bulkhead
-            asBulkhead(warnings);
-        } else if (usageCode == 2) {
-            asEngineBlock(warnings);
-        } else if (usageCode == 4) {
-            //TubeCoupler
-            asTubeCoupler(warnings);
-        } else {
-            //Default
-            asCenteringRing(warnings);
-        }
-    }
-
-    /**
-     * Get the required type of material for this component.
-     *
-     * @return BULK
-     */
-    @Override
-    public Material.Type getMaterialType() {
-        return Material.Type.BULK;
-    }
-}
\ No newline at end of file
diff --git a/src/net/sf/openrocket/file/rocksim/RocksimDensityType.java b/src/net/sf/openrocket/file/rocksim/RocksimDensityType.java
deleted file mode 100644 (file)
index c672b62..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * RocksimDensityType.java
- */
-package net.sf.openrocket.file.rocksim;
-
-/**
- * Models the nose cone shape of a rocket.  Maps from Rocksim's notion to OpenRocket's.
- */
-enum RocksimDensityType {
-    ROCKSIM_BULK   (0, RocksimHandler.ROCKSIM_TO_OPENROCKET_BULK_DENSITY),
-    ROCKSIM_SURFACE(1, RocksimHandler.ROCKSIM_TO_OPENROCKET_SURFACE_DENSITY),
-    ROCKSIM_LINE   (2, RocksimHandler.ROCKSIM_TO_OPENROCKET_LINE_DENSITY);
-
-    /** The Rocksim enumeration value. Sent in XML. */
-    private final int ordinal;
-
-    /** The corresponding OpenRocket shape. */
-    private final double conversion;
-
-    /**
-     * Constructor.
-     *
-     * @param idx            the Rocksim shape code
-     * @param theConversion  the numerical conversion ratio to OpenRocket
-     */
-    private RocksimDensityType(int idx, double theConversion) {
-        ordinal = idx;
-        conversion = theConversion;
-    }
-
-    /**
-     * Get the OpenRocket shape that corresponds to the Rocksim value.
-     *
-     * @return a conversion
-     */
-    public double asOpenRocket() {
-        return conversion;
-    }
-
-    /**
-     * Lookup an instance of this enum based upon the Rocksim code.
-     *
-     * @param rocksimDensityType  the Rocksim code (from XML)
-     * @return an instance of this enum
-     */
-    public static RocksimDensityType fromCode(int rocksimDensityType) {
-        RocksimDensityType[] values = values();
-        for (RocksimDensityType value : values) {
-            if (value.ordinal == rocksimDensityType) {
-                return value;
-            }
-        }
-        return ROCKSIM_BULK; //Default
-    }
-}
-
diff --git a/src/net/sf/openrocket/file/rocksim/RocksimFinishCode.java b/src/net/sf/openrocket/file/rocksim/RocksimFinishCode.java
deleted file mode 100644 (file)
index cf1748b..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * RocksimFinishCode.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.rocketcomponent.ExternalComponent;
-
-/**
- * Models the finish of a component.
- */
-enum RocksimFinishCode {
-    POLISHED(0, ExternalComponent.Finish.POLISHED),
-    GLOSS(1, ExternalComponent.Finish.SMOOTH),
-    MATT(2, ExternalComponent.Finish.NORMAL),
-    UNFINISHED(3, ExternalComponent.Finish.UNFINISHED);
-
-    /** The Rocksim code (from XML). */
-    private final int ordinal;
-    
-    /** The corresponding OpenRocket finish. */
-    private final ExternalComponent.Finish finish;
-
-    /**
-     * Constructor.
-     * 
-     * @param idx   the Rocksim enum value
-     * @param theFinish  the OpenRocket finish
-     */
-    private RocksimFinishCode(int idx, ExternalComponent.Finish theFinish) {
-        ordinal = idx;
-        finish = theFinish;
-    }
-
-    /**
-     * Get the OpenRocket finish.
-     * 
-     * @return a Finish instance
-     */
-    public ExternalComponent.Finish asOpenRocket() {
-        return finish;
-    }
-
-    /**
-     * Lookup an instance of this enum from a Rocksim value.
-     * 
-     * @param rocksimFinishCode  the Rocksim value
-     * 
-     * @return an instance of this enum; Defaults to MATT
-     */
-    public static RocksimFinishCode fromCode(int rocksimFinishCode) {
-        RocksimFinishCode[] values = values();
-        for (RocksimFinishCode value : values) {
-            if (value.ordinal == rocksimFinishCode) {
-                return value;
-            }
-        }
-        return MATT; //Default
-    }
-
-}
-
diff --git a/src/net/sf/openrocket/file/rocksim/RocksimHandler.java b/src/net/sf/openrocket/file/rocksim/RocksimHandler.java
deleted file mode 100644 (file)
index 7198b90..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * RocksimHandler.java
- *
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.Warning;
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.file.simplesax.ElementHandler;
-import net.sf.openrocket.file.simplesax.PlainTextHandler;
-import net.sf.openrocket.rocketcomponent.Rocket;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.Stage;
-import org.xml.sax.SAXException;
-
-import java.util.HashMap;
-
-/**
- * This class is a Sax element handler for Rocksim version 9 design files.  It parses the Rocksim file (typically
- * a .rkt extension) and creates corresponding OpenRocket components.  This is a best effort approach and may not
- * be an exact replica.
- * <p/>
- * Limitations: Rocksim flight simulations are not imported; tube fins are not supported; Rocksim 'pods' are not supported.
- */
-public class RocksimHandler extends ElementHandler {
-
-    /**
-     * Length conversion.  Rocksim is in millimeters, OpenRocket in meters.
-     */
-    public static final int ROCKSIM_TO_OPENROCKET_LENGTH = 1000;
-
-    /**
-     * Mass conversion.  Rocksim is in grams, OpenRocket in kilograms.
-     */
-    public static final int ROCKSIM_TO_OPENROCKET_MASS = 1000;
-
-    /**
-     * Bulk Density conversion.  Rocksim is in kilograms/cubic meter, OpenRocket in kilograms/cubic meter.
-     */
-    public static final int ROCKSIM_TO_OPENROCKET_BULK_DENSITY = 1;
-
-    /**
-     * Surface Density conversion.  Rocksim is in grams/sq centimeter, OpenRocket in kilograms/sq meter.  1000/(100*100) = 1/10
-     */
-    public static final double ROCKSIM_TO_OPENROCKET_SURFACE_DENSITY = 1/10d;
-
-    /**
-     * Line Density conversion.  Rocksim is in kilograms/meter, OpenRocket in kilograms/meter. 
-     */
-    public static final int ROCKSIM_TO_OPENROCKET_LINE_DENSITY = 1;
-
-    /**
-     * Radius conversion.  Rocksim is always in diameters, OpenRocket mostly in radius.
-     */
-    public static final int ROCKSIM_TO_OPENROCKET_RADIUS = 2 * ROCKSIM_TO_OPENROCKET_LENGTH;
-
-    /**
-     * The main content handler.
-     */
-    private RocksimContentHandler handler = null;
-
-    /**
-     * Return the OpenRocketDocument read from the file, or <code>null</code> if a document
-     * has not been read yet.
-     *
-     * @return the document read, or null.
-     */
-    public OpenRocketDocument getDocument() {
-        return handler.getDocument();
-    }
-
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes,
-                                      WarningSet warnings) {
-
-        // Check for unknown elements
-        if (!element.equals("RockSimDocument")) {
-            warnings.add(Warning.fromString("Unknown element " + element + ", ignoring."));
-            return null;
-        }
-
-        // Check for first call
-        if (handler != null) {
-            warnings.add(Warning.fromString("Multiple document elements found, ignoring later "
-                                            + "ones."));
-            return null;
-        }
-
-        handler = new RocksimContentHandler();
-        return handler;
-    }
-
-}
-
-/**
- * Handles the content of the <DesignInformation> tag.
- */
-class RocksimContentHandler extends ElementHandler {
-    /**
-     * The OpenRocketDocument that is the container for the rocket.
-     */
-    private final OpenRocketDocument doc;
-
-    /**
-     * The top-level component, from which all child components are added.
-     */
-    private final Rocket rocket;
-
-    /**
-     * The rocksim file version.
-     */
-    private String version;
-
-    /**
-     * Constructor.
-     */
-    public RocksimContentHandler() {
-        this.rocket = new Rocket();
-        this.doc = new OpenRocketDocument(rocket);
-    }
-
-    /**
-     * Get the OpenRocket document that has been created from parsing the Rocksim design file.
-     *
-     * @return the instantiated OpenRocketDocument
-     */
-    public OpenRocketDocument getDocument() {
-        return doc;
-    }
-
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes,
-                                      WarningSet warnings) {
-        if ("DesignInformation".equals(element)) {
-            //The next sub-element is "RocketDesign", which is really the only thing that matters.  Rather than
-            //create another handler just for that element, handle it here.
-            return this;
-        }
-        if ("FileVersion".equals(element)) {
-            return PlainTextHandler.INSTANCE;
-        }
-        if ("RocketDesign".equals(element)) {
-            return new RocketDesignHandler(rocket);
-        }
-        return null;
-    }
-
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes,
-                             String content, WarningSet warnings) throws SAXException {
-        /**
-         * SAX handler for Rocksim file version number.  The value is not used currently, but could be used in the future
-         * for backward/forward compatibility reasons (different lower level handlers could be called via a strategy pattern).
-         */
-        if ("FileVersion".equals(element)) {
-            version = content;
-        }
-    }
-
-    /**
-     * Answer the file version.
-     *
-     * @return the version of the Rocksim design file
-     */
-    public String getVersion() {
-        return version;
-    }
-}
-
-
-/**
- * A SAX handler for the high level Rocksim design.  This structure includes sub-structures for each of the stages.
- * Correct functioning of this handler is predicated on the stage count element appearing before the actual stage parts
- * structures.  If that invariant is not true, then behavior will be unpredictable.
- */
-class RocketDesignHandler extends ElementHandler {
-    /**
-     * The parent component.
-     */
-    private final RocketComponent component;
-    /**
-     * The parsed stage count.  Defaults to 1.
-     */
-    private int stageCount = 1;
-    /**
-     * The overridden stage 1 mass.
-     */
-    private double stage1Mass = 0d;
-    /**
-     * The overridden stage 2 mass.
-     */
-    private double stage2Mass = 0d;
-    /**
-     * The overridden stage 3 mass.
-     */
-    private double stage3Mass = 0d;
-    /**
-     * The overridden stage 1 Cg.
-     */
-    private double stage1CG = 0d;
-    /**
-     * The overridden stage 2 Cg.
-     */
-    private double stage2CG = 0d;
-    /**
-     * The overridden stage 3 Cg.
-     */
-    private double stage3CG = 0d;
-
-    /**
-     * Constructor.
-     *
-     * @param c the parent component
-     */
-    public RocketDesignHandler(RocketComponent c) {
-        component = c;
-    }
-
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
-        /**
-         * In Rocksim stages are from the top down, so a single stage rocket is actually stage '3'.  A 2-stage
-         * rocket defines stage '2' as the initial booster with stage '3' sitting atop it.  And so on.
-         */
-        if ("Stage3Parts".equals(element)) {
-            final Stage stage = new Stage();
-            if (stage3Mass > 0.0d) {
-                stage.setMassOverridden(true);
-                stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override
-                stage.setOverrideMass(stage3Mass);
-            }
-            if (stage3CG > 0.0d) {
-                stage.setCGOverridden(true);
-                stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override
-                stage.setOverrideCGX(stage3CG);
-            }
-            component.addChild(stage);
-            return new StageHandler(stage);
-        }
-        if ("Stage2Parts".equals(element)) {
-            if (stageCount >= 2) {
-                final Stage stage = new Stage();
-                if (stage2Mass > 0.0d) {
-                    stage.setMassOverridden(true);
-                    stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override
-                    stage.setOverrideMass(stage2Mass);
-                }
-                if (stage2CG > 0.0d) {
-                    stage.setCGOverridden(true);
-                    stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override
-                    stage.setOverrideCGX(stage2CG);
-                }
-                component.addChild(stage);
-                return new StageHandler(stage);
-            }
-        }
-        if ("Stage1Parts".equals(element)) {
-            if (stageCount == 3) {
-                final Stage stage = new Stage();
-                if (stage1Mass > 0.0d) {
-                    stage.setMassOverridden(true);
-                    stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override
-                    stage.setOverrideMass(stage1Mass);
-                }
-                if (stage1CG > 0.0d) {
-                    stage.setCGOverridden(true);
-                    stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override
-                    stage.setOverrideCGX(stage1CG);
-                }
-                component.addChild(stage);
-                return new StageHandler(stage);
-            }
-        }
-        if ("Name".equals(element)) {
-            return PlainTextHandler.INSTANCE;
-        }
-        if ("StageCount".equals(element)) {
-            return PlainTextHandler.INSTANCE;
-        }
-        if ("Stage3Mass".equals(element)) {
-            return PlainTextHandler.INSTANCE;
-        }
-        if ("Stage2Mass".equals(element)) {
-            return PlainTextHandler.INSTANCE;
-        }
-        if ("Stage1Mass".equals(element)) {
-            return PlainTextHandler.INSTANCE;
-        }
-        if ("Stage3CG".equals(element)) {
-            return PlainTextHandler.INSTANCE;
-        }
-        if ("Stage2CGAlone".equals(element)) {
-            return PlainTextHandler.INSTANCE;
-        }
-        if ("Stage1CGAlone".equals(element)) {
-            return PlainTextHandler.INSTANCE;
-        }
-        return null;
-    }
-
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes,
-                             String content, WarningSet warnings) throws SAXException {
-        try {
-            if ("Name".equals(element)) {
-                component.setName(content);
-            }
-            if ("StageCount".equals(element)) {
-                stageCount = Integer.parseInt(content);
-            }
-            if ("Stage3Mass".equals(element)) {
-                stage3Mass = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS;
-            }
-            if ("Stage2Mass".equals(element)) {
-                stage2Mass = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS;
-            }
-            if ("Stage1Mass".equals(element)) {
-                stage1Mass = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS;
-            }
-            if ("Stage3CG".equals(element)) {
-                stage3CG = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("Stage2CGAlone".equals(element)) {
-                stage2CG = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-            if ("Stage1CGAlone".equals(element)) {
-                stage1CG = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-}
-
-/**
- * A SAX handler for a Rocksim stage.
- */
-class StageHandler extends ElementHandler {
-    /**
-     * The parent OpenRocket component.
-     */
-    private final RocketComponent component;
-
-    /**
-     * Constructor.
-     *
-     * @param c the parent component
-     * @throws IllegalArgumentException thrown if <code>c</code> is null
-     */
-    public StageHandler(RocketComponent c) throws IllegalArgumentException {
-        if (c == null) {
-            throw new IllegalArgumentException("The stage component may not be null.");
-        }
-        component = c;
-    }
-
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
-        if ("NoseCone".equals(element)) {
-            return new NoseConeHandler(component, warnings);
-        }
-        if ("BodyTube".equals(element)) {
-            return new BodyTubeHandler(component, warnings);
-        }
-        if ("Transition".equals(element)) {
-            return new TransitionHandler(component, warnings);
-        }
-        return null;
-    }
-}
diff --git a/src/net/sf/openrocket/file/rocksim/RocksimLoader.java b/src/net/sf/openrocket/file/rocksim/RocksimLoader.java
deleted file mode 100644 (file)
index a2258aa..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * RocksimLoader.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.file.RocketLoadException;
-import net.sf.openrocket.file.RocketLoader;
-import net.sf.openrocket.file.simplesax.SimpleSAX;
-
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-/**
- * This class is the main entry point for Rocksim design file imported to OpenRocket.  Currently only Rocksim v9
- * file formats are supported, although it is possible that v8 formats will work for most components.
- * 
- * In the cases of v9 components that exist in Rocksim but have no corollary in OpenRocket a message is added to
- * a warning set and presented to the user.  In effect, this loading is a 'best-effort' mapping and is not meant to
- * be an exact representation of any possible Rocksim design in an OpenRocket format.
- * 
- * Rocksim simulations are not imported.
- * 
- * Wish List:
- *       Material interface (or at least make them abstract in RocketComponent)
- *          setMaterial
- *          getMaterial
- */
-public class RocksimLoader extends RocketLoader {
-       /**
-        * This method is called by the default implementations of {@link #load(java.io.File)}
-        * and {@link #load(java.io.InputStream)} to load the rocket.
-        *
-        * @throws net.sf.openrocket.file.RocketLoadException
-        *          if an error occurs during loading.
-        */
-       @Override
-       protected OpenRocketDocument loadFromStream(InputStream source) throws IOException, RocketLoadException {
-               
-               InputSource xmlSource = new InputSource(source);
-               
-               RocksimHandler handler = new RocksimHandler();
-               
-               try {
-                       SimpleSAX.readXML(xmlSource, handler, warnings);
-               } catch (SAXException e) {
-                       throw new RocketLoadException("Malformed XML in input.", e);
-               }
-               
-               final OpenRocketDocument document = handler.getDocument();
-               document.setFile(null);
-               document.clearUndo();
-               return document;
-       }
-}
diff --git a/src/net/sf/openrocket/file/rocksim/RocksimLocationMode.java b/src/net/sf/openrocket/file/rocksim/RocksimLocationMode.java
deleted file mode 100644 (file)
index 4b30703..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * RocksimLocationMode.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-
-/**
- * Models the relative position of parts on a rocket.  Maps from Rocksim's notion to OpenRocket's.
- */
-enum RocksimLocationMode {
-    FRONT_OF_OWNING_PART (0, RocketComponent.Position.TOP),
-    FROM_TIP_OF_NOSE     (1, RocketComponent.Position.ABSOLUTE),
-    BACK_OF_OWNING_PART  (2, RocketComponent.Position.BOTTOM);
-
-    /** The value Rocksim uses internally (and in the XML file). */
-    private final int ordinal;
-    
-    /** The OpenRocket position equivalent. */
-    private final RocketComponent.Position position;
-
-    /**
-     * Constructor.
-     * 
-     * @param idx   the rocksim enum value
-     * @param theOpenRocketPosition  the corresponding OpenRocket position
-     */
-    RocksimLocationMode(int idx, RocketComponent.Position theOpenRocketPosition) {
-        ordinal = idx;
-        position = theOpenRocketPosition;
-    }
-
-    /**
-     * Get the OpenRocket position.
-     * 
-     * @return  the position instance
-     */
-    public RocketComponent.Position asOpenRocket() {
-        return position;
-    }
-
-    /**
-     * Lookup an instance of this class from a rocksim enum value.
-     * 
-     * @param rocksimCode  the rocksim enum value
-     * 
-     * @return an instance of this enum
-     */
-    public static RocksimLocationMode fromCode(int rocksimCode) {
-        RocksimLocationMode[] values = values();
-        for (RocksimLocationMode value : values) {
-            if (value.ordinal == rocksimCode) {
-                return value;
-            }
-        }
-        return FRONT_OF_OWNING_PART;
-    }
-
-}
\ No newline at end of file
diff --git a/src/net/sf/openrocket/file/rocksim/RocksimNoseConeCode.java b/src/net/sf/openrocket/file/rocksim/RocksimNoseConeCode.java
deleted file mode 100644 (file)
index 8cd7c82..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * RocksimNoseConeCode.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.rocketcomponent.Transition;
-
-/**
- * Models the nose cone shape of a rocket.  Maps from Rocksim's notion to OpenRocket's.
- */
-enum RocksimNoseConeCode {
-    CONICAL         (0, Transition.Shape.CONICAL),
-    OGIVE           (1, Transition.Shape.OGIVE),
-    PARABOLIC       (2, Transition.Shape.ELLIPSOID),  //Rocksim' PARABOLIC most closely resembles an ELLIPSOID in OpenRocket
-    ELLIPTICAL      (3, Transition.Shape.ELLIPSOID),
-    POWER_SERIES    (4, Transition.Shape.POWER),
-    PARABOLIC_SERIES(5, Transition.Shape.PARABOLIC),
-    HAACK           (6, Transition.Shape.HAACK);
-
-    /** The Rocksim enumeration value. Sent in XML. */
-    private final int ordinal;
-    
-    /** The corresponding OpenRocket shape. */
-    private final Transition.Shape shape;
-
-    /**
-     * Constructor.
-     * 
-     * @param idx    the Rocksim shape code
-     * @param aShape the corresponding OpenRocket shape
-     */
-    private RocksimNoseConeCode(int idx, Transition.Shape aShape) {
-        ordinal = idx;
-        shape = aShape;
-    }
-
-    /**
-     * Get the OpenRocket shape that corresponds to the Rocksim shape.
-     * 
-     * @return a shape
-     */
-    public Transition.Shape asOpenRocket() {
-        return shape;
-    }
-
-    /**
-     * Lookup an instance of this enum based upon the Rocksim code.
-     * 
-     * @param rocksimShapeCode  the Rocksim code (from XML)
-     * @return an instance of this enum
-     */
-    public static RocksimNoseConeCode fromCode(int rocksimShapeCode) {
-        RocksimNoseConeCode[] values = values();
-        for (RocksimNoseConeCode value : values) {
-            if (value.ordinal == rocksimShapeCode) {
-                return value;
-            }
-        }
-        return PARABOLIC; //Default
-    }
-}
diff --git a/src/net/sf/openrocket/file/rocksim/StreamerHandler.java b/src/net/sf/openrocket/file/rocksim/StreamerHandler.java
deleted file mode 100644 (file)
index 73a8c2e..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * StreamerHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.file.simplesax.ElementHandler;
-import net.sf.openrocket.file.simplesax.PlainTextHandler;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.Streamer;
-import org.xml.sax.SAXException;
-
-import java.util.HashMap;
-
-/**
- * A SAX handler for Streamer components.
- */
-class StreamerHandler extends RecoveryDeviceHandler<Streamer> {
-
-    /**
-     * The OpenRocket Streamer.
-     */
-    private final Streamer streamer;
-
-    /**
-     * Constructor.
-     *
-     * @param c the parent component
-     * @param warnings  the warning set
-     * 
-     * @throws IllegalArgumentException thrown if <code>c</code> is null
-     */
-    public StreamerHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
-        if (c == null) {
-            throw new IllegalArgumentException("The parent of a streamer may not be null.");
-        }
-        streamer = new Streamer();
-        if (isCompatible(c, Streamer.class, warnings)) {
-            c.addChild(streamer);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
-        return PlainTextHandler.INSTANCE;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        super.closeElement(element, attributes, content, warnings);
-
-        try {
-            if ("Width".equals(element)) {
-                streamer.setStripWidth(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
-            }
-            if ("Len".equals(element)) {
-                streamer.setStripLength(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
-            }
-            if ("DragCoefficient".equals(element)) {
-                streamer.setCD(Double.parseDouble(content));
-            }
-            if ("Material".equals(element)) {
-                setMaterialName(content);
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Streamer getComponent() {
-        return streamer;
-    }
-
-}
-
diff --git a/src/net/sf/openrocket/file/rocksim/TipShapeCode.java b/src/net/sf/openrocket/file/rocksim/TipShapeCode.java
new file mode 100644 (file)
index 0000000..976bdc9
--- /dev/null
@@ -0,0 +1,38 @@
+package net.sf.openrocket.file.rocksim;
+
+import net.sf.openrocket.rocketcomponent.FinSet;
+
+/**
+ */
+public final class TipShapeCode {
+
+    /**
+     * Convert a Rocksim tip shape to an OpenRocket CrossSection.
+     *
+     * @param tipShape the tip shape code from Rocksim
+     *
+     * @return a CrossSection instance
+     */
+    public static FinSet.CrossSection convertTipShapeCode (int tipShape) {
+        switch (tipShape) {
+            case 0:
+                return FinSet.CrossSection.SQUARE;
+            case 1:
+                return FinSet.CrossSection.ROUNDED;
+            case 2:
+                return FinSet.CrossSection.AIRFOIL;
+            default:
+                return FinSet.CrossSection.SQUARE;
+        }
+    }
+
+    public static int convertTipShapeCode (FinSet.CrossSection cs) {
+        if (FinSet.CrossSection.ROUNDED.equals(cs)) {
+            return 1;
+        }
+        if (FinSet.CrossSection.AIRFOIL.equals(cs)) {
+            return 2;
+        }
+        return 0;
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/TransitionHandler.java b/src/net/sf/openrocket/file/rocksim/TransitionHandler.java
deleted file mode 100644 (file)
index 54ea323..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * TransitionHandler.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-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.RocketComponent;
-import net.sf.openrocket.rocketcomponent.Transition;
-import org.xml.sax.SAXException;
-
-import java.util.HashMap;
-
-/**
- * The SAX handler for Transition components.
- */
-class TransitionHandler extends BaseHandler<Transition> {
-    /**
-     * The OpenRocket Transition.
-     */
-    private final Transition transition = new Transition();
-
-    /**
-     * The wall thickness.  Used for hollow nose cones.
-     */
-    private double thickness = 0d;
-
-    /**
-     * Constructor.
-     *
-     * @param c the parent component
-     * @param warnings  the warning set
-     * @throws IllegalArgumentException thrown if <code>c</code> is null
-     */
-    public TransitionHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
-        if (c == null) {
-            throw new IllegalArgumentException("The parent of a transition may not be null.");
-        }
-        if (isCompatible(c, Transition.class, warnings)) {
-            c.addChild(transition);
-        }
-    }
-
-    @Override
-    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
-        return PlainTextHandler.INSTANCE;
-    }
-
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes,
-                             String content, WarningSet warnings) throws SAXException {
-        super.closeElement(element, attributes, content, warnings);
-
-        try {
-            if ("ShapeCode".equals(element)) {
-                transition.setType(RocksimNoseConeCode.fromCode(Integer.parseInt(content)).asOpenRocket());
-            }
-            if ("Len".equals(element)) {
-                transition.setLength(Math.max(0, Double.parseDouble(
-                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
-            }
-            if ("FrontDia".equals(element)) {
-                transition.setForeRadius(Math.max(0, Double.parseDouble(
-                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
-            }
-            if ("RearDia".equals(element)) {
-                transition.setAftRadius(Math.max(0, Double.parseDouble(
-                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
-            }
-            if ("WallThickness".equals(element)) {
-                thickness = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
-            }
-            if ("FrontShoulderDia".equals(element)) {
-                transition.setForeShoulderRadius(Math.max(0d, Double.parseDouble(
-                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
-            }
-            if ("RearShoulderDia".equals(element)) {
-                transition.setAftShoulderRadius(Math.max(0d, Double.parseDouble(
-                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
-            }
-            if ("FrontShoulderLen".equals(element)) {
-                transition.setForeShoulderLength(Math.max(0d, Double.parseDouble(
-                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
-            }
-            if ("RearShoulderLen".equals(element)) {
-                transition.setAftShoulderLength(Math.max(0d, Double.parseDouble(
-                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
-            }
-            if ("ShapeParameter".equals(element)) {
-                if (Transition.Shape.POWER.equals(transition.getType()) ||
-                    Transition.Shape.HAACK.equals(transition.getType()) ||
-                    Transition.Shape.PARABOLIC.equals(transition.getType())) {
-                    transition.setShapeParameter(Double.parseDouble(content));
-                }
-            }
-            if ("ConstructionType".equals(element)) {
-                int typeCode = Integer.parseInt(content);
-                if (typeCode == 0) {
-                    //SOLID
-                    transition.setFilled(true);
-                }
-                else if (typeCode == 1) {
-                    //HOLLOW
-                    transition.setFilled(false);
-                }
-            }
-            if ("FinishCode".equals(element)) {
-                transition.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket());
-            }
-            if ("Material".equals(element)) {
-                setMaterialName(content);
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    @Override
-    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        super.endHandler(element, attributes, content, warnings);
-
-        if (transition.isFilled()) {
-            transition.setAftShoulderThickness(transition.getAftShoulderRadius());
-            transition.setForeShoulderThickness(transition.getForeShoulderRadius());
-        }
-        else {
-            transition.setThickness(thickness);
-            transition.setAftShoulderThickness(thickness);
-            transition.setForeShoulderThickness(thickness);
-        }
-    }
-
-
-    @Override
-    public Transition getComponent() {
-        return transition;
-    }
-
-    /**
-     * Get the required type of material for this component.
-     *
-     * @return BULK
-     */
-    public Material.Type getMaterialType() {
-        return Material.Type.BULK;
-    }
-
-
-}
-
diff --git a/src/net/sf/openrocket/file/rocksim/export/AbstractTransitionDTO.java b/src/net/sf/openrocket/file/rocksim/export/AbstractTransitionDTO.java
new file mode 100644 (file)
index 0000000..ce5db24
--- /dev/null
@@ -0,0 +1,74 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.file.rocksim.importt.RocksimHandler;
+import net.sf.openrocket.file.rocksim.importt.RocksimNoseConeCode;
+import net.sf.openrocket.rocketcomponent.Transition;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+public class AbstractTransitionDTO extends BasePartDTO {
+    @XmlElement(name = "ShapeCode")
+    private int shapeCode = 1;
+    @XmlElement(name = "ConstructionType")
+    private int constructionType = 1;
+    @XmlElement(name = "WallThickness")
+    private double wallThickness = 0d;
+    @XmlElement(name = "ShapeParameter")
+    private double shapeParameter = 0d;
+
+    protected AbstractTransitionDTO() {
+
+    }
+
+    protected AbstractTransitionDTO(Transition nc) {
+        super(nc);
+        setConstructionType(nc.isFilled() ? 0 : 1);
+        setShapeCode(RocksimNoseConeCode.toCode(nc.getType()));
+
+        if (Transition.Shape.POWER.equals(nc.getType()) ||
+                Transition.Shape.HAACK.equals(nc.getType()) ||
+                Transition.Shape.PARABOLIC.equals(nc.getType())) {
+            setShapeParameter(nc.getShapeParameter());
+        }
+
+        setWallThickness(nc.getThickness() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+
+    }
+
+    public int getShapeCode() {
+        return shapeCode;
+    }
+
+    public void setShapeCode(int theShapeCode) {
+        shapeCode = theShapeCode;
+    }
+
+    public int getConstructionType() {
+        return constructionType;
+    }
+
+    public void setConstructionType(int theConstructionType) {
+        constructionType = theConstructionType;
+    }
+
+    public double getWallThickness() {
+        return wallThickness;
+    }
+
+    public void setWallThickness(double theWallThickness) {
+        wallThickness = theWallThickness;
+    }
+
+    public double getShapeParameter() {
+        return shapeParameter;
+    }
+
+    public void setShapeParameter(double theShapeParameter) {
+        shapeParameter = theShapeParameter;
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/BasePartDTO.java b/src/net/sf/openrocket/file/rocksim/export/BasePartDTO.java
new file mode 100644 (file)
index 0000000..48a4d91
--- /dev/null
@@ -0,0 +1,238 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.file.rocksim.importt.BaseHandler;
+import net.sf.openrocket.file.rocksim.importt.RocksimDensityType;
+import net.sf.openrocket.file.rocksim.importt.RocksimFinishCode;
+import net.sf.openrocket.file.rocksim.importt.RocksimHandler;
+import net.sf.openrocket.file.rocksim.importt.RocksimLocationMode;
+import net.sf.openrocket.rocketcomponent.ExternalComponent;
+import net.sf.openrocket.rocketcomponent.RecoveryDevice;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.StructuralComponent;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public abstract class BasePartDTO {
+
+    @XmlElement(name = "KnownMass")
+    private Double knownMass = 0d;
+    @XmlElement(name = "Density")
+    private double density = 0d;
+    @XmlElement(name = "Material")
+    private String material = "";
+    @XmlElement(name = "Name")
+    private String name = "";
+    @XmlElement(name = "KnownCG")
+    private Double knownCG = null;
+    @XmlElement(name = "UseKnownCG")
+    private int useKnownCG = 1;
+    @XmlElement(name = "Xb")
+    private double xb = 0;
+    @XmlElement(name = "CalcMass")
+    private double calcMass = 0d;
+    @XmlElement(name = "CalcCG")
+    private double calcCG = 0d;
+    @XmlElement(name = "DensityType")
+    private int densityType = 0;
+    @XmlElement(name = "RadialLoc")
+    private String radialLoc = "0.";
+    @XmlElement(name = "RadialAngle")
+    private double radialAngle = 0;
+    @XmlElement(name = "LocationMode")
+    private int locationMode = 0;
+    @XmlElement(name = "Len")
+    private double len = 0d;
+    @XmlElement(name = "FinishCode")
+    private int finishCode = 0;
+
+    protected BasePartDTO() {
+    }
+
+    protected BasePartDTO(RocketComponent ec) {
+        setCalcCG(ec.getCG().x * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setCalcMass(ec.getComponentMass() * RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
+        setKnownCG(ec.getOverrideCGX() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setKnownMass(ec.getOverrideMass() * RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
+        setLen(ec.getLength() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setUseKnownCG(ec.isCGOverridden() || ec.isMassOverridden() ? 1 : 0);
+        setName(ec.getName());
+
+        setXb(ec.getPositionValue() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        if (ec instanceof ExternalComponent) {
+            ExternalComponent comp = (ExternalComponent) ec;
+            setLocationMode(RocksimLocationMode.toCode(comp.getRelativePosition()));
+
+            if (comp.getRelativePosition().equals(RocketComponent.Position.BOTTOM)) {
+                setXb(-1 * getXb());
+            }
+            setDensity(comp.getMaterial().getDensity() * RocksimHandler.ROCKSIM_TO_OPENROCKET_BULK_DENSITY);
+            setDensityType(RocksimDensityType.toCode(comp.getMaterial().getType()));
+            String material = comp.getMaterial().getName();
+            if (material.startsWith(BaseHandler.ROCKSIM_MATERIAL_PREFIX)) {
+                material = material.substring(BaseHandler.ROCKSIM_MATERIAL_PREFIX.length());
+            }
+            setMaterial(material);
+
+            setFinishCode(RocksimFinishCode.toCode(comp.getFinish()));
+        }
+        else if (ec instanceof StructuralComponent) {
+            StructuralComponent comp = (StructuralComponent) ec;
+
+            setLocationMode(RocksimLocationMode.toCode(comp.getRelativePosition()));
+            if (comp.getRelativePosition().equals(RocketComponent.Position.BOTTOM)) {
+                setXb(-1 * getXb());
+            }
+            setDensity(comp.getMaterial().getDensity() * RocksimHandler.ROCKSIM_TO_OPENROCKET_BULK_DENSITY);
+            setDensityType(RocksimDensityType.toCode(comp.getMaterial().getType()));
+            String material = comp.getMaterial().getName();
+            if (material.startsWith(BaseHandler.ROCKSIM_MATERIAL_PREFIX)) {
+                material = material.substring(BaseHandler.ROCKSIM_MATERIAL_PREFIX.length());
+            }
+            setMaterial(material);
+        }
+        else if (ec instanceof RecoveryDevice) {
+            RecoveryDevice comp = (RecoveryDevice) ec;
+
+            setLocationMode(RocksimLocationMode.toCode(comp.getRelativePosition()));
+            if (comp.getRelativePosition().equals(RocketComponent.Position.BOTTOM)) {
+                setXb(-1 * getXb());
+            }
+            setDensity(comp.getMaterial().getDensity() * RocksimHandler.ROCKSIM_TO_OPENROCKET_SURFACE_DENSITY);
+            setDensityType(RocksimDensityType.toCode(comp.getMaterial().getType()));
+            String material = comp.getMaterial().getName();
+            if (material.startsWith(BaseHandler.ROCKSIM_MATERIAL_PREFIX)) {
+                material = material.substring(BaseHandler.ROCKSIM_MATERIAL_PREFIX.length());
+            }
+            setMaterial(material);
+
+        }
+    }
+
+    public Double getKnownMass() {
+        return knownMass;
+    }
+
+    public void setKnownMass(Double theKnownMass) {
+        knownMass = theKnownMass;
+    }
+
+    public double getDensity() {
+        return density;
+    }
+
+    public void setDensity(double theDensity) {
+        density = theDensity;
+    }
+
+    public String getMaterial() {
+        return material;
+    }
+
+    public void setMaterial(String theMaterial) {
+        material = theMaterial;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String theName) {
+        name = theName;
+    }
+
+    public Double getKnownCG() {
+        return knownCG;
+    }
+
+    public void setKnownCG(Double theKnownCG) {
+        knownCG = theKnownCG;
+    }
+
+    public int getUseKnownCG() {
+        return useKnownCG;
+    }
+
+    public void setUseKnownCG(int theUseKnownCG) {
+        useKnownCG = theUseKnownCG;
+    }
+
+    public double getXb() {
+        return xb;
+    }
+
+    public void setXb(double theXb) {
+        xb = theXb;
+    }
+
+    public double getCalcMass() {
+        return calcMass;
+    }
+
+    public void setCalcMass(double theCalcMass) {
+        calcMass = theCalcMass;
+    }
+
+    public double getCalcCG() {
+        return calcCG;
+    }
+
+    public void setCalcCG(double theCalcCG) {
+        calcCG = theCalcCG;
+    }
+
+    public int getDensityType() {
+        return densityType;
+    }
+
+    public void setDensityType(int theDensityType) {
+        densityType = theDensityType;
+    }
+
+    public String getRadialLoc() {
+        return radialLoc;
+    }
+
+    public void setRadialLoc(String theRadialLoc) {
+        radialLoc = theRadialLoc;
+    }
+
+    public double getRadialAngle() {
+        return radialAngle;
+    }
+
+    public void setRadialAngle(double theRadialAngle) {
+        radialAngle = theRadialAngle;
+    }
+
+    public int getLocationMode() {
+        return locationMode;
+    }
+
+    public void setLocationMode(int theLocationMode) {
+        locationMode = theLocationMode;
+    }
+
+    public double getLen() {
+        return len;
+    }
+
+    public void setLen(double theLen) {
+        len = theLen;
+    }
+
+    public int getFinishCode() {
+        return finishCode;
+    }
+
+    public void setFinishCode(int theFinishCode) {
+        finishCode = theFinishCode;
+    }
+
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/BodyTubeDTO.java b/src/net/sf/openrocket/file/rocksim/export/BodyTubeDTO.java
new file mode 100644 (file)
index 0000000..f9325d8
--- /dev/null
@@ -0,0 +1,182 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.file.rocksim.importt.RocksimHandler;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.Bulkhead;
+import net.sf.openrocket.rocketcomponent.CenteringRing;
+import net.sf.openrocket.rocketcomponent.EngineBlock;
+import net.sf.openrocket.rocketcomponent.FinSet;
+import net.sf.openrocket.rocketcomponent.FreeformFinSet;
+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.RocketComponent;
+import net.sf.openrocket.rocketcomponent.Streamer;
+import net.sf.openrocket.rocketcomponent.Transition;
+import net.sf.openrocket.rocketcomponent.TubeCoupler;
+
+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;
+
+/**
+ */
+@XmlRootElement(name = "BodyTube")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class BodyTubeDTO extends BasePartDTO {
+
+    @XmlElement(name = "OD")
+    private double od = 0d;
+    @XmlElement(name = "ID")
+    private double id = 0d;
+    @XmlElement(name = "IsMotorMount")
+    private int isMotorMount = 0;
+    @XmlElement(name = "MotorDia")
+    private double motorDia = 0d;
+    @XmlElement(name = "EngineOverhang")
+    private double engineOverhang = 0d;
+    @XmlElement(name = "IsInsideTube")
+    private int isInsideTube = 0;
+    @XmlElementWrapper(name = "AttachedParts")
+    @XmlElementRefs({
+            @XmlElementRef(name = "BodyTube", type = BodyTubeDTO.class),
+            @XmlElementRef(name = "BodyTube", type = InnerBodyTubeDTO.class),
+            @XmlElementRef(name = "Ring", type = CenteringRingDTO.class),
+            @XmlElementRef(name = "LaunchLug", type = LaunchLugDTO.class),
+            @XmlElementRef(name = "FinSet", type = FinSetDTO.class),
+            @XmlElementRef(name = "CustomFinSet", type = CustomFinSetDTO.class),
+            @XmlElementRef(name = "Streamer", type = StreamerDTO.class),
+            @XmlElementRef(name = "Parachute", type = ParachuteDTO.class),
+            @XmlElementRef(name = "MassObject", type = MassObjectDTO.class)})
+    List<BasePartDTO> attachedParts = new ArrayList<BasePartDTO>();
+
+    public BodyTubeDTO() {
+    }
+
+    public BodyTubeDTO(InnerTube inner) {
+        super(inner);
+    }
+
+    public BodyTubeDTO(BodyTube bt) {
+        super(bt);
+
+        setEngineOverhang(bt.getMotorOverhang() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setId(bt.getInnerRadius() * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setOd(bt.getOuterRadius() * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setMotorDia((bt.getMotorMountDiameter() / 2) * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setMotorMount(bt.isMotorMount());
+
+        List<RocketComponent> children = bt.getChildren();
+        for (int i = 0; i < children.size(); i++) {
+            RocketComponent rocketComponents = children.get(i);
+            if (rocketComponents instanceof InnerTube) {
+                attachedParts.add(new InnerBodyTubeDTO((InnerTube) rocketComponents));
+            } else if (rocketComponents instanceof BodyTube) {
+                attachedParts.add(new BodyTubeDTO((BodyTube) rocketComponents));
+            } else if (rocketComponents instanceof Transition) {
+                attachedParts.add(new TransitionDTO((Transition) rocketComponents));
+            } else if (rocketComponents instanceof EngineBlock) {
+                attachedParts.add(new EngineBlockDTO((EngineBlock) rocketComponents));
+            } else if (rocketComponents instanceof TubeCoupler) {
+                attachedParts.add(new TubeCouplerDTO((TubeCoupler) rocketComponents));
+            } else if (rocketComponents instanceof CenteringRing) {
+                attachedParts.add(new CenteringRingDTO((CenteringRing) rocketComponents));
+            } else if (rocketComponents instanceof Bulkhead) {
+                attachedParts.add(new BulkheadDTO((Bulkhead) rocketComponents));
+            } else if (rocketComponents instanceof LaunchLug) {
+                attachedParts.add(new LaunchLugDTO((LaunchLug) rocketComponents));
+            } else if (rocketComponents instanceof Streamer) {
+                attachedParts.add(new StreamerDTO((Streamer) rocketComponents));
+            } else if (rocketComponents instanceof Parachute) {
+                attachedParts.add(new ParachuteDTO((Parachute) rocketComponents));
+            } else if (rocketComponents instanceof MassObject) {
+                attachedParts.add(new MassObjectDTO((MassObject) rocketComponents));
+            } else if (rocketComponents instanceof FreeformFinSet) {
+                attachedParts.add(new CustomFinSetDTO((FreeformFinSet) rocketComponents));
+            } else if (rocketComponents instanceof FinSet) {
+                attachedParts.add(new FinSetDTO((FinSet) rocketComponents));
+            }
+            
+        }
+    }
+
+    public double getOd() {
+        return od;
+    }
+
+    public void setOd(double theOd) {
+        od = theOd;
+    }
+
+    public double getId() {
+        return id;
+    }
+
+    public void setId(double theId) {
+        id = theId;
+    }
+
+    public int getMotorMount() {
+        return isMotorMount;
+    }
+
+    public void setMotorMount(boolean motorMount) {
+        if (motorMount) {
+            isMotorMount = 1;
+        } else {
+            isMotorMount = 0;
+        }
+
+    }
+
+    public void setMotorMount(int theMotorMount) {
+        isMotorMount = theMotorMount;
+    }
+
+    public double getMotorDia() {
+        return motorDia;
+    }
+
+    public void setMotorDia(double theMotorDia) {
+        motorDia = theMotorDia;
+    }
+
+    public double getEngineOverhang() {
+        return engineOverhang;
+    }
+
+    public void setEngineOverhang(double theEngineOverhang) {
+        engineOverhang = theEngineOverhang;
+    }
+
+    public int getInsideTube() {
+        return isInsideTube;
+    }
+
+    public void setInsideTube(boolean inside) {
+        if (inside) {
+            isInsideTube = 1;
+        } else {
+            isInsideTube = 0;
+        }
+    }
+
+    public void setInsideTube(int theInsideTube) {
+        isInsideTube = theInsideTube;
+    }
+
+    public List<BasePartDTO> getAttachedParts() {
+        return attachedParts;
+    }
+
+    public void addAttachedParts(BasePartDTO thePart) {
+        attachedParts.add(thePart);
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/BulkheadDTO.java b/src/net/sf/openrocket/file/rocksim/export/BulkheadDTO.java
new file mode 100644 (file)
index 0000000..c5a82bf
--- /dev/null
@@ -0,0 +1,18 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.rocketcomponent.Bulkhead;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ */
+@XmlRootElement(name = "Ring")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class BulkheadDTO extends CenteringRingDTO {
+    public BulkheadDTO(Bulkhead bh) {
+        super(bh);
+        setUsageCode(CenteringRingDTO.UsageCode.Bulkhead);
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/CenteringRingDTO.java b/src/net/sf/openrocket/file/rocksim/export/CenteringRingDTO.java
new file mode 100644 (file)
index 0000000..e2e8a7c
--- /dev/null
@@ -0,0 +1,94 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.file.rocksim.importt.RocksimHandler;
+import net.sf.openrocket.rocketcomponent.RadiusRingComponent;
+import net.sf.openrocket.rocketcomponent.ThicknessRingComponent;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+/**
+ */
+@XmlRootElement(name = "Ring")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CenteringRingDTO extends BasePartDTO {
+
+    @XmlTransient
+    protected enum UsageCode {
+        //UsageCode
+        CenteringRing(0),
+        Bulkhead(1),
+        EngineBlock(2),
+        Sleeve(3),
+        TubeCoupler(4);
+
+        int ordinal;
+
+        UsageCode(int x) {
+            ordinal = x;
+        }
+    }
+
+    @XmlElement(name = "OD")
+    private double od = 0d;
+    @XmlElement(name = "ID")
+    private double id = 0d;
+    @XmlElement(name = "UsageCode")
+    private int usageCode = UsageCode.CenteringRing.ordinal;
+    @XmlElement(name = "AutoSize")
+    private int autoSize = 0;
+
+    public CenteringRingDTO() {
+
+    }
+    public CenteringRingDTO(RadiusRingComponent cr) {
+        super(cr);
+        setId(cr.getInnerRadius()* RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setOd(cr.getOuterRadius()* RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+    }
+
+    public CenteringRingDTO(ThicknessRingComponent trc) {
+        super(trc);
+        setId(trc.getInnerRadius()* RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setOd(trc.getOuterRadius()* RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+    }
+    public double getOd() {
+        return od;
+    }
+
+    public void setOd(double theOd) {
+        od = theOd;
+    }
+
+    public double getId() {
+        return id;
+    }
+
+    public void setId(double theId) {
+        id = theId;
+    }
+
+    public int getUsageCode() {
+        return usageCode;
+    }
+
+    public void setUsageCode(int theUsageCode) {
+        usageCode = theUsageCode;
+    }
+
+    public void setUsageCode(UsageCode theUsageCode) {
+        usageCode = theUsageCode.ordinal;
+    }
+
+    public int getAutoSize() {
+        return autoSize;
+    }
+
+    public void setAutoSize(int theAutoSize) {
+        autoSize = theAutoSize;
+    }
+
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/CustomFinSetDTO.java b/src/net/sf/openrocket/file/rocksim/export/CustomFinSetDTO.java
new file mode 100644 (file)
index 0000000..99112c9
--- /dev/null
@@ -0,0 +1,48 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.file.rocksim.importt.RocksimHandler;
+import net.sf.openrocket.rocketcomponent.FreeformFinSet;
+import net.sf.openrocket.util.Coordinate;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ */
+@XmlRootElement(name = "CustomFinSet")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CustomFinSetDTO extends FinSetDTO {
+
+    @XmlElement(name = "PointList")
+    private String pointList = "";
+
+    public CustomFinSetDTO() {
+    }
+
+    public CustomFinSetDTO(FreeformFinSet ec) {
+        super(ec);
+        setPointList(convertFreeFormPoints(ec.getFinPoints()));
+    }
+
+
+    private String convertFreeFormPoints(Coordinate[] points) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < points.length; i++) {
+            Coordinate point = points[i];
+            sb.append(point.x * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH).append(",")
+                    .append(point.y * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH).append("|");
+        }
+        return sb.toString();
+    }
+
+    public String getPointList() {
+        return pointList;
+    }
+
+    public void setPointList(String thePointList) {
+        pointList = thePointList;
+    }
+}
+
diff --git a/src/net/sf/openrocket/file/rocksim/export/EngineBlockDTO.java b/src/net/sf/openrocket/file/rocksim/export/EngineBlockDTO.java
new file mode 100644 (file)
index 0000000..bcb6d57
--- /dev/null
@@ -0,0 +1,19 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.rocketcomponent.EngineBlock;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ */
+@XmlRootElement(name = "Ring")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class EngineBlockDTO extends CenteringRingDTO{
+    
+    public EngineBlockDTO(EngineBlock eb) {
+        super(eb);
+        setUsageCode(UsageCode.EngineBlock);
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/FinSetDTO.java b/src/net/sf/openrocket/file/rocksim/export/FinSetDTO.java
new file mode 100644 (file)
index 0000000..b97571c
--- /dev/null
@@ -0,0 +1,191 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.file.rocksim.TipShapeCode;
+import net.sf.openrocket.file.rocksim.importt.RocksimHandler;
+import net.sf.openrocket.rocketcomponent.EllipticalFinSet;
+import net.sf.openrocket.rocketcomponent.FinSet;
+import net.sf.openrocket.rocketcomponent.FreeformFinSet;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ */
+@XmlRootElement(name = "FinSet")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class FinSetDTO extends BasePartDTO {
+
+    @XmlElement(name = "FinCount")
+    private int finCount = 0;
+    @XmlElement(name = "RootChord")
+    private double rootChord = 0d;
+    @XmlElement(name = "TipChord")
+    private double tipChord = 0d;
+    @XmlElement(name = "SemiSpan")
+    private double semiSpan = 0d;
+    @XmlElement(name = "SweepDistance")
+    private double sweepDistance = 0d;
+    @XmlElement(name = "Thickness")
+    private double thickness = 0d;
+    @XmlElement(name = "ShapeCode")
+    private int shapeCode = 0;
+    @XmlElement(name = "TipShapeCode")
+    private int tipShapeCode = 0;
+    @XmlElement(name = "TabLength")
+    private double tabLength = 0d;
+    @XmlElement(name = "TabDepth")
+    private double tabDepth = 0d;
+    @XmlElement(name = "TabOffset")
+    private double tabOffset = 0d;
+    @XmlElement(name = "SweepMode")
+    private int sweepMode = 1;
+    @XmlElement(name = "CantAngle")
+    private double cantAngle = 0d;
+
+    public FinSetDTO() {
+    }
+
+    public FinSetDTO(FinSet ec) {
+        super(ec);
+
+        setCantAngle(ec.getCantAngle());
+        setFinCount(ec.getFinCount());
+        setRootChord(ec.getLength() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setTabDepth(ec.getTabHeight() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setTabLength(ec.getTabLength() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setTabOffset(ec.getTabShift() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setThickness(ec.getThickness() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+
+        if (ec.getRelativePosition().equals(RocketComponent.Position.BOTTOM)) {
+            setXb(getXb() + getLen());
+        }
+
+        setRadialAngle(ec.getBaseRotation());
+        setTipShapeCode(TipShapeCode.convertTipShapeCode(ec.getCrossSection()));
+        if (ec instanceof TrapezoidFinSet) {
+            TrapezoidFinSet tfs = (TrapezoidFinSet) ec;
+            setShapeCode(0);
+            setSemiSpan(tfs.getHeight() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            setTipChord(tfs.getTipChord() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            setSweepDistance(tfs.getSweep() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            setLen(tfs.getLength());
+        }
+        else if (ec instanceof EllipticalFinSet) {
+            EllipticalFinSet efs = (EllipticalFinSet) ec;
+            setShapeCode(1);
+            setSemiSpan(efs.getHeight() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            setLen(efs.getLength() *RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        }
+        else if (ec instanceof FreeformFinSet) {
+            setShapeCode(2);
+        }
+    }
+
+    public int getFinCount() {
+        return finCount;
+    }
+
+    public void setFinCount(int theFinCount) {
+        finCount = theFinCount;
+    }
+
+    public double getRootChord() {
+        return rootChord;
+    }
+
+    public void setRootChord(double theRootChord) {
+        rootChord = theRootChord;
+    }
+
+    public double getTipChord() {
+        return tipChord;
+    }
+
+    public void setTipChord(double theTipChord) {
+        tipChord = theTipChord;
+    }
+
+    public double getSemiSpan() {
+        return semiSpan;
+    }
+
+    public void setSemiSpan(double theSemiSpan) {
+        semiSpan = theSemiSpan;
+    }
+
+    public double getSweepDistance() {
+        return sweepDistance;
+    }
+
+    public void setSweepDistance(double theSweepDistance) {
+        sweepDistance = theSweepDistance;
+    }
+
+    public double getThickness() {
+        return thickness;
+    }
+
+    public void setThickness(double theThickness) {
+        thickness = theThickness;
+    }
+
+    public int getShapeCode() {
+        return shapeCode;
+    }
+
+    public void setShapeCode(int theShapeCode) {
+        shapeCode = theShapeCode;
+    }
+
+    public int getTipShapeCode() {
+        return tipShapeCode;
+    }
+
+    public void setTipShapeCode(int theTipShapeCode) {
+        tipShapeCode = theTipShapeCode;
+    }
+
+    public double getTabLength() {
+        return tabLength;
+    }
+
+    public void setTabLength(double theTabLength) {
+        tabLength = theTabLength;
+    }
+
+    public double getTabDepth() {
+        return tabDepth;
+    }
+
+    public void setTabDepth(double theTabDepth) {
+        tabDepth = theTabDepth;
+    }
+
+    public double getTabOffset() {
+        return tabOffset;
+    }
+
+    public void setTabOffset(double theTabOffset) {
+        tabOffset = theTabOffset;
+    }
+
+    public int getSweepMode() {
+        return sweepMode;
+    }
+
+    public void setSweepMode(int theSweepMode) {
+        sweepMode = theSweepMode;
+    }
+
+    public double getCantAngle() {
+        return cantAngle;
+    }
+
+    public void setCantAngle(double theCantAngle) {
+        cantAngle = theCantAngle;
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/InnerBodyTubeDTO.java b/src/net/sf/openrocket/file/rocksim/export/InnerBodyTubeDTO.java
new file mode 100644 (file)
index 0000000..c898abb
--- /dev/null
@@ -0,0 +1,66 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.file.rocksim.importt.RocksimHandler;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.Bulkhead;
+import net.sf.openrocket.rocketcomponent.CenteringRing;
+import net.sf.openrocket.rocketcomponent.EngineBlock;
+import net.sf.openrocket.rocketcomponent.InnerTube;
+import net.sf.openrocket.rocketcomponent.MassObject;
+import net.sf.openrocket.rocketcomponent.Parachute;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.Streamer;
+import net.sf.openrocket.rocketcomponent.Transition;
+import net.sf.openrocket.rocketcomponent.TubeCoupler;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+/**
+ */
+@XmlRootElement(name = "BodyTube")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class InnerBodyTubeDTO extends BodyTubeDTO {
+
+    public InnerBodyTubeDTO() {
+        super.setInsideTube(true);
+    }
+
+    public InnerBodyTubeDTO(InnerTube bt) {
+        super(bt);
+        setEngineOverhang(bt.getMotorOverhang() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setId(bt.getInnerRadius() * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setOd(bt.getOuterRadius() * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setMotorDia((bt.getMotorMountDiameter() / 2) * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setMotorMount(bt.isMotorMount());
+
+        List<RocketComponent> children = bt.getChildren();
+        for (int i = 0; i < children.size(); i++) {
+            RocketComponent rocketComponents = children.get(i);
+            if (rocketComponents instanceof InnerTube) {
+                attachedParts.add(new InnerBodyTubeDTO((InnerTube) rocketComponents));
+            } else if (rocketComponents instanceof BodyTube) {
+                attachedParts.add(new BodyTubeDTO((BodyTube) rocketComponents));
+            } else if (rocketComponents instanceof Transition) {
+                attachedParts.add(new TransitionDTO((Transition) rocketComponents));
+            } else if (rocketComponents instanceof EngineBlock) {
+                attachedParts.add(new EngineBlockDTO((EngineBlock) rocketComponents));
+            } else if (rocketComponents instanceof TubeCoupler) {
+                attachedParts.add(new TubeCouplerDTO((TubeCoupler) rocketComponents));
+            } else if (rocketComponents instanceof CenteringRing) {
+                attachedParts.add(new CenteringRingDTO((CenteringRing) rocketComponents));
+            } else if (rocketComponents instanceof Bulkhead) {
+                attachedParts.add(new BulkheadDTO((Bulkhead) rocketComponents));
+            } else if (rocketComponents instanceof Streamer) {
+                attachedParts.add(new StreamerDTO((Streamer) rocketComponents));
+            } else if (rocketComponents instanceof Parachute) {
+                attachedParts.add(new ParachuteDTO((Parachute) rocketComponents));
+            } else if (rocketComponents instanceof MassObject) {
+                attachedParts.add(new MassObjectDTO((MassObject) rocketComponents));
+            }
+        }
+        setInsideTube(true);
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/LaunchLugDTO.java b/src/net/sf/openrocket/file/rocksim/export/LaunchLugDTO.java
new file mode 100644 (file)
index 0000000..f2932c8
--- /dev/null
@@ -0,0 +1,47 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.file.rocksim.importt.RocksimHandler;
+import net.sf.openrocket.rocketcomponent.LaunchLug;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ */
+@XmlRootElement(name = "LaunchLug")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class LaunchLugDTO extends BasePartDTO {
+
+    @XmlElement(name = "OD")
+    private double od = 0d;
+    @XmlElement(name = "ID")
+    private double id = 0d;
+
+    public LaunchLugDTO() {
+    }
+
+    public LaunchLugDTO(LaunchLug ec) {
+        super(ec);
+        setId(ec.getInnerRadius() * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setOd(ec.getOuterRadius() * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setRadialAngle(ec.getRadialDirection());
+    }
+
+    public double getOd() {
+        return od;
+    }
+
+    public void setOd(double theOd) {
+        od = theOd;
+    }
+
+    public double getId() {
+        return id;
+    }
+
+    public void setId(double theId) {
+        id = theId;
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/MassObjectDTO.java b/src/net/sf/openrocket/file/rocksim/export/MassObjectDTO.java
new file mode 100644 (file)
index 0000000..ea48844
--- /dev/null
@@ -0,0 +1,25 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.rocketcomponent.MassObject;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ */
+@XmlRootElement(name = "MassObject")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class MassObjectDTO extends BasePartDTO{
+
+    @XmlElement(name = "TypeCode")
+    private int typeCode = 0;
+
+    public MassObjectDTO() {
+    }
+
+    public MassObjectDTO(MassObject ec) {
+        super(ec);
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/NoseConeDTO.java b/src/net/sf/openrocket/file/rocksim/export/NoseConeDTO.java
new file mode 100644 (file)
index 0000000..4a154db
--- /dev/null
@@ -0,0 +1,114 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.file.rocksim.importt.RocksimHandler;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.Bulkhead;
+import net.sf.openrocket.rocketcomponent.CenteringRing;
+import net.sf.openrocket.rocketcomponent.EngineBlock;
+import net.sf.openrocket.rocketcomponent.FinSet;
+import net.sf.openrocket.rocketcomponent.FreeformFinSet;
+import net.sf.openrocket.rocketcomponent.InnerTube;
+import net.sf.openrocket.rocketcomponent.MassObject;
+import net.sf.openrocket.rocketcomponent.NoseCone;
+import net.sf.openrocket.rocketcomponent.Parachute;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.Transition;
+import net.sf.openrocket.rocketcomponent.TubeCoupler;
+
+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;
+
+/**
+ */
+@XmlRootElement(name = "NoseCone")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class NoseConeDTO extends AbstractTransitionDTO {
+
+
+    @XmlElement(name = "BaseDia")
+    private double baseDia = 0d;
+    @XmlElement(name = "ShoulderLen")
+    private double shoulderLen = 0d;
+    @XmlElement(name = "ShoulderOD")
+    private double shoulderOD = 0d;
+
+    @XmlElementWrapper(name = "AttachedParts")
+    @XmlElementRefs({
+            @XmlElementRef(name = "BodyTube", type = BodyTubeDTO.class),
+            @XmlElementRef(name = "BodyTube", type = InnerBodyTubeDTO.class),
+            @XmlElementRef(name = "FinSet", type = FinSetDTO.class),
+            @XmlElementRef(name = "CustomFinSet", type = CustomFinSetDTO.class),
+            @XmlElementRef(name = "Ring", type = CenteringRingDTO.class),
+            @XmlElementRef(name = "Parachute", type = ParachuteDTO.class),
+            @XmlElementRef(name = "MassObject", type = MassObjectDTO.class)})
+    List<BasePartDTO> attachedParts = new ArrayList<BasePartDTO>();
+
+    public NoseConeDTO() {
+    }
+
+    public NoseConeDTO(NoseCone nc) {
+        super(nc);
+        setBaseDia(nc.getAftRadius() * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setShoulderLen(nc.getAftShoulderLength() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setShoulderOD(nc.getAftShoulderRadius() * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+
+        List<RocketComponent> children = nc.getChildren();
+        for (int i = 0; i < children.size(); i++) {
+            RocketComponent rocketComponents = children.get(i);
+            if (rocketComponents instanceof InnerTube) {
+                attachedParts.add(new InnerBodyTubeDTO((InnerTube) rocketComponents));
+            } else if (rocketComponents instanceof BodyTube) {
+                attachedParts.add(new BodyTubeDTO((BodyTube) rocketComponents));
+            } else if (rocketComponents instanceof Transition) {
+                attachedParts.add(new TransitionDTO((Transition) rocketComponents));
+            } else if (rocketComponents instanceof EngineBlock) {
+                attachedParts.add(new EngineBlockDTO((EngineBlock) rocketComponents));
+            } else if (rocketComponents instanceof TubeCoupler) {
+                attachedParts.add(new TubeCouplerDTO((TubeCoupler) rocketComponents));
+            } else if (rocketComponents instanceof CenteringRing) {
+                attachedParts.add(new CenteringRingDTO((CenteringRing) rocketComponents));
+            } else if (rocketComponents instanceof Bulkhead) {
+                attachedParts.add(new BulkheadDTO((Bulkhead) rocketComponents));
+            } else if (rocketComponents instanceof Parachute) {
+                attachedParts.add(new ParachuteDTO((Parachute) rocketComponents));
+            } else if (rocketComponents instanceof MassObject) {
+                attachedParts.add(new MassObjectDTO((MassObject) rocketComponents));
+            } else if (rocketComponents instanceof FreeformFinSet) {
+                attachedParts.add(new CustomFinSetDTO((FreeformFinSet) rocketComponents));
+            } else if (rocketComponents instanceof FinSet) {
+                attachedParts.add(new FinSetDTO((FinSet) rocketComponents));
+            }
+        }
+    }
+
+    public double getBaseDia() {
+        return baseDia;
+    }
+
+    public void setBaseDia(double theBaseDia) {
+        baseDia = theBaseDia;
+    }
+
+    public double getShoulderLen() {
+        return shoulderLen;
+    }
+
+    public void setShoulderLen(double theShoulderLen) {
+        shoulderLen = theShoulderLen;
+    }
+
+    public double getShoulderOD() {
+        return shoulderOD;
+    }
+
+    public void setShoulderOD(double theShoulderOD) {
+        shoulderOD = theShoulderOD;
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/ParachuteDTO.java b/src/net/sf/openrocket/file/rocksim/export/ParachuteDTO.java
new file mode 100644 (file)
index 0000000..eb61222
--- /dev/null
@@ -0,0 +1,129 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.file.rocksim.importt.BaseHandler;
+import net.sf.openrocket.file.rocksim.importt.RocksimHandler;
+import net.sf.openrocket.rocketcomponent.Parachute;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ */
+@XmlRootElement(name = "Parachute")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ParachuteDTO extends BasePartDTO {
+
+    @XmlElement(name = "Dia")
+    private double dia = 0d;
+    @XmlElement(name = "SpillHoleDia")
+    private double spillHoleDia = 0d;
+    @XmlElement(name = "ShroudLineCount")
+    private int ShroudLineCount = 0;
+    @XmlElement(name = "Thickness")
+    private double thickness = 0d;
+    @XmlElement(name = "ShroudLineLen")
+    private double shroudLineLen = 0d;
+    @XmlElement(name = "ChuteCount")
+    private int chuteCount = 1;
+    @XmlElement(name = "ShroudLineMassPerMM")
+    private double shroudLineMassPerMM = 0d;
+    @XmlElement(name = "ShroudLineMaterial")
+    private String shroudLineMaterial = "";
+    @XmlElement(name = "DragCoefficient")
+    private double dragCoefficient = 0.75d;
+    
+    public ParachuteDTO() {
+    }
+
+    public ParachuteDTO(Parachute ec) {
+        super(ec);
+        
+        setChuteCount(1);
+        setDia(ec.getDiameter() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setDragCoefficient(ec.getCD());
+        setShroudLineCount(ec.getLineCount());
+        setShroudLineLen(ec.getLineLength() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+
+        String material = ec.getLineMaterial().getName();
+        setShroudLineMassPerMM(ec.getLineMaterial().getDensity() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LINE_DENSITY);
+
+        if (material.startsWith(BaseHandler.ROCKSIM_MATERIAL_PREFIX)) {
+            material = material.substring(BaseHandler.ROCKSIM_MATERIAL_PREFIX.length());
+        }
+        setShroudLineMaterial(material);
+    }
+
+    public double getDia() {
+        return dia;
+    }
+
+    public void setDia(double theDia) {
+        dia = theDia;
+    }
+
+    public double getSpillHoleDia() {
+        return spillHoleDia;
+    }
+
+    public void setSpillHoleDia(double theSpillHoleDia) {
+        spillHoleDia = theSpillHoleDia;
+    }
+
+    public int getShroudLineCount() {
+        return ShroudLineCount;
+    }
+
+    public void setShroudLineCount(int theShroudLineCount) {
+        ShroudLineCount = theShroudLineCount;
+    }
+
+    public double getThickness() {
+        return thickness;
+    }
+
+    public void setThickness(double theThickness) {
+        thickness = theThickness;
+    }
+
+    public double getShroudLineLen() {
+        return shroudLineLen;
+    }
+
+    public void setShroudLineLen(double theShroudLineLen) {
+        shroudLineLen = theShroudLineLen;
+    }
+
+    public int getChuteCount() {
+        return chuteCount;
+    }
+
+    public void setChuteCount(int theChuteCount) {
+        chuteCount = theChuteCount;
+    }
+
+    public double getShroudLineMassPerMM() {
+        return shroudLineMassPerMM;
+    }
+
+    public void setShroudLineMassPerMM(double theShroudLineMassPerMM) {
+        shroudLineMassPerMM = theShroudLineMassPerMM;
+    }
+
+    public String getShroudLineMaterial() {
+        return shroudLineMaterial;
+    }
+
+    public void setShroudLineMaterial(String theShroudLineMaterial) {
+        shroudLineMaterial = theShroudLineMaterial;
+    }
+
+    public double getDragCoefficient() {
+        return dragCoefficient;
+    }
+
+    public void setDragCoefficient(double theDragCoefficient) {
+        dragCoefficient = theDragCoefficient;
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/RocketDesignDTO.java b/src/net/sf/openrocket/file/rocksim/export/RocketDesignDTO.java
new file mode 100644 (file)
index 0000000..9abc446
--- /dev/null
@@ -0,0 +1,94 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RocketDesignDTO {
+
+    @XmlElement(name = "Name")
+    private String name;
+    @XmlElement(name = "StageCount")
+    private int stageCount = 1;
+    @XmlElement(name = "ViewType")
+    private int viewType = 0;
+    @XmlElement(name = "ViewStageCount")
+    private int viewStageCount = 3;
+    @XmlElement(name = "ViewTypeEdit")
+    private int viewTypeEdit = 0;
+    @XmlElement(name = "ViewStageCountEdit")
+    private int viewStageCountEdit = 3;
+    @XmlElement(name = "ZoomFactor")
+    private double zoomFactor = 0d;
+    @XmlElement (name = "ZoomFactorEdit")
+    private double zoomFactorEdit = 0d;
+    @XmlElement(name = "ScrollPosX")
+    private int scrollPosX = 0;
+    @XmlElement(name = "ScrollPosY")
+    private int scrollPosY = 0;
+    @XmlElement(name = "ScrollPosXEdit")
+    private int scrollPosXEdit = 0;
+    @XmlElement(name = "ScrollPosYEdit")
+    private int scrollPosYEdit = 0;
+    @XmlElement(name = "ThreeDFlags")
+    private int threeDFlags = 0;
+    @XmlElement(name = "ThreeDFlagsEdit")
+    private int threeDFlagsEdit = 0;
+
+    @XmlElement(name = "CPCalcFlags")
+    private String cpCalcFlags = "1";
+    @XmlElement(name = "UseKnownMass")
+    private String useKnownMass = "0";
+    @XmlElement(name = "Stage3Parts")
+    private StageDTO stage3 = new StageDTO();
+    @XmlElement(name = "Stage2Parts", required = true, nillable = false)
+    private StageDTO stage2 = new StageDTO();
+    @XmlElement(name = "Stage1Parts", required = false, nillable = false)
+    private StageDTO stage1 = new StageDTO();
+
+    public RocketDesignDTO() {
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String theName) {
+        name = theName;
+    }
+
+    public int getStageCount() {
+        return stageCount;
+    }
+
+    public void setStageCount(int theStageCount) {
+        stageCount = theStageCount;
+    }
+
+    public StageDTO getStage3() {
+        return stage3;
+    }
+
+    public void setStage3(StageDTO theStage3) {
+        stage3 = theStage3;
+    }
+
+    public StageDTO getStage2() {
+        return stage2;
+    }
+
+    public void setStage2(StageDTO theStage2) {
+        stage2 = theStage2;
+    }
+
+    public StageDTO getStage1() {
+        return stage1;
+    }
+
+    public void setStage1(StageDTO theStage1) {
+        stage1 = theStage1;
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/RocksimDesignDTO.java b/src/net/sf/openrocket/file/rocksim/export/RocksimDesignDTO.java
new file mode 100644 (file)
index 0000000..5612925
--- /dev/null
@@ -0,0 +1,25 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RocksimDesignDTO {
+
+    @XmlElement(name = "RocketDesign")
+    private RocketDesignDTO design;
+
+    public RocksimDesignDTO() {
+    }
+
+    public RocketDesignDTO getDesign() {
+        return design;
+    }
+
+    public void setDesign(RocketDesignDTO theDesign) {
+        design = theDesign;
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/RocksimDocumentDTO.java b/src/net/sf/openrocket/file/rocksim/export/RocksimDocumentDTO.java
new file mode 100644 (file)
index 0000000..681f408
--- /dev/null
@@ -0,0 +1,32 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "RockSimDocument")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RocksimDocumentDTO {
+    
+    @XmlElement(name = "FileVersion")
+    private final String version = "4";
+
+    @XmlElement(name = "DesignInformation")
+    private RocksimDesignDTO design;
+
+    public RocksimDocumentDTO() {
+    }
+
+    public RocksimDesignDTO getDesign() {
+        return design;
+    }
+
+    public void setDesign(RocksimDesignDTO theDesign) {
+        this.design = theDesign;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/RocksimSaver.java b/src/net/sf/openrocket/file/rocksim/export/RocksimSaver.java
new file mode 100644 (file)
index 0000000..3950062
--- /dev/null
@@ -0,0 +1,122 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.document.StorageOptions;
+import net.sf.openrocket.file.RocketSaver;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.NoseCone;
+import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.Stage;
+import net.sf.openrocket.rocketcomponent.Transition;
+import net.sf.openrocket.startup.Application;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.util.List;
+
+/**
+ */
+public class RocksimSaver extends RocketSaver {
+
+    private static final LogHelper log = Application.getLogger();
+
+    public String marshalToRocksim(OpenRocketDocument doc) {
+
+        try {
+            JAXBContext binder = JAXBContext.newInstance(RocksimDocumentDTO.class);
+            Marshaller marshaller = binder.createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+            StringWriter sw = new StringWriter();
+
+            marshaller.marshal(toRocksimDocumentDTO(doc), sw);
+            return sw.toString();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+    @Override
+    public void save(OutputStream dest, OpenRocketDocument doc, StorageOptions options) throws IOException {
+        log.info("Saving .rkt file");
+
+        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(dest, "UTF-8"));
+        writer.write(marshalToRocksim(doc));
+        writer.flush();
+        writer.close();
+    }
+
+    @Override
+    public long estimateFileSize(OpenRocketDocument doc, StorageOptions options) {
+        return marshalToRocksim(doc).length();
+    }
+
+    private RocksimDocumentDTO toRocksimDocumentDTO(OpenRocketDocument doc) {
+        RocksimDocumentDTO rsd = new RocksimDocumentDTO();
+
+        rsd.setDesign(toRocksimDesignDTO(doc.getRocket()));
+
+        return rsd;
+    }
+
+    private RocksimDesignDTO toRocksimDesignDTO(Rocket rocket) {
+        RocksimDesignDTO result = new RocksimDesignDTO();
+        result.setDesign(toRocketDesignDTO(rocket));
+        return result;
+    }
+
+    private RocketDesignDTO toRocketDesignDTO(Rocket rocket) {
+        RocketDesignDTO result = new RocketDesignDTO();
+        result.setName(rocket.getName());
+        int stageCount = rocket.getStageCount();
+        result.setStageCount(stageCount);
+        if (stageCount > 0) {
+            result.setStage3(toStageDTO(rocket.getChild(0).getStage()));
+        }
+        if (stageCount > 1) {
+            result.setStage2(toStageDTO(rocket.getChild(1).getStage()));
+        }
+        if (stageCount > 2) {
+            result.setStage1(toStageDTO(rocket.getChild(2).getStage()));
+        }
+        return result;
+    }
+
+    private StageDTO toStageDTO(Stage stage) {
+        StageDTO result = new StageDTO();
+
+        List<RocketComponent> children = stage.getChildren();
+        for (int i = 0; i < children.size(); i++) {
+            RocketComponent rocketComponents = children.get(i);
+            if (rocketComponents instanceof NoseCone) {
+                result.addExternalPart(toNoseConeDTO((NoseCone) rocketComponents));
+            } else if (rocketComponents instanceof BodyTube) {
+                result.addExternalPart(toBodyTubeDTO((BodyTube) rocketComponents));
+            } else if (rocketComponents instanceof Transition) {
+                result.addExternalPart(toTransitionDTO((Transition) rocketComponents));
+            }
+        }
+        return result;
+    }
+
+    private NoseConeDTO toNoseConeDTO(NoseCone nc) {
+        return new NoseConeDTO(nc);
+    }
+
+    private BodyTubeDTO toBodyTubeDTO(BodyTube bt) {
+        return new BodyTubeDTO(bt);
+    }
+
+    private TransitionDTO toTransitionDTO(Transition tran) {
+        return new TransitionDTO(tran);
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/StageDTO.java b/src/net/sf/openrocket/file/rocksim/export/StageDTO.java
new file mode 100644 (file)
index 0000000..112be2c
--- /dev/null
@@ -0,0 +1,33 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.util.ArrayList;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlElementRefs;
+import java.util.List;
+
+/**
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+public class StageDTO {
+
+    @XmlElementRefs({
+            @XmlElementRef(name = "BodyTube", type = BodyTubeDTO.class),
+            @XmlElementRef(name = "NoseCone", type = NoseConeDTO.class),
+            @XmlElementRef(name = "Transition", type = TransitionDTO.class)
+    })
+    private List<BasePartDTO> externalPart = new ArrayList<BasePartDTO>();
+
+    public StageDTO() {
+    }
+
+    public List<BasePartDTO> getExternalPart() {
+        return externalPart;
+    }
+
+    public void addExternalPart(BasePartDTO theExternalPartDTO) {
+        externalPart.add(theExternalPartDTO);
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/StreamerDTO.java b/src/net/sf/openrocket/file/rocksim/export/StreamerDTO.java
new file mode 100644 (file)
index 0000000..cb68766
--- /dev/null
@@ -0,0 +1,46 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.file.rocksim.importt.RocksimHandler;
+import net.sf.openrocket.rocketcomponent.Streamer;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ */
+@XmlRootElement(name = "Streamer")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class StreamerDTO extends BasePartDTO {
+
+        @XmlElement(name = "Width")
+        private double width = 0d;
+        @XmlElement(name = "DragCoefficient")
+        private double dragCoefficient = 0.75d;
+
+    public StreamerDTO() {
+    }
+
+    public StreamerDTO(Streamer ec) {
+        super(ec);
+        setWidth(ec.getStripWidth() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setDragCoefficient(ec.getCD());
+    }
+
+    public double getWidth() {
+        return width;
+    }
+
+    public void setWidth(double theWidth) {
+        width = theWidth;
+    }
+
+    public double getDragCoefficient() {
+        return dragCoefficient;
+    }
+
+    public void setDragCoefficient(double theDragCoefficient) {
+        dragCoefficient = theDragCoefficient;
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/TransitionDTO.java b/src/net/sf/openrocket/file/rocksim/export/TransitionDTO.java
new file mode 100644 (file)
index 0000000..5d66830
--- /dev/null
@@ -0,0 +1,92 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.file.rocksim.importt.RocksimHandler;
+import net.sf.openrocket.rocketcomponent.Transition;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ */
+@XmlRootElement(name = "Transition")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class TransitionDTO extends AbstractTransitionDTO {
+
+
+    @XmlElement(name = "FrontShoulderLen")
+    private double frontShoulderLen = 0d;
+    @XmlElement(name = "RearShoulderLen")
+    private double rearShoulderLen = 0d;
+    @XmlElement(name = "FrontShoulderDia")
+    private double frontShoulderDia = 0d;
+    @XmlElement(name = "RearShoulderDia")
+    private double rearShoulderDia = 0d;
+    @XmlElement(name = "FrontDia")
+    private double frontDia = 0d;
+    @XmlElement(name = "RearDia")
+    private double rearDia = 0d;
+
+    public TransitionDTO() {
+    }
+
+    public TransitionDTO(Transition tran) {
+        super(tran);
+        setFrontDia(tran.getForeRadius() * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setRearDia(tran.getAftRadius() * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setFrontShoulderDia(tran.getForeShoulderRadius() * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setFrontShoulderLen(tran.getForeShoulderLength() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setRearShoulderDia(tran.getAftShoulderRadius() * RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setRearShoulderLen(tran.getAftShoulderLength() * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+
+
+    }
+    public double getFrontShoulderLen() {
+        return frontShoulderLen;
+    }
+
+    public void setFrontShoulderLen(double theFrontShoulderLen) {
+        frontShoulderLen = theFrontShoulderLen;
+    }
+
+    public double getRearShoulderLen() {
+        return rearShoulderLen;
+    }
+
+    public void setRearShoulderLen(double theRearShoulderLen) {
+        rearShoulderLen = theRearShoulderLen;
+    }
+
+    public double getFrontShoulderDia() {
+        return frontShoulderDia;
+    }
+
+    public void setFrontShoulderDia(double theFrontShoulderDia) {
+        frontShoulderDia = theFrontShoulderDia;
+    }
+
+    public double getRearShoulderDia() {
+        return rearShoulderDia;
+    }
+
+    public void setRearShoulderDia(double theRearShoulderDia) {
+        rearShoulderDia = theRearShoulderDia;
+    }
+
+    public double getFrontDia() {
+        return frontDia;
+    }
+
+    public void setFrontDia(double theFrontDia) {
+        frontDia = theFrontDia;
+    }
+
+    public double getRearDia() {
+        return rearDia;
+    }
+
+    public void setRearDia(double theRearDia) {
+        rearDia = theRearDia;
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/export/TubeCouplerDTO.java b/src/net/sf/openrocket/file/rocksim/export/TubeCouplerDTO.java
new file mode 100644 (file)
index 0000000..52d995e
--- /dev/null
@@ -0,0 +1,19 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.rocketcomponent.TubeCoupler;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ */
+@XmlRootElement(name = "Ring")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class TubeCouplerDTO extends CenteringRingDTO {
+
+    public TubeCouplerDTO(TubeCoupler tc) {
+        super(tc);
+        setUsageCode(UsageCode.TubeCoupler);
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/importt/AttachedPartsHandler.java b/src/net/sf/openrocket/file/rocksim/importt/AttachedPartsHandler.java
new file mode 100644 (file)
index 0000000..4543c51
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * AttachedPartsHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.ElementHandler;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+
+import java.util.HashMap;
+
+/**
+ * A SAX handler for the Rocksim AttachedParts XML type.  
+ */
+class AttachedPartsHandler extends ElementHandler {
+    /** The parent component. */
+    private final RocketComponent component;
+
+    /**
+     * Constructor.
+     * 
+     * @param c  the parent
+     * 
+     * @throws IllegalArgumentException   thrown if <code>c</code> is null
+     */
+    public AttachedPartsHandler(RocketComponent c) throws IllegalArgumentException {
+        if (c == null) {
+            throw new IllegalArgumentException("The parent component of any attached part may not be null.");
+        }
+        component = c;
+    }
+
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        if ("FinSet".equals(element)) {
+            return new FinSetHandler(component);
+        }
+        if ("CustomFinSet".equals(element)) {
+            return new FinSetHandler(component);
+        }
+        if ("LaunchLug".equals(element)) {
+            return new LaunchLugHandler(component, warnings);
+        }
+        if ("Parachute".equals(element)) {
+            return new ParachuteHandler(component, warnings);
+        }
+        if ("Streamer".equals(element)) {
+            return new StreamerHandler(component, warnings);
+        }
+        if ("MassObject".equals(element)) {
+            return new MassObjectHandler(component, warnings);
+        }
+        if ("Ring".equals(element)) {
+            return new RingHandler(component, warnings);
+        }
+        if ("BodyTube".equals(element)) {
+            return new InnerBodyTubeHandler(component, warnings);
+        }
+        if ("Transition".equals(element)) {
+            return new TransitionHandler(component, warnings);
+        }
+        if ("TubeFinSet".equals(element)) {
+            warnings.add("Tube fins are not currently supported. Ignoring.");
+        }
+        if ("RingTail".equals(element)) {
+            warnings.add("Ring tails are not currently supported. Ignoring.");
+        }
+        if ("ExternalPod".equals(element)) {
+            warnings.add("Pods are not currently supported. Ignoring.");
+        }
+        return null;
+    }
+}
+
diff --git a/src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java b/src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java
new file mode 100644 (file)
index 0000000..59fb05a
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * BaseHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.ElementHandler;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.xml.sax.SAXException;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+/**
+ * An abstract base class that handles common parsing.  All Rocksim component handlers are subclassed from here.
+ *
+ * @param <C>   the specific RocketComponent subtype for which the concrete handler can create
+ */
+public abstract class BaseHandler<C extends RocketComponent> extends ElementHandler {
+
+    /**
+     * Prepend rocksim materials.
+     */
+    public static final String ROCKSIM_MATERIAL_PREFIX = "RS: ";
+    /**
+     * The overridden mass.
+     */
+    private Double mass = 0d;
+    /**
+     * The overridden Cg.
+     */
+    private Double cg = 0d;
+    /**
+     * The density of the material in the component.
+     */
+    private Double density = 0d;
+    /**
+     * The internal Rocksim density type.
+     */
+    private RocksimDensityType densityType = RocksimDensityType.ROCKSIM_BULK;
+
+    /**
+     * The material name.
+     */
+    private String materialName = "";
+
+    /**
+     * The SAX method called when the closing element tag is reached.
+     *
+     * @param element        the element name.
+     * @param attributes    attributes of the element.
+     * @param content        the textual content of the element.
+     * @param warnings        the warning set to store warnings in.
+     * @throws SAXException
+     */
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        final C component = getComponent();
+        try {
+            if ("Name".equals(element)) {
+                component.setName(content);
+            }
+            if ("KnownMass".equals(element)) {
+                mass = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
+            }
+            if ("Density".equals(element)) {
+                density = Math.max(0d, Double.parseDouble(content) );
+            }
+            if ("KnownCG".equals(element)) {
+                cg = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            }
+            if ("UseKnownCG".equals(element)) {  //Rocksim sets UseKnownCG to true to control the override of both cg and mass
+                boolean override = "1".equals(content);
+                setOverride(component, override, mass, cg);
+            }
+            if ("DensityType".equals(element)) {
+                densityType = RocksimDensityType.fromCode(Integer.parseInt(content));
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        /* Because of the order of XML elements in Rocksim, not all information is known at the time it really needs
+           to be acted upon.  So we keep temporary instance variables to be used here at the end of the parsing.
+         */
+        density = computeDensity(densityType, density);
+        RocketComponent component = getComponent();
+        updateComponentMaterial(component, materialName, getMaterialType(), density);
+    }
+
+    /**
+     * Compute the density.  Rocksim does strange things with densities.  For some streamer material it's in cubic,
+     * rather than square, units.  In those cases it needs to be converted to an appropriate SURFACE material density.
+     * Some G10 fiberglass materials are in cubic units, other G10 fiberglass is in square units.  And due to a
+     * Rocksim bug, some densities are 0 when they clearly should not be.
+     *
+     * This may be overridden for specific component density computations.
+     *
+     * @param type       the rocksim density
+     * @param rawDensity the density as specified in the Rocksim design file
+     * @return a value in OpenRocket SURFACE density units
+     */
+    protected double computeDensity(RocksimDensityType type, double rawDensity) {
+        return rawDensity / type.asOpenRocket();
+    }
+
+    /**
+     * If the Rocksim component does not override the mass, then create a Material based upon the density defined
+     * for that component.  This *should* result in a consistent representation of Cg between Rocksim and OpenRocket.
+     *
+     * @param component       the component
+     * @param type            the type of the material
+     * @param density         the density in g/cm^3
+     * @param definedMaterial the material that is currently defined on the component; used only to get the name
+     *                        as it appears in Rocksim
+     */
+    public static void updateComponentMaterial(RocketComponent component, String definedMaterial, Material.Type type,
+                                               double density) {
+        if (definedMaterial != null) {
+            Material custom = createCustomMaterial(type, definedMaterial, density);
+            setMaterial(component, custom);
+        }
+    }
+
+    /**
+     * Override the mass and Cg of the component.
+     *
+     * @param component  the component
+     * @param override   true if any override should happen
+     * @param mass       the override mass
+     * @param cg         the override cg
+     */
+    public static void setOverride(RocketComponent component, boolean override, double mass, double cg) {
+        if (override) {
+            component.setCGOverridden(override);
+            component.setMassOverridden(override);
+            component.setOverrideSubcomponents(false); //Rocksim does not support this type of override
+            component.setOverrideMass(mass);
+            component.setOverrideCGX(cg);
+        }
+    }
+
+    /**
+     * Get the component this handler is working upon.
+     *
+     * @return a component
+     */
+    protected abstract C getComponent();
+
+    /**
+     * Get the required type of material for this component.
+     *
+     * @return the required material type
+     */
+    protected abstract Material.Type getMaterialType();
+
+    /**
+     * Some CG positions in Rocksim do not correspond to the CG position reference in OpenRocket.
+     *
+     * @param theCG  the CG value to really use when overriding CG on the OpenRocket component
+     */
+    protected void setCG(double theCG) {
+        cg = theCG;
+    }
+
+    /**
+     * Set the material name as specified in the Rocksim design file.
+     *
+     * @param content  the material name
+     */
+    protected void setMaterialName(String content) {
+        materialName = content;
+    }
+
+    /**
+     * Add child to parent only if the child is compatible.  Otherwise add to warning set.
+     * 
+     * @param parent  the parent component
+     * @param child   the child component
+     * @param warnings the warning set
+     * 
+     * @return true if the child is compatible with parent
+     */
+    protected static boolean isCompatible(RocketComponent parent, Class<? extends RocketComponent> child, WarningSet warnings) {
+        if (!parent.isCompatible(child)) {
+            warnings.add(child.getName() + " can not be attached to "
+                         + parent.getComponentName() + ", ignoring component.");
+            return false;
+        }
+        else {
+            return true;
+        }
+    }
+    
+    /**
+     * Create a custom material based on the density.  The name of the material is prepended with 'RS: ' to
+     * indicate it came from a RockSim material.
+     *
+     * @param type    the type of the material
+     * @param name    the name of the component
+     * @param density the density
+     *
+     * @return a Material instance
+     */
+    public static Material createCustomMaterial(Material.Type type, String name, double density) {
+        return Material.newMaterial(type, ROCKSIM_MATERIAL_PREFIX + name, density, true);
+    }
+
+    /**
+     * Set the material onto an instance of RocketComponent.  This is done because only some subtypes of RocketComponent
+     * have the setMaterial method.  Unfortunately the supertype cannot be used.
+     *
+     * @param component  the component who's material is to be set
+     * @param material the material to be set on the component (defined by getComponent())
+     */
+    private static void setMaterial(RocketComponent component, Material material) {
+        try {
+            final Method method = getMethod(component, "setMaterial", new Class[]{Material.class});
+            if (method != null) {
+                method.invoke(component, material);
+            }
+        }
+        catch (IllegalAccessException ignored) {
+        }
+        catch (InvocationTargetException ignored) {
+        }
+    }
+
+    /**
+     * Find a method by name and argument list.
+     *
+     * @param component  the component who's material is to be seta
+     * @param name the method name
+     * @param args the class types of the parameters
+     *
+     * @return the Method instance, or null
+     */
+    private static Method getMethod(RocketComponent component, String name, Class[] args) {
+        Method method = null;
+        try {
+            method = component.getClass().getMethod(name, args);
+        }
+        catch (NoSuchMethodException ignored) {
+        }
+        return method;
+    }
+
+}
diff --git a/src/net/sf/openrocket/file/rocksim/importt/BodyTubeHandler.java b/src/net/sf/openrocket/file/rocksim/importt/BodyTubeHandler.java
new file mode 100644 (file)
index 0000000..f2acb4c
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * BodyTubeHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+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.BodyTube;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * A SAX handler for Rocksim Body Tubes.
+ */
+class BodyTubeHandler extends BaseHandler<BodyTube> {
+    /**
+     * The OpenRocket BodyTube.
+     */
+    private final BodyTube bodyTube;
+
+    /**
+     * Constructor.
+     *
+     * @param c parent component
+     * @param warnings  the warning set
+     * @throws IllegalArgumentException thrown if <code>c</code> is null
+     */
+    public BodyTubeHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
+        if (c == null) {
+            throw new IllegalArgumentException("The parent component of a body tube may not be null.");
+        }
+        bodyTube = new BodyTube();
+        if (isCompatible(c, BodyTube.class, warnings)) {
+            c.addChild(bodyTube);
+        }
+    }
+
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        if ("AttachedParts".equals(element)) {
+            return new AttachedPartsHandler(bodyTube);
+        }
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        super.closeElement(element, attributes, content, warnings);
+
+        try {
+            if ("OD".equals(element)) {
+                bodyTube.setOuterRadius(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+            }
+            if ("ID".equals(element)) {
+                final double r = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS;
+                bodyTube.setInnerRadius(r);
+            }
+            if ("Len".equals(element)) {
+                bodyTube.setLength(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            }
+            if ("FinishCode".equals(element)) {
+                bodyTube.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket());
+            }
+            if ("IsMotorMount".equals(element)) {
+                bodyTube.setMotorMount("1".equals(content));
+            }
+            if ("EngineOverhang".equals(element)) {
+                bodyTube.setMotorOverhang(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            }
+            if ("Material".equals(element)) {
+                setMaterialName(content);
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+    /**
+     * Get the component this handler is working upon.
+     * 
+     * @return a component
+     */
+    @Override
+    public BodyTube getComponent() {
+        return bodyTube;
+    }
+
+    /**
+     * Get the required type of material for this component.
+     *
+     * @return BULK
+     */
+    public Material.Type getMaterialType() {
+        return Material.Type.BULK;
+    }
+}
+
diff --git a/src/net/sf/openrocket/file/rocksim/importt/FinSetHandler.java b/src/net/sf/openrocket/file/rocksim/importt/FinSetHandler.java
new file mode 100644 (file)
index 0000000..1ddb567
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * FinSetHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+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.EllipticalFinSet;
+import net.sf.openrocket.rocketcomponent.ExternalComponent;
+import net.sf.openrocket.rocketcomponent.FinSet;
+import net.sf.openrocket.rocketcomponent.FreeformFinSet;
+import net.sf.openrocket.rocketcomponent.IllegalFinPointException;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
+import net.sf.openrocket.util.Coordinate;
+import org.xml.sax.SAXException;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * A SAX handler for Rocksim fin sets.  Because the type of fin may not be known first (in Rocksim file format, the fin
+ * shape type is in the middle of the XML structure), and because we're using SAX not DOM, all of the fin
+ * characteristics are kept here until the closing FinSet tag. At that point, <code>asOpenRocket</code> method is called
+ * to construct the corresponding OpenRocket FinSet.
+ */
+class FinSetHandler extends ElementHandler {
+    /**
+     * The parent component.
+     */
+    private final RocketComponent component;
+
+    /**
+     * The name of the fin.
+     */
+    private String name;
+    /**
+     * The Rocksim fin shape code.
+     */
+    private int shapeCode;
+    /**
+     * The location of the fin on its parent.
+     */
+    private double location = 0.0d;
+    /**
+     * The OpenRocket Position which gives the absolute/relative positioning for location.
+     */
+    private RocketComponent.Position position;
+    /**
+     * The number of fins in this fin set.
+     */
+    private int finCount;
+    /**
+     * The length of the root chord.
+     */
+    private double rootChord = 0.0d;
+    /**
+     * The length of the tip chord.
+     */
+    private double tipChord = 0.0d;
+    /**
+     * The length of the mid-chord (aka height).
+     */
+    private double midChordLen = 0.0d;
+    /**
+     * The distance of the leading edge from root to top.
+     */
+    private double sweepDistance = 0.0d;
+    /**
+     * The angle the fins have been rotated from the y-axis, if looking down the tube, in radians.
+     */
+    private double radialAngle = 0.0d;
+    /**
+     * The thickness of the fins.
+     */
+    private double thickness;
+    /**
+     * The finish of the fins.
+     */
+    private ExternalComponent.Finish finish;
+    /**
+     * The shape of the tip.
+     */
+    private int tipShapeCode;
+    /**
+     * The length of the TTW tab.
+     */
+    private double tabLength = 0.0d;
+    /**
+     * The depth of the TTW tab.
+     */
+    private double tabDepth = 0.0d;
+    /**
+     * The offset of the tab, from the front of the fin.
+     */
+    private double taboffset = 0.0d;
+    /**
+     * The elliptical semi-span (height).
+     */
+    private double semiSpan;
+    /**
+     * The list of custom points.
+     */
+    private String pointList;
+    /**
+     * Override the Cg and mass.
+     */
+    private boolean override = false;
+    /**
+     * The overridden mass.
+     */
+    private Double mass = 0d;
+    /**
+     * The overridden Cg.
+     */
+    private Double cg = 0d;
+    /**
+     * The density of the material in the component.
+     */
+    private Double density = 0d;
+    /**
+     * The material name.
+     */
+    private String materialName = "";
+    /**
+     * The Rocksim calculated mass.
+     */
+    private Double calcMass = 0d;
+    /**
+     * The Rocksim calculated cg.
+     */
+    private Double calcCg = 0d;
+
+
+    /**
+     * Constructor.
+     *
+     * @param c the parent
+     *
+     * @throws IllegalArgumentException thrown if <code>c</code> is null
+     */
+    public FinSetHandler (RocketComponent c) throws IllegalArgumentException {
+        if (c == null) {
+            throw new IllegalArgumentException("The parent component of a fin set may not be null.");
+        }
+        component = c;
+    }
+
+    @Override
+    public ElementHandler openElement (String element, HashMap<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement (String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        try {
+            if ("Name".equals(element)) {
+                name = content;
+            }
+            if ("Material".equals(element)) {
+                materialName = content;
+            }
+            if ("FinishCode".equals(element)) {
+                finish = RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket();
+            }
+            if ("Xb".equals(element)) {
+                location = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("LocationMode".equals(element)) {
+                position = RocksimLocationMode.fromCode(Integer.parseInt(content)).asOpenRocket();
+            }
+            if ("FinCount".equals(element)) {
+                finCount = Integer.parseInt(content);
+            }
+            if ("RootChord".equals(element)) {
+                rootChord = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("TipChord".equals(element)) {
+                tipChord = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("SemiSpan".equals(element)) {
+                semiSpan = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("MidChordLen".equals(element)) {
+                midChordLen = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("SweepDistance".equals(element)) {
+                sweepDistance = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("Thickness".equals(element)) {
+                thickness = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("TipShapeCode".equals(element)) {
+                tipShapeCode = Integer.parseInt(content);
+            }
+            if ("TabLength".equals(element)) {
+                tabLength = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("TabDepth".equals(element)) {
+                tabDepth = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("TabOffset".equals(element)) {
+                taboffset = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("RadialAngle".equals(element)) {
+                radialAngle = Double.parseDouble(content);
+            }
+            if ("ShapeCode".equals(element)) {
+                shapeCode = Integer.parseInt(content);
+            }
+            if ("PointList".equals(element)) {
+                pointList = content;
+            }
+            if ("KnownMass".equals(element)) {
+                mass = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
+            }
+            if ("Density".equals(element)) {
+                density = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_BULK_DENSITY);
+            }
+            if ("KnownCG".equals(element)) {
+                cg = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
+            }
+            if ("UseKnownCG".equals(element)) {
+                override = "1".equals(content);
+            }
+            if ("CalcMass".equals(element)) {
+                calcMass = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS;
+            }
+            if ("CalcCg".equals(element)) {
+                calcCg = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+    @Override
+    public void endHandler (String element, HashMap<String, String> attributes,
+            String content, WarningSet warnings) throws SAXException {
+        //Create the fin set and correct for overrides and actual material densities
+        final FinSet finSet = asOpenRocket(warnings);
+        if (component.isCompatible(finSet)) {
+            BaseHandler.setOverride(finSet, override, mass, cg);
+            if (!override && finSet.getCrossSection().equals(FinSet.CrossSection.AIRFOIL)) {
+                //Override mass anyway.  This is done only for AIRFOIL because Rocksim does not compute different
+                //mass/cg for different cross sections, but OpenRocket does.  This can lead to drastic differences
+                //in mass.  To counteract that, the cross section value is retained but the mass/cg is overridden
+                //with the calculated values from Rocksim.  This will best approximate the Rocksim design in OpenRocket.
+                BaseHandler.setOverride(finSet, true, calcMass, calcCg);
+            }
+            BaseHandler.updateComponentMaterial(finSet, materialName, Material.Type.BULK, density);
+            component.addChild(finSet);
+        }
+        else {
+            warnings.add(finSet.getComponentName() + " can not be attached to "
+                         + component.getComponentName() + ", ignoring component.");
+        }
+    }
+
+
+    /**
+     * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's FinSet.
+     *
+     * @param warnings the warning set to convey incompatibilities to the user
+     *
+     * @return a FinSet instance
+     */
+    public FinSet asOpenRocket (WarningSet warnings) {
+        FinSet result;
+
+        if (shapeCode == 0) {
+            //Trapezoidal
+            result = new TrapezoidFinSet();
+            ((TrapezoidFinSet) result).setFinShape(rootChord, tipChord, sweepDistance, semiSpan, thickness);
+        }
+        else if (shapeCode == 1) {
+            //Elliptical
+            result = new EllipticalFinSet();
+            ((EllipticalFinSet) result).setHeight(semiSpan);
+            ((EllipticalFinSet) result).setLength(rootChord);
+        }
+        else if (shapeCode == 2) {
+
+            result = new FreeformFinSet();
+            try {
+                ((FreeformFinSet) result).setPoints(toCoordinates(pointList, warnings));
+            }
+            catch (IllegalFinPointException e) {
+                warnings.add("Illegal fin point set. " + e.getMessage() + " Ignoring.");
+            }
+        }
+        else {
+            return null;
+        }
+        result.setThickness(thickness);
+        result.setName(name);
+        result.setFinCount(finCount);
+        result.setFinish(finish);
+        //All TTW tabs in Rocksim are relative to the front of the fin.
+        result.setTabRelativePosition(FinSet.TabRelativePosition.FRONT);
+        result.setTabHeight(tabDepth);
+        result.setTabLength(tabLength);
+        result.setTabShift(taboffset);
+        result.setBaseRotation(radialAngle);
+        result.setCrossSection(convertTipShapeCode(tipShapeCode));
+        result.setRelativePosition(position);
+        PositionDependentHandler.setLocation(result, position, location);
+        return result;
+
+    }
+
+    /**
+     * Convert a Rocksim string that represents fin plan points into an array of OpenRocket coordinates.
+     *
+     * @param pointList a comma and pipe delimited string of X,Y coordinates from Rocksim.  This is of the format:
+     *                  <pre>x0,y0|x1,y1|x2,y2|... </pre>
+     * @param warnings  the warning set to convey incompatibilities to the user
+     *
+     * @return an array of OpenRocket Coordinates
+     */
+    private Coordinate[] toCoordinates (String pointList, WarningSet warnings) {
+        List<Coordinate> result = new ArrayList<Coordinate>();
+        if (pointList != null && !pointList.isEmpty()) {
+            String[] points = pointList.split("\\Q|\\E");
+            for (String point : points) {
+                String[] aPoint = point.split(",");
+                try {
+                    if (aPoint.length > 1) {
+                        Coordinate c = new Coordinate(
+                                Double.parseDouble(aPoint[0]) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH,
+                                Double.parseDouble(aPoint[1]) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+                        result.add(c);
+                    }
+                    else {
+                        warnings.add("Invalid fin point pair.");
+                    }
+                }
+                catch (NumberFormatException nfe) {
+                    warnings.add("Fin point not in numeric format.");
+                }
+            }
+            if (!result.isEmpty()) {
+                //OpenRocket requires fin plan points be ordered from leading root chord to trailing root chord in the
+                //Coordinate array.
+                Coordinate last = result.get(result.size() - 1);
+                if (last.x == 0 && last.y == 0) {
+                    Collections.reverse(result);
+                }
+            }
+        }
+        final Coordinate[] coords = new Coordinate[result.size()];
+        return result.toArray(coords);
+    }
+
+
+    /**
+     * Convert a Rocksim tip shape to an OpenRocket CrossSection.
+     *
+     * @param tipShape the tip shape code from Rocksim
+     *
+     * @return a CrossSection instance
+     */
+    public static FinSet.CrossSection convertTipShapeCode (int tipShape) {
+        switch (tipShape) {
+            case 0:
+                return FinSet.CrossSection.SQUARE;
+            case 1:
+                return FinSet.CrossSection.ROUNDED;
+            case 2:
+                return FinSet.CrossSection.AIRFOIL;
+            default:
+                return FinSet.CrossSection.SQUARE;
+        }
+    }
+    
+    public static int convertTipShapeCode (FinSet.CrossSection cs) {
+        if (FinSet.CrossSection.ROUNDED.equals(cs)) {
+            return 1;
+        }
+        if (FinSet.CrossSection.AIRFOIL.equals(cs)) {
+            return 2;
+        }
+        return 0;
+    }
+
+}
+
diff --git a/src/net/sf/openrocket/file/rocksim/importt/InnerBodyTubeHandler.java b/src/net/sf/openrocket/file/rocksim/importt/InnerBodyTubeHandler.java
new file mode 100644 (file)
index 0000000..edcf83f
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * InnerBodyTubeHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+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.InnerTube;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * A SAX handler for Rocksim inside tubes.
+ */
+class InnerBodyTubeHandler extends PositionDependentHandler<InnerTube> {
+
+    /**
+     * The OpenRocket InnerTube instance.
+     */
+    private final InnerTube bodyTube;
+
+    /**
+     * Constructor.
+     *
+     * @param c the parent component
+     * @param warnings  the warning set
+     * @throws IllegalArgumentException thrown if <code>c</code> is null
+     */
+    public InnerBodyTubeHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
+        if (c == null) {
+            throw new IllegalArgumentException("The parent component of an inner tube may not be null.");
+        }
+        bodyTube = new InnerTube();
+        if (isCompatible(c, InnerTube.class, warnings)) {
+            c.addChild(bodyTube);
+        }
+    }
+
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        if ("AttachedParts".equals(element)) {
+            return new AttachedPartsHandler(bodyTube);
+        }
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        super.closeElement(element, attributes, content, warnings);
+
+        try {
+            if ("OD".equals(element)) {
+                bodyTube.setOuterRadius(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+            }
+            if ("ID".equals(element)) {
+                final double r = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS;
+                bodyTube.setInnerRadius(r);
+            }
+            if ("Len".equals(element)) {
+                bodyTube.setLength(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            }
+            if ("IsMotorMount".equals(element)) {
+                bodyTube.setMotorMount("1".equals(content));
+            }
+            if ("EngineOverhang".equals(element)) {
+                bodyTube.setMotorOverhang(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            }
+            if ("Material".equals(element)) {
+                setMaterialName(content);
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+    /**
+     * Get the InnerTube component this handler is working upon.
+     * 
+     * @return an InnerTube component
+     */
+    @Override
+    public InnerTube getComponent() {
+        return bodyTube;
+    }
+
+    /**
+     * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not 
+     * public in all components.
+     * 
+     * @param position  the OpenRocket position
+     */
+    @Override
+    public void setRelativePosition(RocketComponent.Position position) {
+        bodyTube.setRelativePosition(position);
+    }
+
+    /**
+     * Get the required type of material for this component.
+     *
+     * @return BULK
+     */
+    @Override
+    public Material.Type getMaterialType() {
+        return Material.Type.BULK;
+    }
+
+}
diff --git a/src/net/sf/openrocket/file/rocksim/importt/LaunchLugHandler.java b/src/net/sf/openrocket/file/rocksim/importt/LaunchLugHandler.java
new file mode 100644 (file)
index 0000000..1a9d51a
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * LaunchLugHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+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.LaunchLug;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * The SAX handler for Rocksim Launch Lugs.
+ */
+class LaunchLugHandler extends PositionDependentHandler<LaunchLug> {
+
+    /**
+     * The OpenRocket LaunchLug instance.
+     */
+    private final LaunchLug lug;
+
+    /**
+     * Constructor.
+     *
+     * @param c the parent
+     * @param warnings  the warning set
+     * 
+     * @throws IllegalArgumentException thrown if <code>c</code> is null
+     */
+    public LaunchLugHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
+        if (c == null) {
+            throw new IllegalArgumentException("The parent component of a launch lug may not be null.");
+        }
+        lug = new LaunchLug();
+        if (isCompatible(c, LaunchLug.class, warnings)) {
+            c.addChild(lug);
+        }
+    }
+
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        super.closeElement(element, attributes, content, warnings);
+
+        try {
+            if ("OD".equals(element)) {
+                lug.setOuterRadius(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
+            }
+            if ("ID".equals(element)) {
+                lug.setInnerRadius(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
+            }
+            if ("Len".equals(element)) {
+                lug.setLength(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
+            }
+            if ("Material".equals(element)) {
+                setMaterialName(content);
+            }
+            if ("RadialAngle".equals(element)) {
+                lug.setRadialDirection(Double.parseDouble(content));
+            }
+            if ("FinishCode".equals(element)) {
+                lug.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket());
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+    /**
+     * Get the LaunchLug component this handler is working upon.
+     * 
+     * @return a LaunchLug component
+     */
+    @Override
+    public LaunchLug getComponent() {
+        return lug;
+    }
+
+    /**
+     * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not 
+     * public in all components.
+     * 
+     * @param position  the OpenRocket position
+     */
+    @Override
+    public void setRelativePosition(RocketComponent.Position position) {
+        lug.setRelativePosition(position);
+    }
+
+    /**
+     * Get the required type of material for this component.
+     *
+     * @return BULK
+     */
+    @Override
+    public Material.Type getMaterialType() {
+        return Material.Type.BULK;
+    }
+}
+
diff --git a/src/net/sf/openrocket/file/rocksim/importt/MassObjectHandler.java b/src/net/sf/openrocket/file/rocksim/importt/MassObjectHandler.java
new file mode 100644 (file)
index 0000000..53a33d8
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * MassObjectHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+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.MassComponent;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * A SAX handler for Rocksim's MassObject XML type.
+ */
+class MassObjectHandler extends PositionDependentHandler<MassComponent> {
+
+    /** 
+     * The Rocksim Mass length fudge factor.  Rocksim completely exaggerates the length of a mass object to the point
+     * that it looks ridiculous in OpenRocket.  This fudge factor is here merely to get the typical mass object to
+     * render in the OpenRocket UI with it's bounds mostly inside it's parent.  The odd thing about it is that 
+     * Rocksim does not expose the length of a mass object in the UI and actually treats mass objects as point objects -
+     * not 3 or even 2 dimensional.
+     */
+    public static final int MASS_LEN_FUDGE_FACTOR = 100;
+
+    /**
+     * The OpenRocket MassComponent - counterpart to the RS MassObject.
+     */
+    private final MassComponent mass;
+
+    /**
+     * Constructor.
+     *l
+     * @param c the parent component
+     * @param warnings  the warning set
+     * 
+     * @throws IllegalArgumentException  thrown if <code>c</code> is null
+     */
+    public MassObjectHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
+        if (c == null) {
+            throw new IllegalArgumentException("The parent component of a mass component may not be null.");
+        }
+        mass = new MassComponent();
+        if (isCompatible(c, MassComponent.class, warnings)) {
+            c.addChild(mass);
+        }
+    }
+
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        super.closeElement(element, attributes, content, warnings);
+        try {
+            if ("Len".equals(element)) {
+                mass.setLength(Double.parseDouble(content) / (RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH * MASS_LEN_FUDGE_FACTOR));
+            }
+            if ("KnownMass".equals(element)) {
+                mass.setComponentMass(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
+            }
+            if ("KnownCG".equals(element)) {
+                //Setting the CG of the Mass Object to 0 is important because of the different ways that Rocksim and
+                //OpenRocket treat mass objects.  Rocksim treats them as points (even though the data file contains a
+                //length) and because Rocksim sets the CG of the mass object to really be relative to the front of
+                //the parent.  But that value is already assumed in the position and position value for the component.
+                //Thus it needs to be set to 0 to say that the mass object's CG is at the point of the mass object.
+                super.setCG(0); 
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+    /**
+     * Get the component this handler is working upon.
+     *
+     * @return a component
+     */
+    @Override
+    public MassComponent getComponent() {
+        return mass;
+    }
+
+    /**
+     * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not
+     * public in all components.
+     *
+     * @param position the OpenRocket position
+     */
+    public void setRelativePosition(RocketComponent.Position position) {
+        mass.setRelativePosition(position);
+    }
+
+    /**
+     * Get the required type of material for this component.  Does not apply to MassComponents.
+     *
+     * @return BULK
+     */
+    @Override
+    public Material.Type getMaterialType() {
+        return Material.Type.BULK;
+    }
+
+}
diff --git a/src/net/sf/openrocket/file/rocksim/importt/NoseConeHandler.java b/src/net/sf/openrocket/file/rocksim/importt/NoseConeHandler.java
new file mode 100644 (file)
index 0000000..7021331
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * NoseConeHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+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.NoseCone;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.Transition;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * The SAX nose cone handler for Rocksim NoseCones.
+ */
+class NoseConeHandler extends BaseHandler<NoseCone> {
+
+    /**
+     * The OpenRocket NoseCone.
+     */
+    private final NoseCone noseCone = new NoseCone();
+
+    /**
+     * The wall thickness.  Used for hollow nose cones.  
+     */
+    private double thickness = 0d;
+    
+    /**
+     * Constructor.
+     *
+     * @param c the parent component to the nosecone
+     * @param warnings  the warning set
+     * 
+     * @throws IllegalArgumentException thrown if <code>c</code> is null
+     */
+    public NoseConeHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
+        if (c == null) {
+            throw new IllegalArgumentException("The parent component of a nose cone may not be null.");
+        }
+        if (isCompatible(c, NoseCone.class, warnings)) {
+            c.addChild(noseCone);
+            noseCone.setAftRadiusAutomatic(false);
+        }
+    }
+
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        //Nose cones in Rocksim may have attached parts - namely Mass Objects - as children.
+        if ("AttachedParts".equals(element)) {
+            return new AttachedPartsHandler(noseCone);
+        }
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes,
+                             String content, WarningSet warnings) throws SAXException {
+        super.closeElement(element, attributes, content, warnings);
+
+        try {
+            if ("ShapeCode".equals(element)) {
+                noseCone.setType(RocksimNoseConeCode.fromCode(Integer.parseInt(content)).asOpenRocket());
+            }
+            if ("Len".equals(element)) {
+                noseCone.setLength(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
+            }
+            if ("BaseDia".equals(element)) {
+                noseCone.setAftRadius(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
+            }
+            if ("WallThickness".equals(element)) {
+                thickness = Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            }
+            if ("ShoulderOD".equals(element)) {
+                noseCone.setAftShoulderRadius(Math.max(0, Double.parseDouble(
+                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
+            }
+            if ("ShoulderLen".equals(element)) {
+                noseCone.setAftShoulderLength(Math.max(0, Double.parseDouble(
+                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
+            }
+            if ("ShapeParameter".equals(element)) {
+                //The Rocksim ShapeParameter only applies to certain shapes, although it is included
+                //in the design file for all nose cones.  Applying it when it should not be causes oddities so 
+                //a check is made for the allowable shapes.
+                if (Transition.Shape.POWER.equals(noseCone.getType()) ||
+                    Transition.Shape.HAACK.equals(noseCone.getType()) ||
+                    Transition.Shape.PARABOLIC.equals(noseCone.getType())) {
+                    noseCone.setShapeParameter(Double.parseDouble(content));
+                }
+            }
+            if ("ConstructionType".equals(element)) {
+                int typeCode = Integer.parseInt(content);
+                if (typeCode == 0) {
+                    //SOLID
+                    noseCone.setFilled(true);
+                }
+                else if (typeCode == 1) {
+                    //HOLLOW
+                    noseCone.setFilled(false);
+                }
+            }
+            if ("FinishCode".equals(element)) {
+                noseCone.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket());
+            }
+            if ("Material".equals(element)) {
+                setMaterialName(content);
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+    @Override
+    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        super.endHandler(element, attributes, content, warnings);
+        
+        if (noseCone.isFilled()) {
+            noseCone.setAftShoulderThickness(noseCone.getAftShoulderRadius());                    
+        }
+        else {
+            noseCone.setThickness(thickness);
+            noseCone.setAftShoulderThickness(thickness);
+        }
+    }
+    
+    /**
+     * Get the nose cone component this handler is working upon.
+     *
+     * @return a nose cone component
+     */
+    @Override
+    public NoseCone getComponent() {
+        return noseCone;
+    }
+
+    /**
+     * Get the required type of material for this component.
+     *
+     * @return BULK
+     */
+    public Material.Type getMaterialType() {
+        return Material.Type.BULK;
+    }
+
+}
diff --git a/src/net/sf/openrocket/file/rocksim/importt/ParachuteHandler.java b/src/net/sf/openrocket/file/rocksim/importt/ParachuteHandler.java
new file mode 100644 (file)
index 0000000..3ff7555
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * ParachuteHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+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.BodyTube;
+import net.sf.openrocket.rocketcomponent.InnerTube;
+import net.sf.openrocket.rocketcomponent.Parachute;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * A SAX handler for Rocksim's Parachute XML type.
+ */
+class ParachuteHandler extends RecoveryDeviceHandler<Parachute> {
+    /**
+     * The OpenRocket Parachute instance
+     */
+    private final Parachute chute;
+    /**
+     * The shroud line density.
+     */
+    private double shroudLineDensity = 0.0d;
+
+    /**
+     * Constructor.
+     *
+     * @param c the parent component
+     * @param warnings  the warning set
+     * 
+     * @throws IllegalArgumentException thrown if <code>c</code> is null
+     */
+    public ParachuteHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
+        if (c == null) {
+            throw new IllegalArgumentException("The parent of a parachute may not be null.");
+        }
+        chute = new Parachute();
+        if (isCompatible(c, Parachute.class, warnings)) {
+            c.addChild(chute);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        super.closeElement(element, attributes, content, warnings);
+        try {
+            if ("Dia".equals(element)) {
+                chute.setDiameter(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+                /* Rocksim doesn't have a packed parachute radius, so we approximate it. */
+                double packed;
+                RocketComponent parent = chute.getParent();
+                if (parent instanceof BodyTube) {
+                    packed = ((BodyTube) parent).getOuterRadius() * 0.9;
+                }
+                else if (parent instanceof InnerTube) {
+                    packed = ((InnerTube) parent).getInnerRadius() * 0.9;
+                }
+                else {
+                    packed = chute.getDiameter() * 0.025;
+                }
+                chute.setRadius(packed);
+            }
+            if ("ShroudLineCount".equals(element)) {
+                chute.setLineCount(Math.max(0, Integer.parseInt(content)));
+            }
+            if ("ShroudLineLen".equals(element)) {
+                chute.setLineLength(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
+            }
+            if ("SpillHoleDia".equals(element)) {
+                //Not supported in OpenRocket
+                double spillHoleRadius = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS;
+                warnings.add("Parachute spill holes are not supported. Ignoring.");
+            }
+            if ("ShroudLineMassPerMM".equals(element)) {
+                shroudLineDensity = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LINE_DENSITY;
+            }
+            if ("ShroudLineMaterial".equals(element)) {
+                chute.setLineMaterial(createCustomMaterial(Material.Type.LINE, content, shroudLineDensity));
+            }
+            if ("DragCoefficient".equals(element)) {
+                chute.setCD(Double.parseDouble(content));
+            }
+            if ("Material".equals(element)) {
+                setMaterialName(content);
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+    /**
+     * Get the component this handler is working upon.
+     *
+     * @return a component
+     */
+    public Parachute getComponent() {
+        return chute;
+    }
+
+}
+
diff --git a/src/net/sf/openrocket/file/rocksim/importt/PositionDependentHandler.java b/src/net/sf/openrocket/file/rocksim/importt/PositionDependentHandler.java
new file mode 100644 (file)
index 0000000..6639b05
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * PositionDependentHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * An abstract base class that handles position dependencies for all lower level components that
+ * are position aware.
+ *
+ * @param <C>   the specific position dependent RocketComponent subtype for which the concrete handler can create
+ */
+public abstract class PositionDependentHandler<C extends RocketComponent> extends BaseHandler<C> {
+
+    /** Temporary position value. */
+    private Double positionValue = 0d;
+
+    /** Temporary position. */
+    private RocketComponent.Position position = RocketComponent.Position.TOP;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        super.closeElement(element, attributes, content, warnings);
+        if ("Xb".equals(element)) {
+            positionValue = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+        }
+        if ("LocationMode".equals(element)) {
+            position = RocksimLocationMode.fromCode(Integer.parseInt(
+                    content)).asOpenRocket();
+        }
+    }
+
+    /**
+     * This method sets the position information onto the component.  Rocksim splits the location/position
+     * information into two disparate data elements.  Both pieces of data are necessary to map into OpenRocket's
+     * position model.
+     *
+     * @param element     the element name
+     * @param attributes  the attributes
+     * @param content     the content of the element
+     * @param warnings        the warning set to store warnings in.
+     * @throws org.xml.sax.SAXException  not thrown
+     */
+    @Override
+    public void endHandler(String element, HashMap<String, String> attributes,
+                           String content, WarningSet warnings) throws SAXException {
+        super.endHandler(element, attributes, content, warnings);
+        setRelativePosition(position);
+        setLocation(getComponent(), position, positionValue);
+    }
+
+    /**
+     * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not
+     * public in all components.
+     *
+     * @param position  the OpenRocket position
+     */
+    protected abstract void setRelativePosition(RocketComponent.Position position);
+
+    /**
+     * Set the position of a component.
+     *
+     * @param component  the component
+     * @param position   the relative position
+     * @param location   the actual position value
+     */
+    public static void setLocation(RocketComponent component, RocketComponent.Position position, double location) {
+        if (position.equals(RocketComponent.Position.BOTTOM)) {
+            component.setPositionValue(-1d * location);
+        }
+        else {
+            component.setPositionValue(location);
+        }
+    }
+
+}
diff --git a/src/net/sf/openrocket/file/rocksim/importt/RecoveryDeviceHandler.java b/src/net/sf/openrocket/file/rocksim/importt/RecoveryDeviceHandler.java
new file mode 100644 (file)
index 0000000..72e356d
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * RecoveryDeviceHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.RecoveryDevice;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * A handler specific to streamers and parachutes.  This is done because Rocksim allows any type of material to be
+ * used as a recovery device, which causes oddities with respect to densities.  Density computation is overridden
+ * here to try to correctly compute a material's density in OpenRocket units.
+ *
+ * @param <C>  either a Streamer or Parachute
+ */
+public abstract class RecoveryDeviceHandler<C extends RecoveryDevice> extends PositionDependentHandler<C> {
+
+    /**
+     * The thickness.  Not used by every component, and some component handlers may parse it for their own purposes.
+     */
+    private double thickness = 0d;
+    /**
+     * The Rocksim calculated mass.  Used only when not overridden and when Rocksim says density == 0 (Rocksim bug).
+     */
+    private Double calcMass = 0d;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        super.closeElement(element, attributes, content, warnings);
+
+        try {
+            if ("Thickness".equals(element)) {
+                thickness = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("CalcMass".equals(element)) {
+                calcMass = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+
+    /**
+     * Compute the density.  Rocksim does strange things with densities.  For some streamer material it's in cubic,
+     * rather than square, units.  In those cases it needs to be converted to an appropriate SURFACE material density.
+     *
+     * @param type       the rocksim density
+     * @param rawDensity the density as specified in the Rocksim design file
+     * @return a value in OpenRocket SURFACE density units
+     */
+    protected double computeDensity(RocksimDensityType type, double rawDensity) {
+
+        double result;
+
+        if (rawDensity > 0d) {
+            //ROCKSIM_SURFACE is a square area density; compute normally
+            //ROCKSIM_LINE is a single length dimension (kg/m) but Rocksim ignores thickness for this type and treats
+            //it like a SURFACE.
+            if (RocksimDensityType.ROCKSIM_SURFACE.equals(type) || RocksimDensityType.ROCKSIM_LINE.equals(type)) {
+                result = rawDensity / RocksimDensityType.ROCKSIM_SURFACE.asOpenRocket();
+            }
+            //ROCKSIM_BULK is a cubic area density; multiple by thickness to make per square area; the result, when
+            //multiplied by the area will then equal Rocksim's computed mass.
+            else {
+                result = (rawDensity / type.asOpenRocket()) * thickness;
+            }
+        }
+        else {
+            result = calcMass / getComponent().getArea();
+            //A Rocksim bug on streamers/parachutes results in a 0 density at times.  When that is detected, try
+            //to compute an approximate density from Rocksim's computed mass.
+            if (RocksimDensityType.ROCKSIM_BULK.equals(type)) {
+                //ROCKSIM_BULK is a cubic area density; multiple by thickness to make per square area
+                result *= thickness;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not
+     * public in all components.
+     *
+     * @param position the OpenRocket position
+     */
+    @Override
+    public void setRelativePosition(RocketComponent.Position position) {
+        getComponent().setRelativePosition(position);
+    }
+
+    /**
+     * Get the required type of material for this component.  This is the OpenRocket type, which does NOT always
+     * correspond to Rocksim.  Some streamer material is defined as BULK in the Rocksim file.  In those cases
+     * it is adjusted in this handler.
+     *
+     * @return SURFACE
+     */
+    @Override
+    public Material.Type getMaterialType() {
+        return Material.Type.SURFACE;
+    }
+
+}
diff --git a/src/net/sf/openrocket/file/rocksim/importt/RingHandler.java b/src/net/sf/openrocket/file/rocksim/importt/RingHandler.java
new file mode 100644 (file)
index 0000000..20f6aac
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * RingHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+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.Bulkhead;
+import net.sf.openrocket.rocketcomponent.CenteringRing;
+import net.sf.openrocket.rocketcomponent.EngineBlock;
+import net.sf.openrocket.rocketcomponent.RingComponent;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.TubeCoupler;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * A SAX handler for centering rings, tube couplers, and bulkheads.
+ */
+class RingHandler extends PositionDependentHandler<CenteringRing> {
+
+    /**
+     * The OpenRocket Ring.
+     */
+    private final CenteringRing ring = new CenteringRing();
+
+    /**
+     * The parent component.
+     */
+    private final RocketComponent parent;
+
+    /**
+     * The parsed Rocksim UsageCode.
+     */
+    private int usageCode = 0;
+
+    /**
+     * Constructor.
+     *
+     * @param theParent the parent component
+     * @param warnings  the warning set
+     * @throws IllegalArgumentException thrown if <code>c</code> is null
+     */
+    public RingHandler(RocketComponent theParent, WarningSet warnings) throws IllegalArgumentException {
+        if (theParent == null) {
+            throw new IllegalArgumentException("The parent of a ring may not be null.");
+        }
+        parent = theParent;
+    }
+
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        super.closeElement(element, attributes, content, warnings);
+
+        try {
+            if ("OD".equals(element)) {
+                ring.setOuterRadius(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+            }
+            if ("ID".equals(element)) {
+                ring.setInnerRadius(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS);
+            }
+            if ("Len".equals(element)) {
+                ring.setLength(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            }
+            if ("Material".equals(element)) {
+                setMaterialName(content);
+            }
+            if ("UsageCode".equals(element)) {
+                usageCode = Integer.parseInt(content);
+            }
+        } catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+    /**
+     * Get the ring component this handler is working upon.
+     *
+     * @return a component
+     */
+    @Override
+    public CenteringRing getComponent() {
+        return ring;
+    }
+
+    /**
+     * This method adds the CenteringRing as a child of the parent rocket component.
+     *
+     * @param warnings the warning set
+     */
+    public void asCenteringRing(WarningSet warnings) {
+
+        if (isCompatible(parent, CenteringRing.class, warnings)) {
+            parent.addChild(ring);
+        }
+    }
+
+    /**
+     * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's Bulkhead.
+     * <p/>
+     * Side Effect Warning: This method adds the resulting Bulkhead as a child of the parent rocket component!
+     *
+     * @param warnings the warning set
+     */
+    public void asBulkhead(WarningSet warnings) {
+
+        Bulkhead result = new Bulkhead();
+
+        copyValues(result);
+
+        if (isCompatible(parent, Bulkhead.class, warnings)) {
+            parent.addChild(result);
+        }
+    }
+
+    /**
+     * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's TubeCoupler.
+     * <p/>
+     * Side Effect Warning: This method adds the resulting TubeCoupler as a child of the parent rocket component!
+     *
+     * @param warnings the warning set
+     */
+    public void asTubeCoupler(WarningSet warnings) {
+
+        TubeCoupler result = new TubeCoupler();
+
+        copyValues(result);
+
+        if (isCompatible(parent, TubeCoupler.class, warnings)) {
+            parent.addChild(result);
+        }
+    }
+
+    /**
+     * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's Engine Block.
+     * <p/>
+     * Side Effect Warning: This method adds the resulting EngineBlock as a child of the parent rocket component!
+     *
+     * @param warnings the warning set
+     */
+    public void asEngineBlock(WarningSet warnings) {
+
+        EngineBlock result = new EngineBlock();
+
+        copyValues(result);
+
+        if (isCompatible(parent, EngineBlock.class, warnings)) {
+            parent.addChild(result);
+        }
+    }
+
+    /**
+     * Copy values from the base ring to the specific component.
+     *
+     * @param result the target to which ring values will be copied
+     */
+    private void copyValues(RingComponent result) {
+        result.setOuterRadius(ring.getOuterRadius());
+        result.setInnerRadius(ring.getInnerRadius());
+        result.setLength(ring.getLength());
+        result.setName(ring.getName());
+        setOverride(result, ring.isOverrideSubcomponentsEnabled(), ring.getOverrideMass(), ring.getOverrideCGX());
+        result.setRelativePosition(ring.getRelativePosition());
+        result.setPositionValue(ring.getPositionValue());
+        result.setMaterial(ring.getMaterial());
+    }
+
+    /**
+     * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not
+     * public in all components.
+     *
+     * @param position the OpenRocket position
+     */
+    @Override
+    public void setRelativePosition(RocketComponent.Position position) {
+        ring.setRelativePosition(position);
+    }
+
+    @Override
+    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
+        super.endHandler(element, attributes, content, warnings);
+
+        // The <Ring> XML element in Rocksim design file is used for many types of components, unfortunately.
+        // Additional subelements are used to indicate the type of the rocket component. When parsing using SAX
+        // this poses a problem because we can't "look ahead" to see what type is being represented at the start
+        // of parsing - something that would be nice to do so that we can instantiate the correct OR component
+        // at the start, then just call setters for the appropriate data.
+
+        // To overcome that, a CenteringRing is instantiated at the start of parsing, it's mutators are called,
+        // and then at the end (this method) converts the CenteringRing to a more appropriate type.  CenteringRing
+        // is generic enough to support the representation of all similar types without loss of data.
+
+        //UsageCode
+        // 0 == Centering Ring
+        // 1 == Bulkhead
+        // 2 == Engine Block
+        // 3 == Sleeve
+        // 4 == Tube Coupler
+
+        if (usageCode == 1) {
+            //Bulkhead
+            asBulkhead(warnings);
+        } else if (usageCode == 2) {
+            asEngineBlock(warnings);
+        } else if (usageCode == 4) {
+            //TubeCoupler
+            asTubeCoupler(warnings);
+        } else {
+            //Default
+            asCenteringRing(warnings);
+        }
+    }
+
+    /**
+     * Get the required type of material for this component.
+     *
+     * @return BULK
+     */
+    @Override
+    public Material.Type getMaterialType() {
+        return Material.Type.BULK;
+    }
+}
\ No newline at end of file
diff --git a/src/net/sf/openrocket/file/rocksim/importt/RocksimDensityType.java b/src/net/sf/openrocket/file/rocksim/importt/RocksimDensityType.java
new file mode 100644 (file)
index 0000000..9e70fa8
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * RocksimDensityType.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.material.Material;
+
+/**
+ * Models the nose cone shape of a rocket.  Maps from Rocksim's notion to OpenRocket's.
+ */
+public enum RocksimDensityType {
+    ROCKSIM_BULK   (0, RocksimHandler.ROCKSIM_TO_OPENROCKET_BULK_DENSITY),
+    ROCKSIM_SURFACE(1, RocksimHandler.ROCKSIM_TO_OPENROCKET_SURFACE_DENSITY),
+    ROCKSIM_LINE   (2, RocksimHandler.ROCKSIM_TO_OPENROCKET_LINE_DENSITY);
+
+    /** The Rocksim enumeration value. Sent in XML. */
+    private final int ordinal;
+
+    /** The corresponding OpenRocket shape. */
+    private final double conversion;
+
+    /**
+     * Constructor.
+     *
+     * @param idx            the Rocksim shape code
+     * @param theConversion  the numerical conversion ratio to OpenRocket
+     */
+    private RocksimDensityType(int idx, double theConversion) {
+        ordinal = idx;
+        conversion = theConversion;
+    }
+
+    /**
+     * Get the OpenRocket shape that corresponds to the Rocksim value.
+     *
+     * @return a conversion
+     */
+    public double asOpenRocket() {
+        return conversion;
+    }
+
+    /**
+     * Lookup an instance of this enum based upon the Rocksim code.
+     *
+     * @param rocksimDensityType  the Rocksim code (from XML)
+     * @return an instance of this enum
+     */
+    public static RocksimDensityType fromCode(int rocksimDensityType) {
+        RocksimDensityType[] values = values();
+        for (RocksimDensityType value : values) {
+            if (value.ordinal == rocksimDensityType) {
+                return value;
+            }
+        }
+        return ROCKSIM_BULK; //Default
+    }
+
+    /**
+     * Get the ordinal code.
+     *
+     * @param type  the OR type
+     *
+     * @return  the Rocksim XML value
+     */
+    public static int toCode(Material.Type type) {
+        if (type.equals(Material.Type.BULK)) {
+            return ROCKSIM_BULK.ordinal;
+        }
+        if (type.equals(Material.Type.LINE)) {
+            return ROCKSIM_LINE.ordinal;
+        }
+        if (type.equals(Material.Type.SURFACE)) {
+            return ROCKSIM_SURFACE.ordinal;
+        }
+        return ROCKSIM_BULK.ordinal;
+    }
+}
+
diff --git a/src/net/sf/openrocket/file/rocksim/importt/RocksimFinishCode.java b/src/net/sf/openrocket/file/rocksim/importt/RocksimFinishCode.java
new file mode 100644 (file)
index 0000000..658db56
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * RocksimFinishCode.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.rocketcomponent.ExternalComponent;
+
+/**
+ * Models the finish of a component.
+ */
+public enum RocksimFinishCode {
+    POLISHED(0, ExternalComponent.Finish.POLISHED),
+    GLOSS(1, ExternalComponent.Finish.SMOOTH),
+    MATT(2, ExternalComponent.Finish.NORMAL),
+    UNFINISHED(3, ExternalComponent.Finish.UNFINISHED);
+
+    /** The Rocksim code (from XML). */
+    private final int ordinal;
+    
+    /** The corresponding OpenRocket finish. */
+    private final ExternalComponent.Finish finish;
+
+    /**
+     * Constructor.
+     * 
+     * @param idx   the Rocksim enum value
+     * @param theFinish  the OpenRocket finish
+     */
+    private RocksimFinishCode(int idx, ExternalComponent.Finish theFinish) {
+        ordinal = idx;
+        finish = theFinish;
+    }
+
+    /**
+     * Get the OpenRocket finish.
+     * 
+     * @return a Finish instance
+     */
+    public ExternalComponent.Finish asOpenRocket() {
+        return finish;
+    }
+
+    /**
+     * Lookup an instance of this enum from a Rocksim value.
+     * 
+     * @param rocksimFinishCode  the Rocksim value
+     * 
+     * @return an instance of this enum; Defaults to MATT
+     */
+    public static RocksimFinishCode fromCode(int rocksimFinishCode) {
+        RocksimFinishCode[] values = values();
+        for (RocksimFinishCode value : values) {
+            if (value.ordinal == rocksimFinishCode) {
+                return value;
+            }
+        }
+        return MATT; //Default
+    }
+
+    /**
+     * Get the ordinal code.
+     *
+     * @param type  the OR type
+     *
+     * @return  the Rocksim XML value
+     */
+    public static int toCode(ExternalComponent.Finish type) {
+        if (type.equals(ExternalComponent.Finish.UNFINISHED)) {
+            return UNFINISHED.ordinal;
+        }
+        if (type.equals(ExternalComponent.Finish.POLISHED)) {
+            return POLISHED.ordinal;
+        }
+        if (type.equals(ExternalComponent.Finish.SMOOTH)) {
+            return GLOSS.ordinal;
+        }
+        return MATT.ordinal;
+    }
+
+}
+
diff --git a/src/net/sf/openrocket/file/rocksim/importt/RocksimHandler.java b/src/net/sf/openrocket/file/rocksim/importt/RocksimHandler.java
new file mode 100644 (file)
index 0000000..7d2d527
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * RocksimHandler.java
+ *
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.Warning;
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.file.simplesax.ElementHandler;
+import net.sf.openrocket.file.simplesax.PlainTextHandler;
+import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.Stage;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * This class is a Sax element handler for Rocksim version 9 design files.  It parses the Rocksim file (typically
+ * a .rkt extension) and creates corresponding OpenRocket components.  This is a best effort approach and may not
+ * be an exact replica.
+ * <p/>
+ * Limitations: Rocksim flight simulations are not imported; tube fins are not supported; Rocksim 'pods' are not supported.
+ */
+public class RocksimHandler extends ElementHandler {
+
+    /**
+     * Length conversion.  Rocksim is in millimeters, OpenRocket in meters.
+     */
+    public static final int ROCKSIM_TO_OPENROCKET_LENGTH = 1000;
+
+    /**
+     * Mass conversion.  Rocksim is in grams, OpenRocket in kilograms.
+     */
+    public static final int ROCKSIM_TO_OPENROCKET_MASS = 1000;
+
+    /**
+     * Bulk Density conversion.  Rocksim is in kilograms/cubic meter, OpenRocket in kilograms/cubic meter.
+     */
+    public static final int ROCKSIM_TO_OPENROCKET_BULK_DENSITY = 1;
+
+    /**
+     * Surface Density conversion.  Rocksim is in grams/sq centimeter, OpenRocket in kilograms/sq meter.  1000/(100*100) = 1/10
+     */
+    public static final double ROCKSIM_TO_OPENROCKET_SURFACE_DENSITY = 1/10d;
+
+    /**
+     * Line Density conversion.  Rocksim is in kilograms/meter, OpenRocket in kilograms/meter. 
+     */
+    public static final int ROCKSIM_TO_OPENROCKET_LINE_DENSITY = 1;
+
+    /**
+     * Radius conversion.  Rocksim is always in diameters, OpenRocket mostly in radius.
+     */
+    public static final int ROCKSIM_TO_OPENROCKET_RADIUS = 2 * ROCKSIM_TO_OPENROCKET_LENGTH;
+
+    /**
+     * The main content handler.
+     */
+    private RocksimContentHandler handler = null;
+
+    /**
+     * Return the OpenRocketDocument read from the file, or <code>null</code> if a document
+     * has not been read yet.
+     *
+     * @return the document read, or null.
+     */
+    public OpenRocketDocument getDocument() {
+        return handler.getDocument();
+    }
+
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes,
+                                      WarningSet warnings) {
+
+        // Check for unknown elements
+        if (!element.equals("RockSimDocument")) {
+            warnings.add(Warning.fromString("Unknown element " + element + ", ignoring."));
+            return null;
+        }
+
+        // Check for first call
+        if (handler != null) {
+            warnings.add(Warning.fromString("Multiple document elements found, ignoring later "
+                                            + "ones."));
+            return null;
+        }
+
+        handler = new RocksimContentHandler();
+        return handler;
+    }
+
+}
+
+/**
+ * Handles the content of the <DesignInformation> tag.
+ */
+class RocksimContentHandler extends ElementHandler {
+    /**
+     * The OpenRocketDocument that is the container for the rocket.
+     */
+    private final OpenRocketDocument doc;
+
+    /**
+     * The top-level component, from which all child components are added.
+     */
+    private final Rocket rocket;
+
+    /**
+     * The rocksim file version.
+     */
+    private String version;
+
+    /**
+     * Constructor.
+     */
+    public RocksimContentHandler() {
+        this.rocket = new Rocket();
+        this.doc = new OpenRocketDocument(rocket);
+    }
+
+    /**
+     * Get the OpenRocket document that has been created from parsing the Rocksim design file.
+     *
+     * @return the instantiated OpenRocketDocument
+     */
+    public OpenRocketDocument getDocument() {
+        return doc;
+    }
+
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes,
+                                      WarningSet warnings) {
+        if ("DesignInformation".equals(element)) {
+            //The next sub-element is "RocketDesign", which is really the only thing that matters.  Rather than
+            //create another handler just for that element, handle it here.
+            return this;
+        }
+        if ("FileVersion".equals(element)) {
+            return PlainTextHandler.INSTANCE;
+        }
+        if ("RocketDesign".equals(element)) {
+            return new RocketDesignHandler(rocket);
+        }
+        return null;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes,
+                             String content, WarningSet warnings) throws SAXException {
+        /**
+         * SAX handler for Rocksim file version number.  The value is not used currently, but could be used in the future
+         * for backward/forward compatibility reasons (different lower level handlers could be called via a strategy pattern).
+         */
+        if ("FileVersion".equals(element)) {
+            version = content;
+        }
+    }
+
+    /**
+     * Answer the file version.
+     *
+     * @return the version of the Rocksim design file
+     */
+    public String getVersion() {
+        return version;
+    }
+}
+
+
+/**
+ * A SAX handler for the high level Rocksim design.  This structure includes sub-structures for each of the stages.
+ * Correct functioning of this handler is predicated on the stage count element appearing before the actual stage parts
+ * structures.  If that invariant is not true, then behavior will be unpredictable.
+ */
+class RocketDesignHandler extends ElementHandler {
+    /**
+     * The parent component.
+     */
+    private final RocketComponent component;
+    /**
+     * The parsed stage count.  Defaults to 1.
+     */
+    private int stageCount = 1;
+    /**
+     * The overridden stage 1 mass.
+     */
+    private double stage1Mass = 0d;
+    /**
+     * The overridden stage 2 mass.
+     */
+    private double stage2Mass = 0d;
+    /**
+     * The overridden stage 3 mass.
+     */
+    private double stage3Mass = 0d;
+    /**
+     * The overridden stage 1 Cg.
+     */
+    private double stage1CG = 0d;
+    /**
+     * The overridden stage 2 Cg.
+     */
+    private double stage2CG = 0d;
+    /**
+     * The overridden stage 3 Cg.
+     */
+    private double stage3CG = 0d;
+
+    /**
+     * Constructor.
+     *
+     * @param c the parent component
+     */
+    public RocketDesignHandler(RocketComponent c) {
+        component = c;
+    }
+
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        /**
+         * In Rocksim stages are from the top down, so a single stage rocket is actually stage '3'.  A 2-stage
+         * rocket defines stage '2' as the initial booster with stage '3' sitting atop it.  And so on.
+         */
+        if ("Stage3Parts".equals(element)) {
+            final Stage stage = new Stage();
+            if (stage3Mass > 0.0d) {
+                stage.setMassOverridden(true);
+                stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override
+                stage.setOverrideMass(stage3Mass);
+            }
+            if (stage3CG > 0.0d) {
+                stage.setCGOverridden(true);
+                stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override
+                stage.setOverrideCGX(stage3CG);
+            }
+            component.addChild(stage);
+            return new StageHandler(stage);
+        }
+        if ("Stage2Parts".equals(element)) {
+            if (stageCount >= 2) {
+                final Stage stage = new Stage();
+                if (stage2Mass > 0.0d) {
+                    stage.setMassOverridden(true);
+                    stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override
+                    stage.setOverrideMass(stage2Mass);
+                }
+                if (stage2CG > 0.0d) {
+                    stage.setCGOverridden(true);
+                    stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override
+                    stage.setOverrideCGX(stage2CG);
+                }
+                component.addChild(stage);
+                return new StageHandler(stage);
+            }
+        }
+        if ("Stage1Parts".equals(element)) {
+            if (stageCount == 3) {
+                final Stage stage = new Stage();
+                if (stage1Mass > 0.0d) {
+                    stage.setMassOverridden(true);
+                    stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override
+                    stage.setOverrideMass(stage1Mass);
+                }
+                if (stage1CG > 0.0d) {
+                    stage.setCGOverridden(true);
+                    stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override
+                    stage.setOverrideCGX(stage1CG);
+                }
+                component.addChild(stage);
+                return new StageHandler(stage);
+            }
+        }
+        if ("Name".equals(element)) {
+            return PlainTextHandler.INSTANCE;
+        }
+        if ("StageCount".equals(element)) {
+            return PlainTextHandler.INSTANCE;
+        }
+        if ("Stage3Mass".equals(element)) {
+            return PlainTextHandler.INSTANCE;
+        }
+        if ("Stage2Mass".equals(element)) {
+            return PlainTextHandler.INSTANCE;
+        }
+        if ("Stage1Mass".equals(element)) {
+            return PlainTextHandler.INSTANCE;
+        }
+        if ("Stage3CG".equals(element)) {
+            return PlainTextHandler.INSTANCE;
+        }
+        if ("Stage2CGAlone".equals(element)) {
+            return PlainTextHandler.INSTANCE;
+        }
+        if ("Stage1CGAlone".equals(element)) {
+            return PlainTextHandler.INSTANCE;
+        }
+        return null;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes,
+                             String content, WarningSet warnings) throws SAXException {
+        try {
+            if ("Name".equals(element)) {
+                component.setName(content);
+            }
+            if ("StageCount".equals(element)) {
+                stageCount = Integer.parseInt(content);
+            }
+            if ("Stage3Mass".equals(element)) {
+                stage3Mass = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS;
+            }
+            if ("Stage2Mass".equals(element)) {
+                stage2Mass = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS;
+            }
+            if ("Stage1Mass".equals(element)) {
+                stage1Mass = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS;
+            }
+            if ("Stage3CG".equals(element)) {
+                stage3CG = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("Stage2CGAlone".equals(element)) {
+                stage2CG = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("Stage1CGAlone".equals(element)) {
+                stage1CG = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+}
+
+/**
+ * A SAX handler for a Rocksim stage.
+ */
+class StageHandler extends ElementHandler {
+    /**
+     * The parent OpenRocket component.
+     */
+    private final RocketComponent component;
+
+    /**
+     * Constructor.
+     *
+     * @param c the parent component
+     * @throws IllegalArgumentException thrown if <code>c</code> is null
+     */
+    public StageHandler(RocketComponent c) throws IllegalArgumentException {
+        if (c == null) {
+            throw new IllegalArgumentException("The stage component may not be null.");
+        }
+        component = c;
+    }
+
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        if ("NoseCone".equals(element)) {
+            return new NoseConeHandler(component, warnings);
+        }
+        if ("BodyTube".equals(element)) {
+            return new BodyTubeHandler(component, warnings);
+        }
+        if ("Transition".equals(element)) {
+            return new TransitionHandler(component, warnings);
+        }
+        return null;
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/importt/RocksimLoader.java b/src/net/sf/openrocket/file/rocksim/importt/RocksimLoader.java
new file mode 100644 (file)
index 0000000..a58a855
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * RocksimLoader.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.file.RocketLoadException;
+import net.sf.openrocket.file.RocketLoader;
+import net.sf.openrocket.file.simplesax.SimpleSAX;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class is the main entry point for Rocksim design file imported to OpenRocket.  Currently only Rocksim v9
+ * file formats are supported, although it is possible that v8 formats will work for most components.
+ * 
+ * In the cases of v9 components that exist in Rocksim but have no corollary in OpenRocket a message is added to
+ * a warning set and presented to the user.  In effect, this loading is a 'best-effort' mapping and is not meant to
+ * be an exact representation of any possible Rocksim design in an OpenRocket format.
+ * 
+ * Rocksim simulations are not imported.
+ * 
+ * Wish List:
+ *       Material interface (or at least make them abstract in RocketComponent)
+ *          setMaterial
+ *          getMaterial
+ */
+public class RocksimLoader extends RocketLoader {
+       /**
+        * This method is called by the default implementations of {@link #load(java.io.File)}
+        * and {@link #load(java.io.InputStream)} to load the rocket.
+        *
+        * @throws net.sf.openrocket.file.RocketLoadException
+        *          if an error occurs during loading.
+        */
+       @Override
+       protected OpenRocketDocument loadFromStream(InputStream source) throws IOException, RocketLoadException {
+               
+               InputSource xmlSource = new InputSource(source);
+               
+               RocksimHandler handler = new RocksimHandler();
+               
+               try {
+                       SimpleSAX.readXML(xmlSource, handler, warnings);
+               } catch (SAXException e) {
+                       throw new RocketLoadException("Malformed XML in input.", e);
+               }
+               
+               final OpenRocketDocument document = handler.getDocument();
+               document.setFile(null);
+               document.clearUndo();
+               return document;
+       }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/importt/RocksimLocationMode.java b/src/net/sf/openrocket/file/rocksim/importt/RocksimLocationMode.java
new file mode 100644 (file)
index 0000000..02daeb8
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * RocksimLocationMode.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+
+/**
+ * Models the relative position of parts on a rocket.  Maps from Rocksim's notion to OpenRocket's.
+ */
+public enum RocksimLocationMode {
+    FRONT_OF_OWNING_PART (0, RocketComponent.Position.TOP),
+    FROM_TIP_OF_NOSE     (1, RocketComponent.Position.ABSOLUTE),
+    BACK_OF_OWNING_PART  (2, RocketComponent.Position.BOTTOM);
+
+    /** The value Rocksim uses internally (and in the XML file). */
+    private final int ordinal;
+    
+    /** The OpenRocket position equivalent. */
+    private final RocketComponent.Position position;
+
+    /**
+     * Constructor.
+     * 
+     * @param idx   the rocksim enum value
+     * @param theOpenRocketPosition  the corresponding OpenRocket position
+     */
+    RocksimLocationMode(int idx, RocketComponent.Position theOpenRocketPosition) {
+        ordinal = idx;
+        position = theOpenRocketPosition;
+    }
+
+    /**
+     * Get the OpenRocket position.
+     * 
+     * @return  the position instance
+     */
+    public RocketComponent.Position asOpenRocket() {
+        return position;
+    }
+
+    /**
+     * Lookup an instance of this class from a rocksim enum value.
+     * 
+     * @param rocksimCode  the rocksim enum value
+     * 
+     * @return an instance of this enum
+     */
+    public static RocksimLocationMode fromCode(int rocksimCode) {
+        RocksimLocationMode[] values = values();
+        for (RocksimLocationMode value : values) {
+            if (value.ordinal == rocksimCode) {
+                return value;
+            }
+        }
+        return FRONT_OF_OWNING_PART;
+    }
+
+    public static int toCode(RocketComponent.Position position) {
+        if (RocketComponent.Position.TOP.equals(position)) {
+            return 0;
+        }
+        if (RocketComponent.Position.ABSOLUTE.equals(position)) {
+            return 1;
+        }
+        if (RocketComponent.Position.BOTTOM.equals(position)) {
+            return 2;
+        }
+        return 0;
+    }
+}
\ No newline at end of file
diff --git a/src/net/sf/openrocket/file/rocksim/importt/RocksimNoseConeCode.java b/src/net/sf/openrocket/file/rocksim/importt/RocksimNoseConeCode.java
new file mode 100644 (file)
index 0000000..0454002
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * RocksimNoseConeCode.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.rocketcomponent.Transition;
+
+/**
+ * Models the nose cone shape of a rocket.  Maps from Rocksim's notion to OpenRocket's.
+ */
+public enum RocksimNoseConeCode {
+    CONICAL         (0, Transition.Shape.CONICAL),
+    OGIVE           (1, Transition.Shape.OGIVE),
+    PARABOLIC       (2, Transition.Shape.ELLIPSOID),  //Rocksim' PARABOLIC most closely resembles an ELLIPSOID in OpenRocket
+    ELLIPTICAL      (3, Transition.Shape.ELLIPSOID),
+    POWER_SERIES    (4, Transition.Shape.POWER),
+    PARABOLIC_SERIES(5, Transition.Shape.PARABOLIC),
+    HAACK           (6, Transition.Shape.HAACK);
+
+    /** The Rocksim enumeration value. Sent in XML. */
+    private final int ordinal;
+    
+    /** The corresponding OpenRocket shape. */
+    private final Transition.Shape shape;
+
+    /**
+     * Constructor.
+     * 
+     * @param idx    the Rocksim shape code
+     * @param aShape the corresponding OpenRocket shape
+     */
+    private RocksimNoseConeCode(int idx, Transition.Shape aShape) {
+        ordinal = idx;
+        shape = aShape;
+    }
+
+    /**
+     * Get the OpenRocket shape that corresponds to the Rocksim shape.
+     * 
+     * @return a shape
+     */
+    public Transition.Shape asOpenRocket() {
+        return shape;
+    }
+
+    /**
+     * Lookup an instance of this enum based upon the Rocksim code.
+     * 
+     * @param rocksimShapeCode  the Rocksim code (from XML)
+     * @return an instance of this enum
+     */
+    public static RocksimNoseConeCode fromCode(int rocksimShapeCode) {
+        RocksimNoseConeCode[] values = values();
+        for (RocksimNoseConeCode value : values) {
+            if (value.ordinal == rocksimShapeCode) {
+                return value;
+            }
+        }
+        return PARABOLIC; //Default
+    }
+
+    /**
+     * Lookup an ordinal value for the Rocksim code.
+     * 
+     * @param type  the OR Shape
+     *              
+     * @return the Rocksim code
+     */
+    public static int toCode(Transition.Shape type) {
+        RocksimNoseConeCode[] values = values();
+        for (RocksimNoseConeCode value : values) {
+            if (value.shape.equals(type)) {
+                if (value.ordinal == 2) {
+                    return 3;
+                }
+                return value.ordinal;
+            }
+        }
+        return ELLIPTICAL.ordinal; //Default
+    }
+}
diff --git a/src/net/sf/openrocket/file/rocksim/importt/StreamerHandler.java b/src/net/sf/openrocket/file/rocksim/importt/StreamerHandler.java
new file mode 100644 (file)
index 0000000..3002a78
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * StreamerHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.ElementHandler;
+import net.sf.openrocket.file.simplesax.PlainTextHandler;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.Streamer;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * A SAX handler for Streamer components.
+ */
+class StreamerHandler extends RecoveryDeviceHandler<Streamer> {
+
+    /**
+     * The OpenRocket Streamer.
+     */
+    private final Streamer streamer;
+
+    /**
+     * Constructor.
+     *
+     * @param c the parent component
+     * @param warnings  the warning set
+     * 
+     * @throws IllegalArgumentException thrown if <code>c</code> is null
+     */
+    public StreamerHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
+        if (c == null) {
+            throw new IllegalArgumentException("The parent of a streamer may not be null.");
+        }
+        streamer = new Streamer();
+        if (isCompatible(c, Streamer.class, warnings)) {
+            c.addChild(streamer);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        super.closeElement(element, attributes, content, warnings);
+
+        try {
+            if ("Width".equals(element)) {
+                streamer.setStripWidth(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
+            }
+            if ("Len".equals(element)) {
+                streamer.setStripLength(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
+            }
+            if ("DragCoefficient".equals(element)) {
+                streamer.setCD(Double.parseDouble(content));
+            }
+            if ("Material".equals(element)) {
+                setMaterialName(content);
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Streamer getComponent() {
+        return streamer;
+    }
+
+}
+
diff --git a/src/net/sf/openrocket/file/rocksim/importt/TransitionHandler.java b/src/net/sf/openrocket/file/rocksim/importt/TransitionHandler.java
new file mode 100644 (file)
index 0000000..b589b67
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * TransitionHandler.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+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.RocketComponent;
+import net.sf.openrocket.rocketcomponent.Transition;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * The SAX handler for Transition components.
+ */
+class TransitionHandler extends BaseHandler<Transition> {
+    /**
+     * The OpenRocket Transition.
+     */
+    private final Transition transition = new Transition();
+
+    /**
+     * The wall thickness.  Used for hollow nose cones.
+     */
+    private double thickness = 0d;
+
+    /**
+     * Constructor.
+     *
+     * @param c the parent component
+     * @param warnings  the warning set
+     * @throws IllegalArgumentException thrown if <code>c</code> is null
+     */
+    public TransitionHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
+        if (c == null) {
+            throw new IllegalArgumentException("The parent of a transition may not be null.");
+        }
+        if (isCompatible(c, Transition.class, warnings)) {
+            c.addChild(transition);
+        }
+    }
+
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes,
+                             String content, WarningSet warnings) throws SAXException {
+        super.closeElement(element, attributes, content, warnings);
+
+        try {
+            if ("ShapeCode".equals(element)) {
+                transition.setType(RocksimNoseConeCode.fromCode(Integer.parseInt(content)).asOpenRocket());
+            }
+            if ("Len".equals(element)) {
+                transition.setLength(Math.max(0, Double.parseDouble(
+                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
+            }
+            if ("FrontDia".equals(element)) {
+                transition.setForeRadius(Math.max(0, Double.parseDouble(
+                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
+            }
+            if ("RearDia".equals(element)) {
+                transition.setAftRadius(Math.max(0, Double.parseDouble(
+                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
+            }
+            if ("WallThickness".equals(element)) {
+                thickness = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            }
+            if ("FrontShoulderDia".equals(element)) {
+                transition.setForeShoulderRadius(Math.max(0d, Double.parseDouble(
+                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
+            }
+            if ("RearShoulderDia".equals(element)) {
+                transition.setAftShoulderRadius(Math.max(0d, Double.parseDouble(
+                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS));
+            }
+            if ("FrontShoulderLen".equals(element)) {
+                transition.setForeShoulderLength(Math.max(0d, Double.parseDouble(
+                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
+            }
+            if ("RearShoulderLen".equals(element)) {
+                transition.setAftShoulderLength(Math.max(0d, Double.parseDouble(
+                        content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH));
+            }
+            if ("ShapeParameter".equals(element)) {
+                if (Transition.Shape.POWER.equals(transition.getType()) ||
+                    Transition.Shape.HAACK.equals(transition.getType()) ||
+                    Transition.Shape.PARABOLIC.equals(transition.getType())) {
+                    transition.setShapeParameter(Double.parseDouble(content));
+                }
+            }
+            if ("ConstructionType".equals(element)) {
+                int typeCode = Integer.parseInt(content);
+                if (typeCode == 0) {
+                    //SOLID
+                    transition.setFilled(true);
+                }
+                else if (typeCode == 1) {
+                    //HOLLOW
+                    transition.setFilled(false);
+                }
+            }
+            if ("FinishCode".equals(element)) {
+                transition.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket());
+            }
+            if ("Material".equals(element)) {
+                setMaterialName(content);
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+    @Override
+    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        super.endHandler(element, attributes, content, warnings);
+
+        if (transition.isFilled()) {
+            transition.setAftShoulderThickness(transition.getAftShoulderRadius());
+            transition.setForeShoulderThickness(transition.getForeShoulderRadius());
+        }
+        else {
+            transition.setThickness(thickness);
+            transition.setAftShoulderThickness(thickness);
+            transition.setForeShoulderThickness(thickness);
+        }
+    }
+
+
+    @Override
+    public Transition getComponent() {
+        return transition;
+    }
+
+    /**
+     * Get the required type of material for this component.
+     *
+     * @return BULK
+     */
+    public Material.Type getMaterialType() {
+        return Material.Type.BULK;
+    }
+
+
+}
+
index 04175fe5947326aed6dc3015b8d50283baf9a8a8..b6bab93905ae28b1ee8f324e28b9c23eb06dc0fa 100644 (file)
@@ -1,62 +1,5 @@
 package net.sf.openrocket.gui.main;
 
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.Toolkit;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-
-import javax.swing.Action;
-import javax.swing.BorderFactory;
-import javax.swing.InputMap;
-import javax.swing.JButton;
-import javax.swing.JComponent;
-import javax.swing.JFileChooser;
-import javax.swing.JFrame;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JPopupMenu;
-import javax.swing.JScrollPane;
-import javax.swing.JSpinner;
-import javax.swing.JSplitPane;
-import javax.swing.JTabbedPane;
-import javax.swing.JTextField;
-import javax.swing.KeyStroke;
-import javax.swing.ListSelectionModel;
-import javax.swing.ScrollPaneConstants;
-import javax.swing.SwingUtilities;
-import javax.swing.border.BevelBorder;
-import javax.swing.border.TitledBorder;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.DefaultTreeSelectionModel;
-import javax.swing.tree.TreePath;
-import javax.swing.tree.TreeSelectionModel;
-
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.aerodynamics.WarningSet;
 import net.sf.openrocket.document.OpenRocketDocument;
@@ -65,6 +8,7 @@ import net.sf.openrocket.file.RocketLoadException;
 import net.sf.openrocket.file.RocketLoader;
 import net.sf.openrocket.file.RocketSaver;
 import net.sf.openrocket.file.openrocket.OpenRocketSaver;
+import net.sf.openrocket.file.rocksim.export.RocksimSaver;
 import net.sf.openrocket.gui.StorageOptionChooser;
 import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
 import net.sf.openrocket.gui.dialogs.AboutDialog;
@@ -104,6 +48,38 @@ import net.sf.openrocket.util.MemoryManagement.MemoryData;
 import net.sf.openrocket.util.Reflection;
 import net.sf.openrocket.util.TestRockets;
 
+import javax.swing.*;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultTreeSelectionModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
 public class BasicFrame extends JFrame {
        private static final LogHelper log = Application.getLogger();
        
@@ -1277,7 +1253,9 @@ public class BasicFrame extends JFrame {
                StorageOptionChooser storageChooser =
                                new StorageOptionChooser(document, document.getDefaultStorageOptions());
                JFileChooser chooser = new JFileChooser();
-               chooser.setFileFilter(FileHelper.OPENROCKET_DESIGN_FILTER);
+        chooser.addChoosableFileFilter(FileHelper.OPENROCKET_DESIGN_FILTER);
+        chooser.addChoosableFileFilter(FileHelper.ROCKSIM_DESIGN_FILTER);
+        chooser.setFileFilter(FileHelper.OPENROCKET_DESIGN_FILTER);
                chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
                chooser.setAccessory(storageChooser);
                if (document.getFile() != null)
@@ -1298,12 +1276,30 @@ public class BasicFrame extends JFrame {
                ((SwingPreferences) Application.getPreferences()).setDefaultDirectory(chooser.getCurrentDirectory());
                storageChooser.storeOptions(document.getDefaultStorageOptions());
                
-               file = FileHelper.ensureExtension(file, "ork");
-               if (!FileHelper.confirmWrite(file, this)) {
-                       return false;
-               }
-               
-               return saveAs(file);
+        if (chooser.getFileFilter().equals(FileHelper.OPENROCKET_DESIGN_FILTER)) {
+                   file = FileHelper.ensureExtension(file, "ork");
+                   if (!FileHelper.confirmWrite(file, this)) {
+                           return false;
+               }
+               
+               return saveAs(file);
+        }
+        else if (chooser.getFileFilter().equals(FileHelper.ROCKSIM_DESIGN_FILTER)) {
+            file = FileHelper.ensureExtension(file, "rkt");
+            if (!FileHelper.confirmWrite(file, this)) {
+                return false;
+            }
+
+            try {
+                new RocksimSaver().save(file, document);
+                return true;
+            } catch (IOException e) {
+                return false;
+            }
+        }
+        else {
+            return false;
+        }
        }
        
        private boolean saveAs(File file) {
index fc118881dc042fa97cd1ee635c5021c6d3c37a6c..24c773e589b5c841aae1f469aa716e5c942ae108 100644 (file)
@@ -1,13 +1,13 @@
 package net.sf.openrocket.rocketcomponent;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.MathUtil;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * A set of trapezoidal fins.  The root and tip chords are perpendicular to the rocket
  * base line, while the leading and aft edges may be slanted.
@@ -109,7 +109,7 @@ public class TrapezoidFinSet extends FinSet {
        
        /**
         * Get the sweep angle.  This is calculated from the true sweep and height, and is not
-        * stored separetely.
+        * stored separately.
         */
        public double getSweepAngle() {
                if (height == 0) {
index ddfc1fcb9081bb5ff6e6dc87c4427a2136360a89..91530a302cd9c522916bf9152897b3a874652ddf 100644 (file)
@@ -1,21 +1,20 @@
 package net.sf.openrocket.utils;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.Locale;
-
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.document.StorageOptions;
 import net.sf.openrocket.file.RocketLoadException;
 import net.sf.openrocket.file.RocketLoader;
 import net.sf.openrocket.file.RocketSaver;
 import net.sf.openrocket.file.openrocket.OpenRocketSaver;
-import net.sf.openrocket.file.rocksim.RocksimLoader;
 import net.sf.openrocket.gui.util.SwingPreferences;
 import net.sf.openrocket.l10n.ResourceBundleTranslator;
 import net.sf.openrocket.logging.LogLevel;
 import net.sf.openrocket.startup.Application;
 
+import java.io.File;
+import java.io.IOException;
+import java.util.Locale;
+
 /**
  * Utility that loads Rocksim file formats and saves them in ORK format.
  * File is saved with the .rkt extension replaced with .ork.
@@ -32,7 +31,7 @@ public class RocksimConverter {
                
                setup();
                
-               RocketLoader loader = new RocksimLoader();
+               RocketLoader loader = new net.sf.openrocket.file.rocksim.importt.RocksimLoader();
                RocketSaver saver = new OpenRocketSaver();
                
                for (String inputFile : args) {
diff --git a/test/net/sf/openrocket/file/rocksim/BodyTubeHandlerTest.java b/test/net/sf/openrocket/file/rocksim/BodyTubeHandlerTest.java
deleted file mode 100644 (file)
index 88a7892..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * BodyTubeHandlerTest.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.file.simplesax.PlainTextHandler;
-import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.ExternalComponent;
-import net.sf.openrocket.rocketcomponent.Stage;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.HashMap;
-
-/**
- * BodyTubeHandler Tester.
- *
- */
-public class BodyTubeHandlerTest extends RocksimTestBase {
-
-    /**
-     * Method: constructor
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testConstructor() throws Exception {
-
-        try {
-            new BodyTubeHandler(null, new WarningSet());
-            Assert.fail("Should have thrown IllegalArgumentException");
-        }
-        catch (IllegalArgumentException iae) {
-            //success
-        }
-
-        Stage stage = new Stage();
-        BodyTubeHandler handler = new BodyTubeHandler(stage, new WarningSet());
-        BodyTube component = (BodyTube) getField(handler, "bodyTube");
-        assertContains(component, stage.getChildren());
-    }
-
-    /**
-     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testOpenElement() throws Exception {
-        Assert.assertEquals(PlainTextHandler.INSTANCE, new BodyTubeHandler(new Stage(), new WarningSet()).openElement(null, null, null));
-        Assert.assertNotNull(new BodyTubeHandler(new Stage(), new WarningSet()).openElement("AttachedParts", null, null));
-    }
-
-    /**
-     *
-     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-     *
-     * @throws Exception  thrown if something goes awry
-     */
-    @Test
-    public void testCloseElement() throws Exception {
-        Stage stage = new Stage();
-        BodyTubeHandler handler = new BodyTubeHandler(stage, new WarningSet());
-        BodyTube component = (BodyTube) getField(handler, "bodyTube");
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        handler.closeElement("OD", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
-        handler.closeElement("OD", attributes, "0", warnings);
-        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
-        handler.closeElement("OD", attributes, "75", warnings);
-        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius(), 0.001);
-        handler.closeElement("OD", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("ID", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
-        handler.closeElement("ID", attributes, "0", warnings);
-        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
-        handler.closeElement("ID", attributes, "75", warnings);
-        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius(), 0.001);
-        handler.closeElement("ID", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Len", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("IsMotorMount", attributes, "1", warnings);
-        Assert.assertTrue(component.isMotorMount());
-        handler.closeElement("IsMotorMount", attributes, "0", warnings);
-        Assert.assertFalse(component.isMotorMount());
-        handler.closeElement("IsMotorMount", attributes, "foo", warnings);
-        Assert.assertFalse(component.isMotorMount());
-
-        handler.closeElement("EngineOverhang", attributes, "-1", warnings);
-        Assert.assertEquals(-1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang(), 0.001);
-        handler.closeElement("EngineOverhang", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang(), 0.001);
-        handler.closeElement("EngineOverhang", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang(), 0.001);
-        handler.closeElement("EngineOverhang", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("FinishCode", attributes, "-1", warnings);
-        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
-        handler.closeElement("FinishCode", attributes, "100", warnings);
-        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
-        handler.closeElement("FinishCode", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Name", attributes, "Test Name", warnings);
-        Assert.assertEquals("Test Name", component.getName());
-    }
-    
-    /**
-     * Method: getComponent()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testGetComponent() throws Exception {
-        Assert.assertTrue(new BodyTubeHandler(new Stage(), new WarningSet()).getComponent() instanceof BodyTube);
-    }
-
-    /**
-     * Method: getMaterialType()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testGetMaterialType() throws Exception {
-        Assert.assertEquals(Material.Type.BULK, new BodyTubeHandler(new Stage(), new WarningSet()).getMaterialType());
-    }
-
-}
diff --git a/test/net/sf/openrocket/file/rocksim/FinSetHandlerTest.java b/test/net/sf/openrocket/file/rocksim/FinSetHandlerTest.java
deleted file mode 100644 (file)
index 4ee683e..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * FinSetHandlerTest.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import junit.framework.TestCase;
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.EllipticalFinSet;
-import net.sf.openrocket.rocketcomponent.FinSet;
-import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
-import net.sf.openrocket.util.Coordinate;
-
-import java.lang.reflect.Method;
-import java.util.HashMap;
-
-/**
- * FinSetHandler Tester.
- *
- */
-public class FinSetHandlerTest extends TestCase {
-
-    /**
-     * Method: asOpenRocket(WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testAsOpenRocket() throws Exception {
-
-        FinSetHandler dto = new FinSetHandler(new BodyTube());
-
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        dto.closeElement("Name", attributes, "The name", warnings);
-        dto.closeElement("ShapeCode", attributes, "0", warnings);
-        dto.closeElement("Xb", attributes, "2", warnings);
-        dto.closeElement("FinCount", attributes, "4", warnings);
-        dto.closeElement("RootChord", attributes, "10", warnings);
-        dto.closeElement("TipChord", attributes, "11", warnings);
-        dto.closeElement("SemiSpan", attributes, "12", warnings);
-        dto.closeElement("MidChordLen", attributes, "13", warnings);
-        dto.closeElement("SweepDistance", attributes, "14", warnings);
-        dto.closeElement("Thickness", attributes, "200", warnings);
-        dto.closeElement("TipShapeCode", attributes, "1", warnings);
-        dto.closeElement("TabLength", attributes, "400", warnings);
-        dto.closeElement("TabDepth", attributes, "500", warnings);
-        dto.closeElement("TabOffset", attributes, "30", warnings);
-        dto.closeElement("RadialAngle", attributes, ".123", warnings);
-        dto.closeElement("PointList", attributes, "20,0|2,2|0,0", warnings);
-        dto.closeElement("LocationMode", attributes, "0", warnings);
-
-        WarningSet set = new WarningSet();
-        FinSet fins = dto.asOpenRocket(set);
-        assertNotNull(fins);
-        assertEquals(0, set.size());
-
-        assertEquals("The name", fins.getName());
-        assertTrue(fins instanceof TrapezoidFinSet);
-        assertEquals(4, fins.getFinCount());
-
-        assertEquals(0.012d, ((TrapezoidFinSet) fins).getHeight());
-        assertEquals(0.012d, fins.getSpan());
-        
-        assertEquals(0.2d, fins.getThickness());
-        assertEquals(0.4d, fins.getTabLength());
-        assertEquals(0.5d, fins.getTabHeight());
-        assertEquals(0.03d, fins.getTabShift());
-        assertEquals(.123d, fins.getBaseRotation());
-
-        dto.closeElement("ShapeCode", attributes, "1", warnings);
-        fins = dto.asOpenRocket(set);
-        assertNotNull(fins);
-        assertEquals(0, set.size());
-
-        assertEquals("The name", fins.getName());
-        assertTrue(fins instanceof EllipticalFinSet);
-        assertEquals(4, fins.getFinCount());
-
-        assertEquals(0.2d, fins.getThickness());
-        assertEquals(0.4d, fins.getTabLength());
-        assertEquals(0.5d, fins.getTabHeight());
-        assertEquals(0.03d, fins.getTabShift());
-        assertEquals(.123d, fins.getBaseRotation());
-    }
-
-
-    /**
-     * Method: toCoordinates(String pointList)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testToCoordinates() throws Exception {
-        FinSetHandler holder = new FinSetHandler(new BodyTube());
-        Method method = FinSetHandler.class.getDeclaredMethod("toCoordinates", String.class, WarningSet.class);
-        method.setAccessible(true);
-
-        WarningSet warnings = new WarningSet();
-        //Null finlist
-        String finlist = null;
-        Coordinate[] result = (Coordinate[])method.invoke(holder, finlist, warnings);
-        assertNotNull(result);
-        assertTrue(0 == result.length);
-
-        //Empty string finlist
-        finlist = "";
-        result = (Coordinate[])method.invoke(holder, finlist, warnings);
-        assertNotNull(result);
-        assertTrue(0 == result.length);
-        
-        //Invalid finlist (only x coordinate)
-        finlist = "10.0";
-        result = (Coordinate[])method.invoke(holder, finlist, warnings);
-        assertNotNull(result);
-        assertTrue(0 == result.length);
-        assertEquals(1, warnings.size());
-        warnings.clear();
-
-        //Invalid finlist (non-numeric character)
-        finlist = "10.0,asdf";
-        result = (Coordinate[])method.invoke(holder, finlist, warnings);
-        assertNotNull(result);
-        assertTrue(0 == result.length);
-        assertEquals(1, warnings.size());
-        warnings.clear();
-
-        //Invalid finlist (all delimiters)
-        finlist = "||||||";
-        result = (Coordinate[])method.invoke(holder, finlist, warnings);
-        assertNotNull(result);
-        assertTrue(0 == result.length);
-        assertEquals(0, warnings.size());
-        warnings.clear();
-
-        //One point finlist - from a parsing view it's valid; from a practical view it may not be, but that's outside
-        //the scope of this test case
-        finlist = "10.0,5.0";
-        result = (Coordinate[])method.invoke(holder, finlist, warnings);
-        assertNotNull(result);
-        assertTrue(1 == result.length);
-        assertEquals(0, warnings.size());
-        warnings.clear();
-        
-        //Two point finlist - from a parsing view it's valid; from a practical view it may not be, but that's outside
-        //the scope of this test case
-        finlist = "10.0,5.0|3.3,4.4";
-        result = (Coordinate[])method.invoke(holder, finlist, warnings);
-        assertNotNull(result);
-        assertTrue(2 == result.length);
-        assertEquals(0, warnings.size());
-        warnings.clear();
-        
-        //Normal four point finlist.
-        finlist = "518.16,0|517.494,37.2145|1.31261,6.77283|0,0|";
-        result = (Coordinate[])method.invoke(holder, finlist, warnings);
-        assertNotNull(result);
-        assertTrue(4 == result.length);
-        assertEquals(new Coordinate(0,0), result[0]);
-        assertEquals(0, warnings.size());
-        warnings.clear();
-        
-        //Normal four point finlist with spaces.
-        finlist = "518.16 , 0 | 517.494 , 37.2145 | 1.31261,6.77283|0,0|";
-        result = (Coordinate[])method.invoke(holder, finlist, warnings);
-        assertNotNull(result);
-        assertTrue(4 == result.length);
-        assertEquals(new Coordinate(0,0), result[0]);
-        assertEquals(new Coordinate(.51816,0), result[3]);
-        assertEquals(0, warnings.size());
-        warnings.clear();
-        
-        //Reversed Normal four point finlist.
-        finlist = "0,0|1.31261,6.77283|517.494,37.2145|518.16,0|";
-        result = (Coordinate[])method.invoke(holder, finlist, warnings);
-        assertNotNull(result);
-        assertTrue(4 == result.length);
-        assertEquals(new Coordinate(0,0), result[0]);
-        assertEquals(new Coordinate(.51816,0), result[3]);
-        assertEquals(0, warnings.size());
-        warnings.clear();
-        
-    }
-}
diff --git a/test/net/sf/openrocket/file/rocksim/InnerBodyTubeHandlerTest.java b/test/net/sf/openrocket/file/rocksim/InnerBodyTubeHandlerTest.java
deleted file mode 100644 (file)
index d1950bc..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * InnerBodyTubeHandlerTest.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.file.simplesax.PlainTextHandler;
-import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.InnerTube;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.junit.Assert;
-
-import java.util.HashMap;
-
-/**
- * InnerBodyTubeHandler Tester.
- *
- */
-public class InnerBodyTubeHandlerTest extends RocksimTestBase {
-
-    /**
-     * Method: constructor
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testConstructor() throws Exception {
-
-        try {
-            new InnerBodyTubeHandler(null, new WarningSet());
-            Assert.fail("Should have thrown IllegalArgumentException");
-        }
-        catch (IllegalArgumentException iae) {
-            //success
-        }
-
-        BodyTube tube = new BodyTube();
-        InnerBodyTubeHandler handler = new InnerBodyTubeHandler(tube, new WarningSet());
-        InnerTube component = (InnerTube) getField(handler, "bodyTube");
-        assertContains(component, tube.getChildren());
-    }
-
-    /**
-     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testOpenElement() throws Exception {
-        Assert.assertEquals(PlainTextHandler.INSTANCE, new InnerBodyTubeHandler(new BodyTube(), new WarningSet()).openElement(null, null, null));
-        Assert.assertNotNull(new InnerBodyTubeHandler(new BodyTube(), new WarningSet()).openElement("AttachedParts", null, null));
-    }
-
-    /**
-     *
-     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-     *
-     * @throws Exception  thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testCloseElement() throws Exception {
-        BodyTube tube = new BodyTube();
-        InnerBodyTubeHandler handler = new InnerBodyTubeHandler(tube, new WarningSet());
-        InnerTube component = (InnerTube) getField(handler, "bodyTube");
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        handler.closeElement("OD", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
-        handler.closeElement("OD", attributes, "0", warnings);
-        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
-        handler.closeElement("OD", attributes, "75", warnings);
-        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius(), 0.001);
-        handler.closeElement("OD", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("ID", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
-        handler.closeElement("ID", attributes, "0", warnings);
-        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
-        handler.closeElement("ID", attributes, "75", warnings);
-        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius(), 0.001);
-        handler.closeElement("ID", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Len", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("IsMotorMount", attributes, "1", warnings);
-        Assert.assertTrue(component.isMotorMount());
-        handler.closeElement("IsMotorMount", attributes, "0", warnings);
-        Assert.assertFalse(component.isMotorMount());
-        handler.closeElement("IsMotorMount", attributes, "foo", warnings);
-        Assert.assertFalse(component.isMotorMount());
-
-        handler.closeElement("EngineOverhang", attributes, "-1", warnings);
-        Assert.assertEquals(-1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang(), 0.001);
-        handler.closeElement("EngineOverhang", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang(), 0.001);
-        handler.closeElement("EngineOverhang", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang(), 0.001);
-        handler.closeElement("EngineOverhang", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Name", attributes, "Test Name", warnings);
-        Assert.assertEquals("Test Name", component.getName());
-    }
-    
-    /**
-     * Method: setRelativePosition(RocketComponent.Position position)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testSetRelativePosition() throws Exception {
-        BodyTube tube = new BodyTube();
-        InnerBodyTubeHandler handler = new InnerBodyTubeHandler(tube, new WarningSet());
-        InnerTube component = (InnerTube) getField(handler, "bodyTube");
-        handler.setRelativePosition(RocketComponent.Position.ABSOLUTE);
-        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
-    }
-
-    /**
-     * Method: getComponent()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetComponent() throws Exception {
-        Assert.assertTrue(new InnerBodyTubeHandler(new BodyTube(), new WarningSet()).getComponent() instanceof InnerTube);
-    }
-
-    /**
-     * Method: getMaterialType()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetMaterialType() throws Exception {
-        Assert.assertEquals(Material.Type.BULK, new InnerBodyTubeHandler(new BodyTube(), new WarningSet()).getMaterialType());
-    }
-
-}
diff --git a/test/net/sf/openrocket/file/rocksim/LaunchLugHandlerTest.java b/test/net/sf/openrocket/file/rocksim/LaunchLugHandlerTest.java
deleted file mode 100644 (file)
index 0effbea..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * LaunchLugHandlerTest.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.file.simplesax.PlainTextHandler;
-import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.ExternalComponent;
-import net.sf.openrocket.rocketcomponent.LaunchLug;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.junit.Assert;
-
-import java.util.HashMap;
-
-/**
- * LaunchLugHandler Tester.
- *
- */
-public class LaunchLugHandlerTest extends RocksimTestBase {
-
-    /**
-     * Method: constructor
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testConstructor() throws Exception {
-
-        try {
-            new LaunchLugHandler(null, new WarningSet());
-            Assert.fail("Should have thrown IllegalArgumentException");
-        }
-        catch (IllegalArgumentException iae) {
-            //success
-        }
-
-        BodyTube tube = new BodyTube();
-        LaunchLugHandler handler = new LaunchLugHandler(tube, new WarningSet());
-        LaunchLug component = (LaunchLug) getField(handler, "lug");
-        assertContains(component, tube.getChildren());
-    }
-
-    /**
-     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testOpenElement() throws Exception {
-        Assert.assertEquals(PlainTextHandler.INSTANCE, new LaunchLugHandler(new BodyTube(), new WarningSet()).openElement(null, null, null));
-    }
-
-    /**
-     *
-     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-     *
-     * @throws Exception  thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testCloseElement() throws Exception {
-        BodyTube tube = new BodyTube();
-        LaunchLugHandler handler = new LaunchLugHandler(tube, new WarningSet());
-        LaunchLug component = (LaunchLug) getField(handler, "lug");
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        handler.closeElement("OD", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getOuterRadius(), 0.001);
-        handler.closeElement("OD", attributes, "0", warnings);
-        Assert.assertEquals(0d, component.getOuterRadius(), 0.001);
-        handler.closeElement("OD", attributes, "75", warnings);
-        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getOuterRadius(), 0.001);
-        handler.closeElement("OD", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("ID", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
-        handler.closeElement("ID", attributes, "0", warnings);
-        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
-        handler.closeElement("ID", attributes, "75", warnings);
-        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius(), 0.001);
-        handler.closeElement("ID", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Len", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("FinishCode", attributes, "-1", warnings);
-        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
-        handler.closeElement("FinishCode", attributes, "100", warnings);
-        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
-        handler.closeElement("FinishCode", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Name", attributes, "Test Name", warnings);
-        Assert.assertEquals("Test Name", component.getName());
-    }
-    
-    /**
-     * Method: setRelativePosition(RocketComponent.Position position)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testSetRelativePosition() throws Exception {
-        BodyTube tube = new BodyTube();
-        LaunchLugHandler handler = new LaunchLugHandler(tube, new WarningSet());
-        LaunchLug component = (LaunchLug) getField(handler, "lug");
-        handler.setRelativePosition(RocketComponent.Position.ABSOLUTE);
-        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
-    }
-
-    /**
-     * Method: getComponent()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetComponent() throws Exception {
-        Assert.assertTrue(new LaunchLugHandler(new BodyTube(), new WarningSet()).getComponent() instanceof LaunchLug);
-    }
-
-    /**
-     * Method: getMaterialType()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetMaterialType() throws Exception {
-        Assert.assertEquals(Material.Type.BULK, new LaunchLugHandler(new BodyTube(), new WarningSet()).getMaterialType());
-    }
-
-
-}
diff --git a/test/net/sf/openrocket/file/rocksim/MassObjectHandlerTest.java b/test/net/sf/openrocket/file/rocksim/MassObjectHandlerTest.java
deleted file mode 100644 (file)
index fa72a43..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * MassObjectHandlerTest.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.file.simplesax.PlainTextHandler;
-import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.MassComponent;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.junit.Assert;
-
-import java.util.HashMap;
-
-/**
- * MassObjectHandler Tester.
- *
- */
-public class MassObjectHandlerTest extends RocksimTestBase {
-
-    /**
-     * Method: constructor
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testConstructor() throws Exception {
-
-        try {
-            new MassObjectHandler(null, new WarningSet());
-            Assert.fail("Should have thrown IllegalArgumentException");
-        }
-        catch (IllegalArgumentException iae) {
-            //success
-        }
-
-        BodyTube tube = new BodyTube();
-        MassObjectHandler handler = new MassObjectHandler(tube, new WarningSet());
-        MassComponent component = (MassComponent) getField(handler, "mass");
-        assertContains(component, tube.getChildren());
-    }
-
-    /**
-     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testOpenElement() throws Exception {
-        Assert.assertEquals(PlainTextHandler.INSTANCE, new MassObjectHandler(new BodyTube(), new WarningSet()).openElement(null, null, null));
-    }
-
-    /**
-     *
-     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-     *
-     * @throws Exception  thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testCloseElement() throws Exception {
-        BodyTube tube = new BodyTube();
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        MassObjectHandler handler = new MassObjectHandler(tube, new WarningSet());
-        MassComponent component = (MassComponent) getField(handler, "mass");
-
-        handler.closeElement("Len", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10", warnings);
-        Assert.assertEquals(10d / (MassObjectHandler.MASS_LEN_FUDGE_FACTOR * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)
-                , component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / (MassObjectHandler.MASS_LEN_FUDGE_FACTOR * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)
-                , component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("KnownMass", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getComponentMass(), 0.001);
-        handler.closeElement("KnownMass", attributes, "100", warnings);
-        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS, component.getComponentMass(), 0.001);
-        handler.closeElement("KnownMass", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-    }
-    
-    /**
-     * Method: setRelativePosition(RocketComponent.Position position)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testSetRelativePosition() throws Exception {
-        BodyTube tube = new BodyTube();
-        MassObjectHandler handler = new MassObjectHandler(tube, new WarningSet());
-        MassComponent component = (MassComponent) getField(handler, "mass");
-        handler.setRelativePosition(RocketComponent.Position.ABSOLUTE);
-        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
-    }
-
-    /**
-     * Method: getComponent()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetComponent() throws Exception {
-        Assert.assertTrue(new MassObjectHandler(new BodyTube(), new WarningSet()).getComponent() instanceof MassComponent);
-    }
-
-    /**
-     * Method: getMaterialType()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetMaterialType() throws Exception {
-        Assert.assertEquals(Material.Type.BULK, new MassObjectHandler(new BodyTube(), new WarningSet()).getMaterialType());
-    }
-}
diff --git a/test/net/sf/openrocket/file/rocksim/NoseConeHandlerTest.java b/test/net/sf/openrocket/file/rocksim/NoseConeHandlerTest.java
deleted file mode 100644 (file)
index 92dbb45..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * NoseConeHandlerTest.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.file.simplesax.PlainTextHandler;
-import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.ExternalComponent;
-import net.sf.openrocket.rocketcomponent.NoseCone;
-import net.sf.openrocket.rocketcomponent.Stage;
-import net.sf.openrocket.rocketcomponent.Transition;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.HashMap;
-
-/**
- * NoseConeHandler Tester.
- *
- */
-public class NoseConeHandlerTest extends RocksimTestBase {
-
-    /**
-     * Method: constructor
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testConstructor() throws Exception {
-
-        try {
-            new NoseConeHandler(null, new WarningSet());
-            Assert.fail("Should have thrown IllegalArgumentException");
-        }
-        catch (IllegalArgumentException iae) {
-            //success
-        }
-
-        Stage stage = new Stage();
-        NoseConeHandler handler = new NoseConeHandler(stage, new WarningSet());
-        NoseCone component = (NoseCone) getField(handler, "noseCone");
-        assertContains(component, stage.getChildren());
-    }
-
-    /**
-     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testOpenElement() throws Exception {
-        Assert.assertEquals(PlainTextHandler.INSTANCE, new NoseConeHandler(new Stage(), new WarningSet()).openElement(null, null, null));
-        Assert.assertNotNull(new NoseConeHandler(new Stage(), new WarningSet()).openElement("AttachedParts", null, null));
-    }
-
-    /**
-     *
-     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-     *
-     * @throws Exception  thrown if something goes awry
-     */
-    @Test
-    public void testCloseElement() throws Exception {
-
-        Stage stage = new Stage();
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        NoseConeHandler handler = new NoseConeHandler(stage, warnings);
-        NoseCone component = (NoseCone) getField(handler, "noseCone");
-
-        handler.closeElement("ShapeCode", attributes, "0", warnings);
-        Assert.assertEquals(Transition.Shape.CONICAL, component.getType());
-        handler.closeElement("ShapeCode", attributes, "1", warnings);
-        Assert.assertEquals(Transition.Shape.OGIVE, component.getType());
-        handler.closeElement("ShapeCode", attributes, "17", warnings);
-        Assert.assertEquals(RocksimNoseConeCode.PARABOLIC.asOpenRocket(), component.getType());  //test of default
-        handler.closeElement("ShapeCode", attributes, "foo", warnings);
-        Assert.assertNotNull(component.getType());
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Len", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("BaseDia", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getAftRadius(), 0.001);
-        handler.closeElement("BaseDia", attributes, "100", warnings);
-        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getAftRadius(), 0.001);
-        handler.closeElement("BaseDia", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        
-        final double aft = 100d;
-        component.setAftRadius(aft);
-        
-        handler.closeElement("ConstructionType", attributes, "0", warnings);
-        component.setAftShoulderRadius(1.1d);
-        handler.closeElement("WallThickness", attributes, "-1", warnings);
-        handler.endHandler("Transition", attributes, null, warnings);
-        Assert.assertEquals(component.getAftRadius(), component.getThickness(), 0.001);
-        Assert.assertEquals(component.getAftShoulderThickness(), component.getAftShoulderThickness(), 0.001);
-        handler.closeElement("WallThickness", attributes, "100", warnings);
-        handler.endHandler("Transition", attributes, null, warnings);
-        Assert.assertEquals(aft, component.getThickness(), 0.001);
-        handler.closeElement("WallThickness", attributes, "foo", warnings);
-        handler.endHandler("Transition", attributes, null, warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-        
-        handler.closeElement("ConstructionType", attributes, "1", warnings);
-        component.setAftShoulderRadius(1.1d);
-        handler.closeElement("WallThickness", attributes, "-1", warnings);
-        handler.endHandler("Transition", attributes, null, warnings);
-        Assert.assertEquals(0d, component.getThickness(), 0.001);
-        Assert.assertEquals(0d, component.getAftShoulderThickness(), 0.001);
-        handler.closeElement("WallThickness", attributes, "1.1", warnings);
-        handler.endHandler("Transition", attributes, null, warnings);
-        Assert.assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getThickness(), 0.001);
-        Assert.assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderThickness(), 0.001);
-        
-        handler.closeElement("ShoulderLen", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getAftShoulderLength(), 0.001);
-        handler.closeElement("ShoulderLen", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderLength(), 0.001);
-        handler.closeElement("ShoulderLen", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderLength(), 0.001);
-        handler.closeElement("ShoulderLen", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("ShoulderOD", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getAftShoulderRadius(), 0.001);
-        handler.closeElement("ShoulderOD", attributes, "100", warnings);
-        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getAftShoulderRadius(), 0.001);
-        handler.closeElement("ShoulderOD", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        component.setType(Transition.Shape.HAACK);
-        handler.closeElement("ShapeParameter", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getShapeParameter(), 0.001);
-        handler.closeElement("ShapeParameter", attributes, "100", warnings);
-        Assert.assertEquals(Transition.Shape.HAACK.maxParameter(), component.getShapeParameter(), 0.001);
-        handler.closeElement("ShapeParameter", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        Assert.assertEquals("Could not convert ShapeParameter value of foo.  It is expected to be a number.", 
-                     warnings.iterator().next().toString());
-
-        warnings.clear();
-
-        component.setType(Transition.Shape.CONICAL);
-        component.setShapeParameter(0d);
-        handler.closeElement("ShapeParameter", attributes, "100", warnings);
-        Assert.assertEquals(0d, component.getShapeParameter(), 0.001);
-
-        handler.closeElement("FinishCode", attributes, "-1", warnings);
-        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
-        handler.closeElement("FinishCode", attributes, "100", warnings);
-        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
-        handler.closeElement("FinishCode", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Name", attributes, "Test Name", warnings);
-        Assert.assertEquals("Test Name", component.getName());
-        
-        handler.closeElement("Material", attributes, "Some Material", warnings);
-        handler.endHandler("NoseCone", attributes, null, warnings);
-        Assert.assertTrue(component.getMaterial().getName().contains("Some Material"));
-     }
-
-    /**
-     * Method: getComponent()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testGetComponent() throws Exception {
-        Assert.assertTrue(new NoseConeHandler(new Stage(), new WarningSet()).getComponent() instanceof NoseCone);
-    }
-
-    /**
-     * Method: getMaterialType()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testGetMaterialType() throws Exception {
-        Assert.assertEquals(Material.Type.BULK, new NoseConeHandler(new Stage(), new WarningSet()).getMaterialType());
-    }
-}
diff --git a/test/net/sf/openrocket/file/rocksim/ParachuteHandlerTest.java b/test/net/sf/openrocket/file/rocksim/ParachuteHandlerTest.java
deleted file mode 100644 (file)
index f1037d2..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * ParachuteHandlerTest.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.file.simplesax.PlainTextHandler;
-import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.Parachute;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.junit.Assert;
-
-import java.util.HashMap;
-
-/**
- * ParachuteHandler Tester.
- */
-public class ParachuteHandlerTest extends RocksimTestBase {
-
-    /**
-     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testOpenElement() throws Exception {
-        Assert.assertEquals(PlainTextHandler.INSTANCE, new ParachuteHandler(new BodyTube(), new WarningSet()).openElement(null, null, null));
-    }
-
-    /**
-     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testCloseElement() throws Exception {
-
-        BodyTube tube = new BodyTube();
-        ParachuteHandler handler = new ParachuteHandler(tube, new WarningSet());
-        Parachute component = (Parachute) getField(handler, "chute");
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        handler.closeElement("Name", attributes, "Test Name", warnings);
-        Assert.assertEquals("Test Name", component.getName());
-
-        handler.closeElement("DragCoefficient", attributes, "0.94", warnings);
-        Assert.assertEquals(0.94d, component.getCD(), 0.001);
-        handler.closeElement("DragCoefficient", attributes, "-0.94", warnings);
-        Assert.assertEquals(-0.94d, component.getCD(), 0.001);
-        handler.closeElement("DragCoefficient", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Dia", attributes, "-1", warnings);
-        Assert.assertEquals(-1d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getDiameter(), 0.001);
-        handler.closeElement("Dia", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getDiameter(), 0.001);
-        handler.closeElement("Dia", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("ShroudLineCount", attributes, "-1", warnings);
-        Assert.assertEquals(0, component.getLineCount());
-        handler.closeElement("ShroudLineCount", attributes, "10", warnings);
-        Assert.assertEquals(10, component.getLineCount());
-        handler.closeElement("ShroudLineCount", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("ShroudLineLen", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getLineLength(), 0.001);
-        handler.closeElement("ShroudLineLen", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLineLength(), 0.001);
-        handler.closeElement("ShroudLineLen", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-    }
-
-    /**
-     * Method: constructor
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testConstructor() throws Exception {
-
-        try {
-            new ParachuteHandler(null, new WarningSet());
-            Assert.fail("Should have thrown IllegalArgumentException");
-        }
-        catch (IllegalArgumentException iae) {
-            //success
-        }
-
-        BodyTube tube = new BodyTube();
-        ParachuteHandler handler = new ParachuteHandler(tube, new WarningSet());
-        Parachute component = (Parachute) getField(handler, "chute");
-        assertContains(component, tube.getChildren());
-    }
-
-    /**
-     * Method: setRelativePosition(RocketComponent.Position position)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testSetRelativePosition() throws Exception {
-        BodyTube tube = new BodyTube();
-        ParachuteHandler handler = new ParachuteHandler(tube, new WarningSet());
-        Parachute component = (Parachute) getField(handler, "chute");
-        handler.setRelativePosition(RocketComponent.Position.ABSOLUTE);
-        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
-    }
-
-    /**
-     * Method: getComponent()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetComponent() throws Exception {
-        Assert.assertTrue(new ParachuteHandler(new BodyTube(), new WarningSet()).getComponent() instanceof Parachute);
-    }
-
-    /**
-     * Method: getMaterialType()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetMaterialType() throws Exception {
-        Assert.assertEquals(Material.Type.SURFACE, new ParachuteHandler(new BodyTube(), new WarningSet()).getMaterialType());
-    }
-
-    /**
-     * Method: endHandler()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testEndHandler() throws Exception {
-        BodyTube tube = new BodyTube();
-        ParachuteHandler handler = new ParachuteHandler(tube, new WarningSet());
-        Parachute component = (Parachute) getField(handler, "chute");
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        handler.closeElement("Xb", attributes, "-10", warnings);
-        handler.closeElement("LocationMode", attributes, "1", warnings);
-        handler.endHandler("Parachute", attributes, null, warnings);
-        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
-        Assert.assertEquals(component.getPositionValue(), -10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, 0.001);
-
-        handler.closeElement("Xb", attributes, "-10", warnings);
-        handler.closeElement("LocationMode", attributes, "2", warnings);
-        handler.endHandler("Parachute", attributes, null, warnings);
-        Assert.assertEquals(RocketComponent.Position.BOTTOM, component.getRelativePosition());
-        Assert.assertEquals(component.getPositionValue(), 10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, 0.001);
-    }
-}
diff --git a/test/net/sf/openrocket/file/rocksim/PodFins.rkt b/test/net/sf/openrocket/file/rocksim/PodFins.rkt
deleted file mode 100644 (file)
index a137008..0000000
+++ /dev/null
@@ -1,605 +0,0 @@
-<RockSimDocument>
-  <FileVersion>4</FileVersion>
-  <DesignInformation>
-    <RocketDesign>
-      <CalculateCD>1</CalculateCD>
-      <ProCalculateCD>1</ProCalculateCD>
-      <ProCalculateCN>1</ProCalculateCN>
-      <FixedCd>0.75</FixedCd>
-      <FixedCd2>0.8</FixedCd2>
-      <FixedCd3>0.81</FixedCd3>
-      <FixedCd2Alone>0.95</FixedCd2Alone>
-      <FixedCd3Alone>0.95</FixedCd3Alone>
-      <StageCount>1</StageCount>
-      <Stage3Mass>0.</Stage3Mass>
-      <Stage2Mass>0.</Stage2Mass>
-      <Stage1Mass>0.</Stage1Mass>
-      <Stage321CG>0.</Stage321CG>
-      <Stage32CG>0.</Stage32CG>
-      <Stage3CG>0.</Stage3CG>
-      <Stage2CGAlone>0.</Stage2CGAlone>
-      <Stage1CGAlone>0.</Stage1CGAlone>
-      <CPCalcFlags>1</CPCalcFlags>
-      <LaunchGuideLength>914.4</LaunchGuideLength>
-      <UseKnownMass>0</UseKnownMass>
-      <DefaultFinish>0</DefaultFinish>
-      <FinishMedium>0</FinishMedium>
-      <FinishCoatCount>1</FinishCoatCount>
-      <GlueType>0</GlueType>
-      <CPSimFlags>1</CPSimFlags>
-      <LastSerialNumber>7</LastSerialNumber>
-      <DisplayFlags>1</DisplayFlags>
-      <MetricsFlags>0</MetricsFlags>
-      <BarromanXN>0,567.719,0,0</BarromanXN>
-      <BarrowmanCNa>0,19.2193,0,0</BarrowmanCNa>
-      <RockSimXN>0,571.25,0,0</RockSimXN>
-      <RockSimCNa>0,28.2677,0,0</RockSimCNa>
-      <RockSimCNa90>0,0,0,0</RockSimCNa90>
-      <RockSimXN90>0,0,0,0</RockSimXN90>
-      <ViewType>0</ViewType>
-      <ViewStageCount>1</ViewStageCount>
-      <ViewTypeEdit>0</ViewTypeEdit>
-      <ViewStageCountEdit>1</ViewStageCountEdit>
-      <ZoomFactor>0.</ZoomFactor>
-      <ZoomFactorEdit>0.</ZoomFactorEdit>
-      <ScrollPosX>0</ScrollPosX>
-      <ScrollPosY>0</ScrollPosY>
-      <ScrollPosXEdit>0</ScrollPosXEdit>
-      <ScrollPosYEdit>0</ScrollPosYEdit>
-      <ThreeDFlags>0</ThreeDFlags>
-      <ThreeDFlagsEdit>0</ThreeDFlagsEdit>
-      <UseModelSprite>0</UseModelSprite>
-      <StaticMarginRef>0</StaticMarginRef>
-      <UserRefDiameter>0.</UserRefDiameter>
-      <SideMarkerHeight>10.</SideMarkerHeight>
-      <SideDimensionHeight>10.</SideDimensionHeight>
-      <BaseMarkerHeight>10.</BaseMarkerHeight>
-      <BaseDimensionHeight>10.</BaseDimensionHeight>
-      <ShowGlideCP>0</ShowGlideCP>
-      <ShowGridTypeSide>0</ShowGridTypeSide>
-      <ShowGridTypeBase>0</ShowGridTypeBase>
-      <GridSpacing>10.</GridSpacing>
-      <GridOpacity>0.15</GridOpacity>
-      <GridColor>black</GridColor>
-      <MaxDiaWithFins>259.588</MaxDiaWithFins>
-      <MaxDiaWithoutFins>56.388</MaxDiaWithoutFins>
-      <MaxLenWithFins>717.499</MaxLenWithFins>
-      <MaxLenWithoutFins>717.499</MaxLenWithoutFins>
-      <MinXExtent>0.</MinXExtent>
-      <MaxXExtent>717.499</MaxXExtent>
-      <CalculatedMaxStageDia>0,56.388,0,0</CalculatedMaxStageDia>
-      <CalculatedStageLen>0,717.499,0,0</CalculatedStageLen>
-      <Cd3>
-        <PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-        <X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-        <A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-        <B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-        <C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-      </PolyData>
-    </Cd3>
-    <Cd32>
-      <PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-      <X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-      <A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-      <B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-      <C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-    </PolyData>
-  </Cd32>
-  <Cd321>
-    <PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-    <X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-    <A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-    <B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-    <C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-  </PolyData>
-</Cd321>
-<Cb3>
-  <PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-  <X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-  <A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-  <B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-  <C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cb3>
-<Cb32>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cb32>
-<Cb321>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cb321>
-<CNa3>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CNa3>
-<CNa32>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CNa32>
-<CNa321>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CNa321>
-<CP3>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CP3>
-<CP32>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CP32>
-<CP321>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CP321>
-<SimulationEventList>
-</SimulationEventList>
-<Stage3Parts>
-<NoseCone>
-<PartMfg>Apogee</PartMfg>
-<KnownMass>24.0999</KnownMass>
-<Density>1049.21</Density>
-<Material>Polystyrene PS</Material>
-<Name>Nose cone</Name>
-<KnownCG>65.3999</KnownCG>
-<UseKnownCG>1</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>94.7384</CalcMass>
-<CalcCG>208.434</CalcCG>
-<WettedSurface>0.0323955</WettedSurface>
-<PaintedSurface>0.0323955</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>19470</PartNo>
-<PartDesc>PNC-70A</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>1</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>2.</BarrowmanCNa>
-<BarrowmanXN>0.126958</BarrowmanXN>
-<RockSimCNa>2.</RockSimCNa>
-<RockSimXN>0.126958</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>0.</Station>
-<Len>272.999</Len>
-<BaseDia>56.2991</BaseDia>
-<FinishCode>0</FinishCode>
-<ShapeCode>1</ShapeCode>
-<ConstructionType>1</ConstructionType>
-<ShoulderLen>58.3997</ShoulderLen>
-<WallThickness>2.159</WallThickness>
-<ShapeParameter>0.</ShapeParameter>
-<ShoulderOD>53.1012</ShoulderOD>
-<BaseExtensionLen>0.</BaseExtensionLen>
-<CoreDia>0.</CoreDia>
-<CoreLen>0.</CoreLen>
-<AttachedParts>
-</AttachedParts>
-</NoseCone>
-<BodyTube>
-<PartMfg>Estes</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>44.4492</CalcMass>
-<CalcCG>222.25</CalcCG>
-<WettedSurface>0.0787423</WettedSurface>
-<PaintedSurface>0.0787423</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>Estes</PartNo>
-<PartDesc>BT-70</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>2</SerialNo>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>272.999</Station>
-<OD>56.388</OD>
-<ID>55.372</ID>
-<Len>444.5</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>0.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>0</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<FinSet>
-<PartMfg>Public Missiles</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1905.24</Density>
-<Material>G10 fiberglass</Material>
-<Name>Fin set</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>273.05</Xb>
-<CalcMass>75.5033</CalcMass>
-<CalcCG>110.067</CalcCG>
-<WettedSurface>0.0167742</WettedSurface>
-<PaintedSurface>0.0503225</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>FIN-A-04</PartNo>
-<PartDesc>Fins</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>4</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>16.5474</BarrowmanCNa>
-<BarrowmanXN>0.628599</BarrowmanXN>
-<RockSimCNa>23.7789</RockSimCNa>
-<RockSimXN>0.628599</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>546.049</Station>
-<FinCount>3</FinCount>
-<RootChord>165.1</RootChord>
-<TipChord>0.</TipChord>
-<SemiSpan>101.6</SemiSpan>
-<MidChordLen>130.909</MidChordLen>
-<SweepDistance>165.1</SweepDistance>
-<Thickness>1.5748</Thickness>
-<ShapeCode>0</ShapeCode>
-<FinishCode>0</FinishCode>
-<TipShapeCode>1</TipShapeCode>
-<TabLength>0.</TabLength>
-<TabDepth>0.</TabDepth>
-<TabOffset>0.</TabOffset>
-<SweepMode>1</SweepMode>
-<SweepAngle>1.02001</SweepAngle>
-<RockSimXNPerFin>0.</RockSimXNPerFin>
-<RockSimRadialXNPerFin>62.0607</RockSimRadialXNPerFin>
-<RockSimCNaPerFin>13.7288</RockSimCNaPerFin>
-<TaperRatio>0.</TaperRatio>
-<CantAngle>0.</CantAngle>
-<CantPivotPoint>0.</CantPivotPoint>
-<AttachedParts>
-</AttachedParts>
-</FinSet>
-<BodyTube>
-<PartMfg>Apogee</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>107.95</Xb>
-<CalcMass>1.7435</CalcMass>
-<CalcCG>55.5625</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>10062</PartNo>
-<PartDesc>13 mm</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>5</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>380.949</Station>
-<OD>13.8176</OD>
-<ID>13.1572</ID>
-<Len>111.125</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>13.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>1</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<FinSet>
-<PartMfg>Public Missiles</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1905.24</Density>
-<Material>G10 fiberglass</Material>
-<Name>Fin set</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>5.53666</CalcMass>
-<CalcCG>44.5707</CalcCG>
-<WettedSurface>0.00365927</WettedSurface>
-<PaintedSurface>0.00365927</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>FIN-A-06</PartNo>
-<PartDesc>Fins</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>7</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.671866</BarrowmanCNa>
-<BarrowmanXN>0.380349</BarrowmanXN>
-<RockSimCNa>2.4888</RockSimCNa>
-<RockSimXN>0.380349</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>349.199</Station>
-<FinCount>1</FinCount>
-<RootChord>66.675</RootChord>
-<TipChord>38.1</TipChord>
-<SemiSpan>34.925</SemiSpan>
-<MidChordLen>42.7843</MidChordLen>
-<SweepDistance>39.0017</SweepDistance>
-<Thickness>1.5875</Thickness>
-<ShapeCode>0</ShapeCode>
-<FinishCode>0</FinishCode>
-<TipShapeCode>0</TipShapeCode>
-<TabLength>0.</TabLength>
-<TabDepth>0.</TabDepth>
-<TabOffset>0.</TabOffset>
-<SweepMode>1</SweepMode>
-<SweepAngle>0.366519</SweepAngle>
-<RockSimXNPerFin>0.</RockSimXNPerFin>
-<RockSimRadialXNPerFin>44.069</RockSimRadialXNPerFin>
-<RockSimCNaPerFin>2.87382</RockSimCNaPerFin>
-<TaperRatio>0.571429</TaperRatio>
-<CantAngle>0.</CantAngle>
-<CantPivotPoint>0.</CantPivotPoint>
-<AttachedParts>
-</AttachedParts>
-</FinSet>
-</AttachedParts>
-</BodyTube>
-<ExternalPod>
-<PartMfg>Custom</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>0.</Density>
-<Name>Pod</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>76.2</Xb>
-<CalcMass>0.</CalcMass>
-<CalcCG>0.</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<RadialLoc>28.194</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>6</SerialNo>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>349.199</Station>
-<Detachable>1</Detachable>
-<AutoCalcRadialDistance>1</AutoCalcRadialDistance>
-<AutoCalcRadialAngle>1</AutoCalcRadialAngle>
-<AttachedParts>
-<FinSet>
-<PartMfg>Public Missiles</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1905.24</Density>
-<Material>G10 fiberglass</Material>
-<Name>Fin set</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>5.53666</CalcMass>
-<CalcCG>44.5707</CalcCG>
-<WettedSurface>0.00365927</WettedSurface>
-<PaintedSurface>0.00365927</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>FIN-A-06</PartNo>
-<PartDesc>Fins</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>7</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.671866</BarrowmanCNa>
-<BarrowmanXN>0.380349</BarrowmanXN>
-<RockSimCNa>2.4888</RockSimCNa>
-<RockSimXN>0.380349</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>349.199</Station>
-<FinCount>1</FinCount>
-<RootChord>66.675</RootChord>
-<TipChord>38.1</TipChord>
-<SemiSpan>34.925</SemiSpan>
-<MidChordLen>42.7843</MidChordLen>
-<SweepDistance>39.0017</SweepDistance>
-<Thickness>1.5875</Thickness>
-<ShapeCode>0</ShapeCode>
-<FinishCode>0</FinishCode>
-<TipShapeCode>0</TipShapeCode>
-<TabLength>0.</TabLength>
-<TabDepth>0.</TabDepth>
-<TabOffset>0.</TabOffset>
-<SweepMode>1</SweepMode>
-<SweepAngle>0.366519</SweepAngle>
-<RockSimXNPerFin>0.</RockSimXNPerFin>
-<RockSimRadialXNPerFin>44.069</RockSimRadialXNPerFin>
-<RockSimCNaPerFin>2.87382</RockSimCNaPerFin>
-<TaperRatio>0.571429</TaperRatio>
-<CantAngle>0.</CantAngle>
-<CantPivotPoint>0.</CantPivotPoint>
-<AttachedParts>
-</AttachedParts>
-</FinSet>
-</AttachedParts>
-</ExternalPod>
-</AttachedParts>
-</BodyTube>
-</Stage3Parts>
-<Stage2Parts>
-</Stage2Parts>
-<Stage1Parts>
-</Stage1Parts>
-<SideViewDims>
-</SideViewDims>
-<BaseViewDims>
-</BaseViewDims>
-<VertViewDims>
-</VertViewDims>
-</RocketDesign>
-</DesignInformation>
-<SimulationResultsList>
-</SimulationResultsList>
-</RockSimDocument>
diff --git a/test/net/sf/openrocket/file/rocksim/RingHandlerTest.java b/test/net/sf/openrocket/file/rocksim/RingHandlerTest.java
deleted file mode 100644 (file)
index b238eb9..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * RingHandlerTest.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.file.simplesax.PlainTextHandler;
-import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.Bulkhead;
-import net.sf.openrocket.rocketcomponent.CenteringRing;
-import net.sf.openrocket.rocketcomponent.EngineBlock;
-import net.sf.openrocket.rocketcomponent.RingComponent;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.TubeCoupler;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.HashMap;
-
-/**
- * RingHandler Tester.
- */
-public class RingHandlerTest extends RocksimTestBase {
-
-    /**
-     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testOpenElement() throws Exception {
-        Assert.assertEquals(PlainTextHandler.INSTANCE, new RingHandler(new BodyTube(), new WarningSet()).openElement(null, null, null));
-    }
-
-    /**
-     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testCloseElement() throws Exception {
-
-        BodyTube tube = new BodyTube();
-        RingHandler handler = new RingHandler(tube, new WarningSet());
-        CenteringRing component = (CenteringRing) getField(handler, "ring");
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        handler.closeElement("OD", attributes, "0", warnings);
-        Assert.assertEquals(0d, component.getOuterRadius(), 0.001);
-        handler.closeElement("OD", attributes, "75", warnings);
-        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getOuterRadius(), 0.001);
-        handler.closeElement("OD", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("ID", attributes, "0", warnings);
-        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
-        handler.closeElement("ID", attributes, "75", warnings);
-        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius(), 0.001);
-        handler.closeElement("ID", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Len", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Name", attributes, "Test Name", warnings);
-        Assert.assertEquals("Test Name", component.getName());
-    }
-
-    /**
-     * Test a bulkhead.
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testBulkhead() throws Exception {
-        BodyTube tube = new BodyTube();
-        RingHandler handler = new RingHandler(tube, new WarningSet());
-        CenteringRing component = (CenteringRing) getField(handler, "ring");
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        handler.closeElement("OD", attributes, "75", warnings);
-        handler.closeElement("ID", attributes, "0", warnings);
-        handler.closeElement("Len", attributes, "10", warnings);
-        handler.closeElement("Name", attributes, "Test Name", warnings);
-        handler.closeElement("KnownMass", attributes, "109.9", warnings);
-        handler.closeElement("UsageCode", attributes, "1", warnings);
-        handler.closeElement("UseKnownCG", attributes, "1", warnings);
-        handler.endHandler("", attributes, "", warnings);
-        
-        Assert.assertEquals(1, tube.getChildren().size());
-        RingComponent child = (RingComponent)tube.getChild(0);
-
-        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getOuterRadius(), 0.001);
-        Assert.assertEquals(0d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getInnerRadius(), 0.001);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, child.getLength(), 0.001);
-        Assert.assertEquals("Test Name", child.getName());
-        Assert.assertEquals(109.9/1000, child.getMass(), 0.001);
-        Assert.assertEquals(0, child.getPositionValue(), 0.0);
-        Assert.assertEquals(RocketComponent.Position.TOP, child.getRelativePosition());
-        Assert.assertTrue(child instanceof Bulkhead);
-
-    }
-    
-    /**
-     * Test a tube coupler.
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testTubeCoupler() throws Exception {
-        BodyTube tube = new BodyTube();
-        RingHandler handler = new RingHandler(tube, new WarningSet());
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        handler.closeElement("OD", attributes, "75", warnings);
-        handler.closeElement("ID", attributes, "70", warnings);
-        handler.closeElement("Len", attributes, "10", warnings);
-        handler.closeElement("Name", attributes, "Test Name", warnings);
-        handler.closeElement("KnownMass", attributes, "109.9", warnings);
-        handler.closeElement("UsageCode", attributes, "4", warnings);
-        handler.closeElement("UseKnownCG", attributes, "1", warnings);
-        handler.endHandler("", attributes, "", warnings);
-
-        Assert.assertEquals(1, tube.getChildren().size());
-        RingComponent child = (RingComponent)tube.getChild(0);
-        Assert.assertTrue(child instanceof TubeCoupler);
-
-        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getOuterRadius(), 0.001);
-        Assert.assertEquals(70d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getInnerRadius(), 0.001);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, child.getLength(), 0.001);
-        Assert.assertEquals("Test Name", child.getName());
-        Assert.assertEquals(109.9/1000, child.getMass(), 0.001);
-        Assert.assertEquals(0, child.getPositionValue(), 0.0);
-        Assert.assertEquals(RocketComponent.Position.TOP, child.getRelativePosition());
-    }
-
-    /**
-     * Test a engine block.
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testEngineBlock() throws Exception {
-        BodyTube tube = new BodyTube();
-        RingHandler handler = new RingHandler(tube, new WarningSet());
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        handler.closeElement("OD", attributes, "75", warnings);
-        handler.closeElement("ID", attributes, "70", warnings);
-        handler.closeElement("Len", attributes, "10", warnings);
-        handler.closeElement("Name", attributes, "Test Name", warnings);
-        handler.closeElement("KnownMass", attributes, "109.9", warnings);
-        handler.closeElement("UsageCode", attributes, "2", warnings);
-        handler.closeElement("KnownCG", attributes, "4", warnings);
-        handler.closeElement("UseKnownCG", attributes, "1", warnings);
-        handler.endHandler("", attributes, "", warnings);
-
-        Assert.assertEquals(1, tube.getChildren().size());
-        RingComponent child = (RingComponent)tube.getChild(0);
-        Assert.assertTrue(child instanceof EngineBlock);
-
-        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getOuterRadius(), 0.001);
-        Assert.assertEquals(70d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getInnerRadius(), 0.001);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, child.getLength(), 0.001);
-        Assert.assertEquals("Test Name", child.getName());
-        Assert.assertEquals(109.9/1000, child.getMass(), 0.001);
-        Assert.assertEquals(0, child.getPositionValue(), 0.0);
-        Assert.assertEquals(RocketComponent.Position.TOP, child.getRelativePosition());
-        Assert.assertEquals(4d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, child.getCG().x, 0.000001);
-        
-    }
-
-    /**
-     * Test a centering ring
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testRing() throws Exception {
-        BodyTube tube = new BodyTube();
-        RingHandler handler = new RingHandler(tube, new WarningSet());
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        handler.closeElement("OD", attributes, "75", warnings);
-        handler.closeElement("ID", attributes, "0", warnings);
-        handler.closeElement("Len", attributes, "10", warnings);
-        handler.closeElement("Name", attributes, "Test Name", warnings);
-        handler.closeElement("KnownMass", attributes, "109.9", warnings);
-        handler.closeElement("UsageCode", attributes, "0", warnings);
-        handler.closeElement("UseKnownCG", attributes, "1", warnings);
-        handler.endHandler("", attributes, "", warnings);
-
-        Assert.assertEquals(1, tube.getChildren().size());
-        RingComponent child = (RingComponent)tube.getChild(0);
-
-        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getOuterRadius(), 0.001);
-        Assert.assertEquals(0d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getInnerRadius(), 0.001);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, child.getLength(), 0.001);
-        Assert.assertEquals("Test Name", child.getName());
-        Assert.assertEquals(109.9/1000, child.getMass(), 0.001);
-        Assert.assertEquals(0, child.getPositionValue(), 0.0);
-        Assert.assertEquals(RocketComponent.Position.TOP, child.getRelativePosition());
-        Assert.assertTrue(child instanceof CenteringRing);
-    }
-
-    /**
-     * Method: constructor
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testConstructor() throws Exception {
-
-        try {
-            new RingHandler(null, new WarningSet());
-            Assert.fail("Should have thrown IllegalArgumentException");
-        }
-        catch (IllegalArgumentException iae) {
-            //success
-        }
-
-        BodyTube tube = new BodyTube();
-        RingHandler handler = new RingHandler(tube, new WarningSet());
-        CenteringRing component = (CenteringRing) getField(handler, "ring");
-    }
-
-    /**
-     * Method: setRelativePosition(RocketComponent.Position position)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testSetRelativePosition() throws Exception {
-        BodyTube tube = new BodyTube();
-        RingHandler handler = new RingHandler(tube, new WarningSet());
-        CenteringRing component = (CenteringRing) getField(handler, "ring");
-        handler.setRelativePosition(RocketComponent.Position.ABSOLUTE);
-        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
-    }
-
-    
-    /**
-     * Method: getComponent()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetComponent() throws Exception {
-        Assert.assertTrue(new RingHandler(new BodyTube(), new WarningSet()).getComponent() instanceof CenteringRing);
-    }
-
-    /**
-     * Method: getMaterialType()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetMaterialType() throws Exception {
-        Assert.assertEquals(Material.Type.BULK, new RingHandler(new BodyTube(), new WarningSet()).getMaterialType());
-    }
-
-
-}
diff --git a/test/net/sf/openrocket/file/rocksim/RocksimContentHandlerTest.java b/test/net/sf/openrocket/file/rocksim/RocksimContentHandlerTest.java
deleted file mode 100644 (file)
index b9edfb2..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * RocksimContentHandlerTest.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import org.junit.Assert;
-
-/**
- * RocksimContentHandler Tester.
- *
- */
-public class RocksimContentHandlerTest {
-
-    /**
-     *
-     * Method: getDocument()
-     *
-     * @throws Exception  thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetDocument() throws Exception {
-        RocksimContentHandler handler = new RocksimContentHandler();
-        Assert.assertNotNull(handler.getDocument());
-    }
-
-}
diff --git a/test/net/sf/openrocket/file/rocksim/RocksimLoaderTest.java b/test/net/sf/openrocket/file/rocksim/RocksimLoaderTest.java
deleted file mode 100644 (file)
index 83b1fab..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * RocksimLoaderTest.java
- *
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.LaunchLug;
-import net.sf.openrocket.rocketcomponent.Rocket;
-import net.sf.openrocket.rocketcomponent.Stage;
-import org.junit.Assert;
-
-import java.io.BufferedInputStream;
-import java.io.InputStream;
-
-/**
- * RocksimLoader Tester.
- *
- */
-public class RocksimLoaderTest {
-
-    /**
-     * Test a bug reported via automated bug report.  I have been unable to reproduce this bug
-     * (hanging finset off of an inner body tube) when creating a Rocksim file using Rocksim.  The bug
-     * is reproducible when manually modifying the Rocksim file, which is what is tested here.
-     */
-    @org.junit.Test
-    public void testFinsOnInnerTube() throws Exception {
-        RocksimLoader loader = new RocksimLoader();
-        InputStream stream = this.getClass().getResourceAsStream("PodFins.rkt");
-        Assert.assertNotNull("Could not open PodFins.rkt", stream);
-        try {
-            OpenRocketDocument doc = loader.loadFromStream(new BufferedInputStream(stream));
-            Assert.assertNotNull(doc);
-            Rocket rocket = doc.getRocket();
-            Assert.assertNotNull(rocket);
-        }
-        catch (IllegalStateException ise) {
-            Assert.fail(ise.getMessage());
-        }
-        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
-        InputStream stream = this.getClass().getResourceAsStream("rocksimTestRocket1.rkt");
-        Assert.assertNotNull("Could not open rocksimTestRocket1.rkt", stream);
-        OpenRocketDocument doc = loader.loadFromStream(new BufferedInputStream(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 = loader.loadFromStream(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(1, loader.getWarnings().size());
-        Assert.assertEquals(3, rocket.getStageCount());
-        Stage stage1 = (Stage)rocket.getChild(0);
-        Assert.assertFalse(stage1.isMassOverridden());
-        Assert.assertFalse(stage1.isCGOverridden());
-        Stage stage2 = (Stage)rocket.getChild(1);
-        Assert.assertFalse(stage2.isMassOverridden());
-        Assert.assertFalse(stage2.isCGOverridden());
-        Stage stage3 = (Stage)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 = loader.loadFromStream(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 = (Stage)rocket.getChild(0);
-        stage2 = (Stage)rocket.getChild(1);
-        stage3 = (Stage)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(4, 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.getRadialDirection(), 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);
-    }
-
-}
diff --git a/test/net/sf/openrocket/file/rocksim/RocksimTestBase.java b/test/net/sf/openrocket/file/rocksim/RocksimTestBase.java
deleted file mode 100644 (file)
index 82f1201..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * BaseRocksimTest.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.gui.util.SwingPreferences;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.startup.Application;
-import org.junit.Assert;
-import org.junit.Before;
-
-import java.lang.reflect.Field;
-import java.util.List;
-
-/**
- * A base class for the Rocksim tests.  Includes code from the junitx.addons project.
- */
-public abstract class RocksimTestBase {
-       
-       /* (non-Javadoc)
-        * @see junit.framework.TestCase#setUp()
-        */
-       @Before
-    public void setUp() throws Exception {
-        Application.setPreferences( new SwingPreferences() );
-       }
-
-
-       public void assertContains(RocketComponent child, List<RocketComponent> components) {
-               Assert.assertTrue("Components did not contain child", components.contains(child));
-       }
-       
-       /**
-        * Returns the value of the field on the specified object.  The name
-        * parameter is a <code>String</code> specifying the simple name of the
-        * desired field.<p>
-        *
-        * The object is first searched for any matching field.  If no matching
-        * field is found, the superclasses are recursively searched.
-        *
-        * @exception NoSuchFieldException if a field with the specified name is
-        * not found.
-        */
-       public static Object getField(Object object,
-                                                                       String name)
-                       throws NoSuchFieldException {
-               if (object == null) {
-                       throw new IllegalArgumentException("Invalid null object argument");
-               }
-               for (Class cls = object.getClass(); cls != null; cls = cls.getSuperclass()) {
-                       try {
-                               Field field = cls.getDeclaredField(name);
-                               field.setAccessible(true);
-                               return field.get(object);
-                       } catch (Exception ex) {
-                               /* in case of an exception, we will throw a new
-                                * NoSuchFieldException object */
-                               ;
-                       }
-               }
-               throw new NoSuchFieldException("Could get value for field " +
-                               object.getClass().getName() + "." + name);
-       }
-       
-       /**
-        * Returns the value of the field on the specified class.  The name
-        * parameter is a <code>String</code> specifying the simple name of the
-        * desired field.<p>
-        *
-        * The class is first searched for any matching field.  If no matching
-        * field is found, the superclasses are recursively searched.
-        *
-        * @exception NoSuchFieldException if a field with the specified name is
-        * not found.
-        */
-       public static Object getField(Class cls,
-                                                                       String name)
-                       throws NoSuchFieldException {
-               if (cls == null) {
-                       throw new IllegalArgumentException("Invalid null cls argument");
-               }
-               Class base = cls;
-               while (base != null) {
-                       try {
-                               Field field = base.getDeclaredField(name);
-                               field.setAccessible(true);
-                               return field.get(base);
-                       } catch (Exception ex) {
-                               /* in case of an exception, we will throw a new
-                                * NoSuchFieldException object */
-                               ;
-                       }
-                       base = base.getSuperclass();
-               }
-               throw new NoSuchFieldException("Could get value for static field " +
-                               cls.getName() + "." + name);
-       }
-       
-
-}
diff --git a/test/net/sf/openrocket/file/rocksim/StreamerHandlerTest.java b/test/net/sf/openrocket/file/rocksim/StreamerHandlerTest.java
deleted file mode 100644 (file)
index 3730f88..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * StreamerHandlerTest.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.file.simplesax.PlainTextHandler;
-import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.BodyTube;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.Streamer;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.HashMap;
-
-/**
- * StreamerHandler Tester.
- */
-public class StreamerHandlerTest extends RocksimTestBase {
-
-    /**
-     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testOpenElement() throws Exception {
-        Assert.assertEquals(PlainTextHandler.INSTANCE, new StreamerHandler(new BodyTube(), new WarningSet()).openElement(null, null, null));
-    }
-
-    /**
-     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testCloseElement() throws Exception {
-
-        BodyTube tube = new BodyTube();
-        StreamerHandler handler = new StreamerHandler(tube, new WarningSet());
-        Streamer component = (Streamer) getField(handler, "streamer");
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        handler.closeElement("Width", attributes, "0", warnings);
-        Assert.assertEquals(0d/ RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getStripWidth(), 0.001);
-        handler.closeElement("Width", attributes, "10", warnings);
-        Assert.assertEquals(10d/ RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getStripWidth(), 0.001);
-        handler.closeElement("Width", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Len", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getStripLength(), 0.001);
-        handler.closeElement("Len", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getStripLength(), 0.001);
-        handler.closeElement("Len", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getStripLength(), 0.001);
-        handler.closeElement("Len", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Name", attributes, "Test Name", warnings);
-        Assert.assertEquals("Test Name", component.getName());
-
-        handler.closeElement("DragCoefficient", attributes, "0.94", warnings);
-        Assert.assertEquals(0.94d, component.getCD(), 0.001);
-        handler.closeElement("DragCoefficient", attributes, "-0.94", warnings);
-        Assert.assertEquals(-0.94d, component.getCD(), 0.001);
-        handler.closeElement("DragCoefficient", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-    }
-
-    /**
-     * Method: constructor
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testConstructor() throws Exception {
-
-        try {
-            new StreamerHandler(null, new WarningSet());
-            Assert.fail("Should have thrown IllegalArgumentException");
-        }
-        catch (IllegalArgumentException iae) {
-            //success
-        }
-
-        BodyTube tube = new BodyTube();
-        StreamerHandler handler = new StreamerHandler(tube, new WarningSet());
-        Streamer component = (Streamer) getField(handler, "streamer");
-        assertContains(component, tube.getChildren());
-    }
-
-    /**
-     * Method: setRelativePosition(RocketComponent.Position position)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testSetRelativePosition() throws Exception {
-        BodyTube tube = new BodyTube();
-        StreamerHandler handler = new StreamerHandler(tube, new WarningSet());
-        Streamer component = (Streamer) getField(handler, "streamer");
-        handler.setRelativePosition(RocketComponent.Position.ABSOLUTE);
-        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
-    }
-
-    /**
-     * Method: getComponent()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testGetComponent() throws Exception {
-        Assert.assertTrue(new StreamerHandler(new BodyTube(), new WarningSet()).getComponent() instanceof Streamer);
-    }
-
-    /**
-     * Method: getMaterialType()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testGetMaterialType() throws Exception {
-        Assert.assertEquals(Material.Type.SURFACE, new StreamerHandler(new BodyTube(), new WarningSet()).getMaterialType());
-    }
-
-    /**
-     * Method: endHandler()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @Test
-    public void testEndHandler() throws Exception {
-        BodyTube tube = new BodyTube();
-        StreamerHandler handler = new StreamerHandler(tube, new WarningSet());
-        Streamer component = (Streamer) getField(handler, "streamer");
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        handler.closeElement("Xb", attributes, "-10", warnings);
-        handler.closeElement("LocationMode", attributes, "1", warnings);
-        handler.endHandler("Streamer", attributes, null, warnings);
-        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
-        Assert.assertEquals(component.getPositionValue(), -10d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, 0.001);
-
-        handler.closeElement("Xb", attributes, "-10", warnings);
-        handler.closeElement("LocationMode", attributes, "2", warnings);
-        handler.endHandler("Streamer", attributes, null, warnings);
-        Assert.assertEquals(RocketComponent.Position.BOTTOM, component.getRelativePosition());
-        Assert.assertEquals(component.getPositionValue(), 10d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, 0.001);
-
-        handler.closeElement("Thickness", attributes, "0.02", warnings);
-        Assert.assertEquals(0.01848, handler.computeDensity(RocksimDensityType.ROCKSIM_BULK, 924d), 0.001);
-
-        //Test Density Type 0 (Bulk)
-        handler.closeElement("Density", attributes, "924.0", warnings);
-        handler.closeElement("DensityType", attributes, "0", warnings);
-        handler.endHandler("Streamer", attributes, null, warnings);
-        Assert.assertEquals(0.01848d, component.getMaterial().getDensity(), 0.001);
-
-        //Test Density Type 1 (Surface)
-        handler.closeElement("Density", attributes, "0.006685", warnings);
-        handler.closeElement("DensityType", attributes, "1", warnings);
-        handler.endHandler("Streamer", attributes, null, warnings);
-        Assert.assertTrue(Math.abs(0.06685d - component.getMaterial().getDensity()) < 0.00001);
-
-        //Test Density Type 2 (Line)
-        handler.closeElement("Density", attributes, "0.223225", warnings);
-        handler.closeElement("DensityType", attributes, "2", warnings);
-        handler.closeElement("Len", attributes, "3810.", warnings);
-        handler.closeElement("Width", attributes, "203.2", warnings);
-        handler.endHandler("Streamer", attributes, null, warnings);
-
-        Assert.assertEquals(1.728190092, component.getMass(), 0.001);
-
-    }
-
-}
diff --git a/test/net/sf/openrocket/file/rocksim/TransitionHandlerTest.java b/test/net/sf/openrocket/file/rocksim/TransitionHandlerTest.java
deleted file mode 100644 (file)
index 2754294..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * TransitionHandlerTest.java
- */
-package net.sf.openrocket.file.rocksim;
-
-import net.sf.openrocket.aerodynamics.WarningSet;
-import net.sf.openrocket.file.simplesax.PlainTextHandler;
-import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.ExternalComponent;
-import net.sf.openrocket.rocketcomponent.Stage;
-import net.sf.openrocket.rocketcomponent.Transition;
-import org.junit.Assert;
-
-import java.util.HashMap;
-
-/**
- * TransitionHandler Tester.
- */
-public class TransitionHandlerTest extends RocksimTestBase {
-
-    /**
-     * Method: constructor
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testConstructor() throws Exception {
-
-        try {
-            new TransitionHandler(null, new WarningSet());
-            Assert.fail("Should have thrown IllegalArgumentException");
-        }
-        catch (IllegalArgumentException iae) {
-            //success
-        }
-
-        Stage stage = new Stage();
-        TransitionHandler handler = new TransitionHandler(stage, new WarningSet());
-        Transition component = (Transition) getField(handler, "transition");
-        assertContains(component, stage.getChildren());
-    }
-
-    /**
-     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testOpenElement() throws Exception {
-        Assert.assertEquals(PlainTextHandler.INSTANCE, new TransitionHandler(new Stage(), new WarningSet()).openElement(null, null, null));
-    }
-
-    /**
-     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testCloseElement() throws Exception {
-
-        Stage stage = new Stage();
-        HashMap<String, String> attributes = new HashMap<String, String>();
-        WarningSet warnings = new WarningSet();
-
-        TransitionHandler handler = new TransitionHandler(stage, new WarningSet());
-        Transition component = (Transition) getField(handler, "transition");
-
-        handler.closeElement("ShapeCode", attributes, "0", warnings);
-        Assert.assertEquals(Transition.Shape.CONICAL, component.getType());
-        handler.closeElement("ShapeCode", attributes, "1", warnings);
-        Assert.assertEquals(Transition.Shape.OGIVE, component.getType());
-        handler.closeElement("ShapeCode", attributes, "17", warnings);
-        Assert.assertEquals(RocksimNoseConeCode.PARABOLIC.asOpenRocket(), component.getType());  //test of default
-        handler.closeElement("ShapeCode", attributes, "foo", warnings);
-        Assert.assertNotNull(component.getType());
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Len", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
-        handler.closeElement("Len", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("FrontDia", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getForeRadius(), 0.001);
-        handler.closeElement("FrontDia", attributes, "100", warnings);
-        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getForeRadius(), 0.001);
-        handler.closeElement("FrontDia", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("RearDia", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getAftRadius(), 0.001);
-        handler.closeElement("RearDia", attributes, "100", warnings);
-        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getAftRadius(), 0.001);
-        handler.closeElement("RearDia", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        final double aft = 100d;
-        component.setAftRadius(aft);
-        
-        handler.closeElement("ConstructionType", attributes, "0", warnings);
-        component.setAftShoulderRadius(1.1d);
-        component.setForeShoulderRadius(1.1d);
-        handler.closeElement("WallThickness", attributes, "-1", warnings);
-        handler.endHandler("Transition", attributes, null, warnings);
-        Assert.assertEquals(component.getAftRadius(), component.getThickness(), 0.001);
-        Assert.assertEquals(component.getAftShoulderThickness(), component.getAftShoulderThickness(), 0.001);
-        Assert.assertEquals(component.getForeShoulderThickness(), component.getForeShoulderThickness(), 0.001);
-        handler.closeElement("WallThickness", attributes, "100", warnings);
-        handler.endHandler("Transition", attributes, null, warnings);
-        Assert.assertEquals(aft, component.getThickness(), 0.001);
-        handler.closeElement("WallThickness", attributes, "foo", warnings);
-        handler.endHandler("Transition", attributes, null, warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-        
-        handler.closeElement("ConstructionType", attributes, "1", warnings);
-        component.setAftShoulderRadius(1.1d);
-        component.setForeShoulderRadius(1.1d);
-        handler.closeElement("WallThickness", attributes, "-1", warnings);
-        handler.endHandler("Transition", attributes, null, warnings);
-        Assert.assertEquals(0d, component.getThickness(), 0.001);
-        Assert.assertEquals(0d, component.getAftShoulderThickness(), 0.001);
-        Assert.assertEquals(0d, component.getForeShoulderThickness(), 0.001);
-        handler.closeElement("WallThickness", attributes, "1.1", warnings);
-        handler.endHandler("Transition", attributes, null, warnings);
-        Assert.assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getThickness(), 0.001);
-        Assert.assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderThickness(), 0.001);
-        Assert.assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getForeShoulderThickness(), 0.001);
-        
-
-        handler.closeElement("FrontShoulderLen", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getForeShoulderLength(), 0.001);
-        handler.closeElement("FrontShoulderLen", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getForeShoulderLength(), 0.001);
-        handler.closeElement("FrontShoulderLen", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getForeShoulderLength(), 0.001);
-        handler.closeElement("FrontShoulderLen", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("RearShoulderLen", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getAftShoulderLength(), 0.001);
-        handler.closeElement("RearShoulderLen", attributes, "10", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderLength(), 0.001);
-        handler.closeElement("RearShoulderLen", attributes, "10.0", warnings);
-        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderLength(), 0.001);
-        handler.closeElement("RearShoulderLen", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("FrontShoulderDia", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getForeShoulderRadius(), 0.001);
-        handler.closeElement("FrontShoulderDia", attributes, "100", warnings);
-        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getForeShoulderRadius(), 0.001);
-        handler.closeElement("FrontShoulderDia", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("RearShoulderDia", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getAftShoulderRadius(), 0.001);
-        handler.closeElement("RearShoulderDia", attributes, "100", warnings);
-        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getAftShoulderRadius(), 0.001);
-        handler.closeElement("RearShoulderDia", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        component.setType(Transition.Shape.HAACK);
-        handler.closeElement("ShapeParameter", attributes, "-1", warnings);
-        Assert.assertEquals(0d, component.getShapeParameter(), 0.001);
-        handler.closeElement("ShapeParameter", attributes, "100", warnings);
-        Assert.assertEquals(Transition.Shape.HAACK.maxParameter(), component.getShapeParameter(), 0.001);
-        handler.closeElement("ShapeParameter", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        Assert.assertEquals("Could not convert ShapeParameter value of foo.  It is expected to be a number.", 
-                     warnings.iterator().next().toString());
-
-        warnings.clear();
-
-        component.setType(Transition.Shape.CONICAL);
-        component.setShapeParameter(0d);
-        handler.closeElement("ShapeParameter", attributes, "100", warnings);
-        Assert.assertEquals(0d, component.getShapeParameter(), 0.001);
-
-        handler.closeElement("FinishCode", attributes, "-1", warnings);
-        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
-        handler.closeElement("FinishCode", attributes, "100", warnings);
-        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
-        handler.closeElement("FinishCode", attributes, "foo", warnings);
-        Assert.assertEquals(1, warnings.size());
-        warnings.clear();
-
-        handler.closeElement("Name", attributes, "Test Name", warnings);
-        Assert.assertEquals("Test Name", component.getName());
-        
-        handler.closeElement("Material", attributes, "Some Material", warnings);
-        handler.endHandler("Transition", attributes, null, warnings);
-        Assert.assertTrue(component.getMaterial().getName().contains("Some Material"));
-    }
-
-    /**
-     * Method: getComponent()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetComponent() throws Exception {
-        Assert.assertTrue(new TransitionHandler(new Stage(), new WarningSet()).getComponent() instanceof Transition);
-    }
-
-    /**
-     * Method: getMaterialType()
-     *
-     * @throws Exception thrown if something goes awry
-     */
-    @org.junit.Test
-    public void testGetMaterialType() throws Exception {
-        Assert.assertEquals(Material.Type.BULK, new TransitionHandler(new Stage(), new WarningSet()).getMaterialType());
-    }
-
-
-}
diff --git a/test/net/sf/openrocket/file/rocksim/export/RocksimDocumentDTOTest.java b/test/net/sf/openrocket/file/rocksim/export/RocksimDocumentDTOTest.java
new file mode 100644 (file)
index 0000000..7feb8d2
--- /dev/null
@@ -0,0 +1,66 @@
+package net.sf.openrocket.file.rocksim.export;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.file.rocksim.importt.RocksimLoader;
+import net.sf.openrocket.file.rocksim.importt.RocksimLoaderTest;
+import net.sf.openrocket.file.rocksim.importt.RocksimTestBase;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.StringWriter;
+
+/**
+ */
+public class RocksimDocumentDTOTest extends RocksimTestBase {
+    
+    @Test
+    public void testDTO() throws Exception {
+        JAXBContext binder = JAXBContext.newInstance(RocksimDocumentDTO.class);
+        Marshaller marshaller = binder.createMarshaller();
+        marshaller.setProperty("jaxb.fragment", Boolean.TRUE);
+
+        NoseConeDTO noseCone = new NoseConeDTO();
+        noseCone.setBaseDia(10d);
+        noseCone.setCalcCG(1.3d);
+
+        StageDTO stage1 = new StageDTO();
+        stage1.addExternalPart(noseCone);
+
+        RocketDesignDTO design2 = new RocketDesignDTO();
+        design2.setName("Test");
+        design2.setStage3(stage1);
+
+        RocksimDesignDTO design = new RocksimDesignDTO();
+        design.setDesign(design2);
+        RocksimDocumentDTO message = new RocksimDocumentDTO();
+        message.setDesign(design);
+
+
+        StringWriter stringWriter = new StringWriter();
+        marshaller.marshal(message, stringWriter);
+
+        String response = stringWriter.toString();
+
+        System.err.println(response);
+    }
+    
+    @Test
+    public void testRoundTrip() throws Exception {
+        OpenRocketDocument ord = RocksimLoaderTest.loadRocksimRocket3(new RocksimLoader());
+        
+        Assert.assertNotNull(ord);
+        String result = new RocksimSaver().marshalToRocksim(ord);
+
+//        System.err.println(result);
+        
+        File output = new File("rt.rkt");
+        FileWriter fw = new FileWriter(output);
+        fw.write(result);
+        fw.flush();
+        fw.close();
+    }
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/BodyTubeHandlerTest.java b/test/net/sf/openrocket/file/rocksim/importt/BodyTubeHandlerTest.java
new file mode 100644 (file)
index 0000000..b69a3bd
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * BodyTubeHandlerTest.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.PlainTextHandler;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.ExternalComponent;
+import net.sf.openrocket.rocketcomponent.Stage;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+
+/**
+ * BodyTubeHandler Tester.
+ *
+ */
+public class BodyTubeHandlerTest extends RocksimTestBase {
+
+    /**
+     * Method: constructor
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testConstructor() throws Exception {
+
+        try {
+            new BodyTubeHandler(null, new WarningSet());
+            Assert.fail("Should have thrown IllegalArgumentException");
+        }
+        catch (IllegalArgumentException iae) {
+            //success
+        }
+
+        Stage stage = new Stage();
+        BodyTubeHandler handler = new BodyTubeHandler(stage, new WarningSet());
+        BodyTube component = (BodyTube) getField(handler, "bodyTube");
+        assertContains(component, stage.getChildren());
+    }
+
+    /**
+     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testOpenElement() throws Exception {
+        Assert.assertEquals(PlainTextHandler.INSTANCE, new BodyTubeHandler(new Stage(), new WarningSet()).openElement(null, null, null));
+        Assert.assertNotNull(new BodyTubeHandler(new Stage(), new WarningSet()).openElement("AttachedParts", null, null));
+    }
+
+    /**
+     *
+     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+     *
+     * @throws Exception  thrown if something goes awry
+     */
+    @Test
+    public void testCloseElement() throws Exception {
+        Stage stage = new Stage();
+        BodyTubeHandler handler = new BodyTubeHandler(stage, new WarningSet());
+        BodyTube component = (BodyTube) getField(handler, "bodyTube");
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        handler.closeElement("OD", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
+        handler.closeElement("OD", attributes, "0", warnings);
+        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
+        handler.closeElement("OD", attributes, "75", warnings);
+        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius(), 0.001);
+        handler.closeElement("OD", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("ID", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
+        handler.closeElement("ID", attributes, "0", warnings);
+        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
+        handler.closeElement("ID", attributes, "75", warnings);
+        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius(), 0.001);
+        handler.closeElement("ID", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Len", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("IsMotorMount", attributes, "1", warnings);
+        Assert.assertTrue(component.isMotorMount());
+        handler.closeElement("IsMotorMount", attributes, "0", warnings);
+        Assert.assertFalse(component.isMotorMount());
+        handler.closeElement("IsMotorMount", attributes, "foo", warnings);
+        Assert.assertFalse(component.isMotorMount());
+
+        handler.closeElement("EngineOverhang", attributes, "-1", warnings);
+        Assert.assertEquals(-1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang(), 0.001);
+        handler.closeElement("EngineOverhang", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang(), 0.001);
+        handler.closeElement("EngineOverhang", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang(), 0.001);
+        handler.closeElement("EngineOverhang", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("FinishCode", attributes, "-1", warnings);
+        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
+        handler.closeElement("FinishCode", attributes, "100", warnings);
+        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
+        handler.closeElement("FinishCode", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Name", attributes, "Test Name", warnings);
+        Assert.assertEquals("Test Name", component.getName());
+    }
+    
+    /**
+     * Method: getComponent()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testGetComponent() throws Exception {
+        Assert.assertTrue(new BodyTubeHandler(new Stage(), new WarningSet()).getComponent() instanceof BodyTube);
+    }
+
+    /**
+     * Method: getMaterialType()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testGetMaterialType() throws Exception {
+        Assert.assertEquals(Material.Type.BULK, new BodyTubeHandler(new Stage(), new WarningSet()).getMaterialType());
+    }
+
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/FinSetHandlerTest.java b/test/net/sf/openrocket/file/rocksim/importt/FinSetHandlerTest.java
new file mode 100644 (file)
index 0000000..503654b
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * FinSetHandlerTest.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import junit.framework.TestCase;
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.EllipticalFinSet;
+import net.sf.openrocket.rocketcomponent.FinSet;
+import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
+import net.sf.openrocket.util.Coordinate;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+/**
+ * FinSetHandler Tester.
+ *
+ */
+public class FinSetHandlerTest extends TestCase {
+
+    /**
+     * Method: asOpenRocket(WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testAsOpenRocket() throws Exception {
+
+        FinSetHandler dto = new FinSetHandler(new BodyTube());
+
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        dto.closeElement("Name", attributes, "The name", warnings);
+        dto.closeElement("ShapeCode", attributes, "0", warnings);
+        dto.closeElement("Xb", attributes, "2", warnings);
+        dto.closeElement("FinCount", attributes, "4", warnings);
+        dto.closeElement("RootChord", attributes, "10", warnings);
+        dto.closeElement("TipChord", attributes, "11", warnings);
+        dto.closeElement("SemiSpan", attributes, "12", warnings);
+        dto.closeElement("MidChordLen", attributes, "13", warnings);
+        dto.closeElement("SweepDistance", attributes, "14", warnings);
+        dto.closeElement("Thickness", attributes, "200", warnings);
+        dto.closeElement("TipShapeCode", attributes, "1", warnings);
+        dto.closeElement("TabLength", attributes, "400", warnings);
+        dto.closeElement("TabDepth", attributes, "500", warnings);
+        dto.closeElement("TabOffset", attributes, "30", warnings);
+        dto.closeElement("RadialAngle", attributes, ".123", warnings);
+        dto.closeElement("PointList", attributes, "20,0|2,2|0,0", warnings);
+        dto.closeElement("LocationMode", attributes, "0", warnings);
+
+        WarningSet set = new WarningSet();
+        FinSet fins = dto.asOpenRocket(set);
+        assertNotNull(fins);
+        assertEquals(0, set.size());
+
+        assertEquals("The name", fins.getName());
+        assertTrue(fins instanceof TrapezoidFinSet);
+        assertEquals(4, fins.getFinCount());
+
+        assertEquals(0.012d, ((TrapezoidFinSet) fins).getHeight());
+        assertEquals(0.012d, fins.getSpan());
+        
+        assertEquals(0.2d, fins.getThickness());
+        assertEquals(0.4d, fins.getTabLength());
+        assertEquals(0.5d, fins.getTabHeight());
+        assertEquals(0.03d, fins.getTabShift());
+        assertEquals(.123d, fins.getBaseRotation());
+
+        dto.closeElement("ShapeCode", attributes, "1", warnings);
+        fins = dto.asOpenRocket(set);
+        assertNotNull(fins);
+        assertEquals(0, set.size());
+
+        assertEquals("The name", fins.getName());
+        assertTrue(fins instanceof EllipticalFinSet);
+        assertEquals(4, fins.getFinCount());
+
+        assertEquals(0.2d, fins.getThickness());
+        assertEquals(0.4d, fins.getTabLength());
+        assertEquals(0.5d, fins.getTabHeight());
+        assertEquals(0.03d, fins.getTabShift());
+        assertEquals(.123d, fins.getBaseRotation());
+    }
+
+
+    /**
+     * Method: toCoordinates(String pointList)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testToCoordinates() throws Exception {
+        FinSetHandler holder = new FinSetHandler(new BodyTube());
+        Method method = FinSetHandler.class.getDeclaredMethod("toCoordinates", String.class, WarningSet.class);
+        method.setAccessible(true);
+
+        WarningSet warnings = new WarningSet();
+        //Null finlist
+        String finlist = null;
+        Coordinate[] result = (Coordinate[])method.invoke(holder, finlist, warnings);
+        assertNotNull(result);
+        assertTrue(0 == result.length);
+
+        //Empty string finlist
+        finlist = "";
+        result = (Coordinate[])method.invoke(holder, finlist, warnings);
+        assertNotNull(result);
+        assertTrue(0 == result.length);
+        
+        //Invalid finlist (only x coordinate)
+        finlist = "10.0";
+        result = (Coordinate[])method.invoke(holder, finlist, warnings);
+        assertNotNull(result);
+        assertTrue(0 == result.length);
+        assertEquals(1, warnings.size());
+        warnings.clear();
+
+        //Invalid finlist (non-numeric character)
+        finlist = "10.0,asdf";
+        result = (Coordinate[])method.invoke(holder, finlist, warnings);
+        assertNotNull(result);
+        assertTrue(0 == result.length);
+        assertEquals(1, warnings.size());
+        warnings.clear();
+
+        //Invalid finlist (all delimiters)
+        finlist = "||||||";
+        result = (Coordinate[])method.invoke(holder, finlist, warnings);
+        assertNotNull(result);
+        assertTrue(0 == result.length);
+        assertEquals(0, warnings.size());
+        warnings.clear();
+
+        //One point finlist - from a parsing view it's valid; from a practical view it may not be, but that's outside
+        //the scope of this test case
+        finlist = "10.0,5.0";
+        result = (Coordinate[])method.invoke(holder, finlist, warnings);
+        assertNotNull(result);
+        assertTrue(1 == result.length);
+        assertEquals(0, warnings.size());
+        warnings.clear();
+        
+        //Two point finlist - from a parsing view it's valid; from a practical view it may not be, but that's outside
+        //the scope of this test case
+        finlist = "10.0,5.0|3.3,4.4";
+        result = (Coordinate[])method.invoke(holder, finlist, warnings);
+        assertNotNull(result);
+        assertTrue(2 == result.length);
+        assertEquals(0, warnings.size());
+        warnings.clear();
+        
+        //Normal four point finlist.
+        finlist = "518.16,0|517.494,37.2145|1.31261,6.77283|0,0|";
+        result = (Coordinate[])method.invoke(holder, finlist, warnings);
+        assertNotNull(result);
+        assertTrue(4 == result.length);
+        assertEquals(new Coordinate(0,0), result[0]);
+        assertEquals(0, warnings.size());
+        warnings.clear();
+        
+        //Normal four point finlist with spaces.
+        finlist = "518.16 , 0 | 517.494 , 37.2145 | 1.31261,6.77283|0,0|";
+        result = (Coordinate[])method.invoke(holder, finlist, warnings);
+        assertNotNull(result);
+        assertTrue(4 == result.length);
+        assertEquals(new Coordinate(0,0), result[0]);
+        assertEquals(new Coordinate(.51816,0), result[3]);
+        assertEquals(0, warnings.size());
+        warnings.clear();
+        
+        //Reversed Normal four point finlist.
+        finlist = "0,0|1.31261,6.77283|517.494,37.2145|518.16,0|";
+        result = (Coordinate[])method.invoke(holder, finlist, warnings);
+        assertNotNull(result);
+        assertTrue(4 == result.length);
+        assertEquals(new Coordinate(0,0), result[0]);
+        assertEquals(new Coordinate(.51816,0), result[3]);
+        assertEquals(0, warnings.size());
+        warnings.clear();
+        
+    }
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/InnerBodyTubeHandlerTest.java b/test/net/sf/openrocket/file/rocksim/importt/InnerBodyTubeHandlerTest.java
new file mode 100644 (file)
index 0000000..fa070ce
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * InnerBodyTubeHandlerTest.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.PlainTextHandler;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.InnerTube;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.junit.Assert;
+
+import java.util.HashMap;
+
+/**
+ * InnerBodyTubeHandler Tester.
+ *
+ */
+public class InnerBodyTubeHandlerTest extends RocksimTestBase {
+
+    /**
+     * Method: constructor
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testConstructor() throws Exception {
+
+        try {
+            new InnerBodyTubeHandler(null, new WarningSet());
+            Assert.fail("Should have thrown IllegalArgumentException");
+        }
+        catch (IllegalArgumentException iae) {
+            //success
+        }
+
+        BodyTube tube = new BodyTube();
+        InnerBodyTubeHandler handler = new InnerBodyTubeHandler(tube, new WarningSet());
+        InnerTube component = (InnerTube) getField(handler, "bodyTube");
+        assertContains(component, tube.getChildren());
+    }
+
+    /**
+     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testOpenElement() throws Exception {
+        Assert.assertEquals(PlainTextHandler.INSTANCE, new InnerBodyTubeHandler(new BodyTube(), new WarningSet()).openElement(null, null, null));
+        Assert.assertNotNull(new InnerBodyTubeHandler(new BodyTube(), new WarningSet()).openElement("AttachedParts", null, null));
+    }
+
+    /**
+     *
+     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+     *
+     * @throws Exception  thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testCloseElement() throws Exception {
+        BodyTube tube = new BodyTube();
+        InnerBodyTubeHandler handler = new InnerBodyTubeHandler(tube, new WarningSet());
+        InnerTube component = (InnerTube) getField(handler, "bodyTube");
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        handler.closeElement("OD", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
+        handler.closeElement("OD", attributes, "0", warnings);
+        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
+        handler.closeElement("OD", attributes, "75", warnings);
+        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius(), 0.001);
+        handler.closeElement("OD", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("ID", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
+        handler.closeElement("ID", attributes, "0", warnings);
+        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
+        handler.closeElement("ID", attributes, "75", warnings);
+        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius(), 0.001);
+        handler.closeElement("ID", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Len", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("IsMotorMount", attributes, "1", warnings);
+        Assert.assertTrue(component.isMotorMount());
+        handler.closeElement("IsMotorMount", attributes, "0", warnings);
+        Assert.assertFalse(component.isMotorMount());
+        handler.closeElement("IsMotorMount", attributes, "foo", warnings);
+        Assert.assertFalse(component.isMotorMount());
+
+        handler.closeElement("EngineOverhang", attributes, "-1", warnings);
+        Assert.assertEquals(-1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang(), 0.001);
+        handler.closeElement("EngineOverhang", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang(), 0.001);
+        handler.closeElement("EngineOverhang", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang(), 0.001);
+        handler.closeElement("EngineOverhang", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Name", attributes, "Test Name", warnings);
+        Assert.assertEquals("Test Name", component.getName());
+    }
+    
+    /**
+     * Method: setRelativePosition(RocketComponent.Position position)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testSetRelativePosition() throws Exception {
+        BodyTube tube = new BodyTube();
+        InnerBodyTubeHandler handler = new InnerBodyTubeHandler(tube, new WarningSet());
+        InnerTube component = (InnerTube) getField(handler, "bodyTube");
+        handler.setRelativePosition(RocketComponent.Position.ABSOLUTE);
+        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
+    }
+
+    /**
+     * Method: getComponent()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetComponent() throws Exception {
+        Assert.assertTrue(new InnerBodyTubeHandler(new BodyTube(), new WarningSet()).getComponent() instanceof InnerTube);
+    }
+
+    /**
+     * Method: getMaterialType()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetMaterialType() throws Exception {
+        Assert.assertEquals(Material.Type.BULK, new InnerBodyTubeHandler(new BodyTube(), new WarningSet()).getMaterialType());
+    }
+
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/LaunchLugHandlerTest.java b/test/net/sf/openrocket/file/rocksim/importt/LaunchLugHandlerTest.java
new file mode 100644 (file)
index 0000000..503ce80
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * LaunchLugHandlerTest.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.PlainTextHandler;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.ExternalComponent;
+import net.sf.openrocket.rocketcomponent.LaunchLug;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.junit.Assert;
+
+import java.util.HashMap;
+
+/**
+ * LaunchLugHandler Tester.
+ *
+ */
+public class LaunchLugHandlerTest extends RocksimTestBase {
+
+    /**
+     * Method: constructor
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testConstructor() throws Exception {
+
+        try {
+            new LaunchLugHandler(null, new WarningSet());
+            Assert.fail("Should have thrown IllegalArgumentException");
+        }
+        catch (IllegalArgumentException iae) {
+            //success
+        }
+
+        BodyTube tube = new BodyTube();
+        LaunchLugHandler handler = new LaunchLugHandler(tube, new WarningSet());
+        LaunchLug component = (LaunchLug) getField(handler, "lug");
+        assertContains(component, tube.getChildren());
+    }
+
+    /**
+     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testOpenElement() throws Exception {
+        Assert.assertEquals(PlainTextHandler.INSTANCE, new LaunchLugHandler(new BodyTube(), new WarningSet()).openElement(null, null, null));
+    }
+
+    /**
+     *
+     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+     *
+     * @throws Exception  thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testCloseElement() throws Exception {
+        BodyTube tube = new BodyTube();
+        LaunchLugHandler handler = new LaunchLugHandler(tube, new WarningSet());
+        LaunchLug component = (LaunchLug) getField(handler, "lug");
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        handler.closeElement("OD", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getOuterRadius(), 0.001);
+        handler.closeElement("OD", attributes, "0", warnings);
+        Assert.assertEquals(0d, component.getOuterRadius(), 0.001);
+        handler.closeElement("OD", attributes, "75", warnings);
+        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getOuterRadius(), 0.001);
+        handler.closeElement("OD", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("ID", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
+        handler.closeElement("ID", attributes, "0", warnings);
+        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
+        handler.closeElement("ID", attributes, "75", warnings);
+        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius(), 0.001);
+        handler.closeElement("ID", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Len", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("FinishCode", attributes, "-1", warnings);
+        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
+        handler.closeElement("FinishCode", attributes, "100", warnings);
+        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
+        handler.closeElement("FinishCode", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Name", attributes, "Test Name", warnings);
+        Assert.assertEquals("Test Name", component.getName());
+    }
+    
+    /**
+     * Method: setRelativePosition(RocketComponent.Position position)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testSetRelativePosition() throws Exception {
+        BodyTube tube = new BodyTube();
+        LaunchLugHandler handler = new LaunchLugHandler(tube, new WarningSet());
+        LaunchLug component = (LaunchLug) getField(handler, "lug");
+        handler.setRelativePosition(RocketComponent.Position.ABSOLUTE);
+        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
+    }
+
+    /**
+     * Method: getComponent()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetComponent() throws Exception {
+        Assert.assertTrue(new LaunchLugHandler(new BodyTube(), new WarningSet()).getComponent() instanceof LaunchLug);
+    }
+
+    /**
+     * Method: getMaterialType()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetMaterialType() throws Exception {
+        Assert.assertEquals(Material.Type.BULK, new LaunchLugHandler(new BodyTube(), new WarningSet()).getMaterialType());
+    }
+
+
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/MassObjectHandlerTest.java b/test/net/sf/openrocket/file/rocksim/importt/MassObjectHandlerTest.java
new file mode 100644 (file)
index 0000000..e5360a1
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * MassObjectHandlerTest.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.PlainTextHandler;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.MassComponent;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.junit.Assert;
+
+import java.util.HashMap;
+
+/**
+ * MassObjectHandler Tester.
+ *
+ */
+public class MassObjectHandlerTest extends RocksimTestBase {
+
+    /**
+     * Method: constructor
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testConstructor() throws Exception {
+
+        try {
+            new MassObjectHandler(null, new WarningSet());
+            Assert.fail("Should have thrown IllegalArgumentException");
+        }
+        catch (IllegalArgumentException iae) {
+            //success
+        }
+
+        BodyTube tube = new BodyTube();
+        MassObjectHandler handler = new MassObjectHandler(tube, new WarningSet());
+        MassComponent component = (MassComponent) getField(handler, "mass");
+        assertContains(component, tube.getChildren());
+    }
+
+    /**
+     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testOpenElement() throws Exception {
+        Assert.assertEquals(PlainTextHandler.INSTANCE, new MassObjectHandler(new BodyTube(), new WarningSet()).openElement(null, null, null));
+    }
+
+    /**
+     *
+     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+     *
+     * @throws Exception  thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testCloseElement() throws Exception {
+        BodyTube tube = new BodyTube();
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        MassObjectHandler handler = new MassObjectHandler(tube, new WarningSet());
+        MassComponent component = (MassComponent) getField(handler, "mass");
+
+        handler.closeElement("Len", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10", warnings);
+        Assert.assertEquals(10d / (MassObjectHandler.MASS_LEN_FUDGE_FACTOR * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)
+                , component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / (MassObjectHandler.MASS_LEN_FUDGE_FACTOR * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)
+                , component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("KnownMass", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getComponentMass(), 0.001);
+        handler.closeElement("KnownMass", attributes, "100", warnings);
+        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS, component.getComponentMass(), 0.001);
+        handler.closeElement("KnownMass", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+    }
+    
+    /**
+     * Method: setRelativePosition(RocketComponent.Position position)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testSetRelativePosition() throws Exception {
+        BodyTube tube = new BodyTube();
+        MassObjectHandler handler = new MassObjectHandler(tube, new WarningSet());
+        MassComponent component = (MassComponent) getField(handler, "mass");
+        handler.setRelativePosition(RocketComponent.Position.ABSOLUTE);
+        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
+    }
+
+    /**
+     * Method: getComponent()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetComponent() throws Exception {
+        Assert.assertTrue(new MassObjectHandler(new BodyTube(), new WarningSet()).getComponent() instanceof MassComponent);
+    }
+
+    /**
+     * Method: getMaterialType()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetMaterialType() throws Exception {
+        Assert.assertEquals(Material.Type.BULK, new MassObjectHandler(new BodyTube(), new WarningSet()).getMaterialType());
+    }
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/NoseConeHandlerTest.java b/test/net/sf/openrocket/file/rocksim/importt/NoseConeHandlerTest.java
new file mode 100644 (file)
index 0000000..593434c
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * NoseConeHandlerTest.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.PlainTextHandler;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.ExternalComponent;
+import net.sf.openrocket.rocketcomponent.NoseCone;
+import net.sf.openrocket.rocketcomponent.Stage;
+import net.sf.openrocket.rocketcomponent.Transition;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+
+/**
+ * NoseConeHandler Tester.
+ *
+ */
+public class NoseConeHandlerTest extends RocksimTestBase {
+
+    /**
+     * Method: constructor
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testConstructor() throws Exception {
+
+        try {
+            new NoseConeHandler(null, new WarningSet());
+            Assert.fail("Should have thrown IllegalArgumentException");
+        }
+        catch (IllegalArgumentException iae) {
+            //success
+        }
+
+        Stage stage = new Stage();
+        NoseConeHandler handler = new NoseConeHandler(stage, new WarningSet());
+        NoseCone component = (NoseCone) getField(handler, "noseCone");
+        assertContains(component, stage.getChildren());
+    }
+
+    /**
+     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testOpenElement() throws Exception {
+        Assert.assertEquals(PlainTextHandler.INSTANCE, new NoseConeHandler(new Stage(), new WarningSet()).openElement(null, null, null));
+        Assert.assertNotNull(new NoseConeHandler(new Stage(), new WarningSet()).openElement("AttachedParts", null, null));
+    }
+
+    /**
+     *
+     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+     *
+     * @throws Exception  thrown if something goes awry
+     */
+    @Test
+    public void testCloseElement() throws Exception {
+
+        Stage stage = new Stage();
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        NoseConeHandler handler = new NoseConeHandler(stage, warnings);
+        NoseCone component = (NoseCone) getField(handler, "noseCone");
+
+        handler.closeElement("ShapeCode", attributes, "0", warnings);
+        Assert.assertEquals(Transition.Shape.CONICAL, component.getType());
+        handler.closeElement("ShapeCode", attributes, "1", warnings);
+        Assert.assertEquals(Transition.Shape.OGIVE, component.getType());
+        handler.closeElement("ShapeCode", attributes, "17", warnings);
+        Assert.assertEquals(RocksimNoseConeCode.PARABOLIC.asOpenRocket(), component.getType());  //test of default
+        handler.closeElement("ShapeCode", attributes, "foo", warnings);
+        Assert.assertNotNull(component.getType());
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Len", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("BaseDia", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getAftRadius(), 0.001);
+        handler.closeElement("BaseDia", attributes, "100", warnings);
+        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getAftRadius(), 0.001);
+        handler.closeElement("BaseDia", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        
+        final double aft = 100d;
+        component.setAftRadius(aft);
+        
+        handler.closeElement("ConstructionType", attributes, "0", warnings);
+        component.setAftShoulderRadius(1.1d);
+        handler.closeElement("WallThickness", attributes, "-1", warnings);
+        handler.endHandler("Transition", attributes, null, warnings);
+        Assert.assertEquals(component.getAftRadius(), component.getThickness(), 0.001);
+        Assert.assertEquals(component.getAftShoulderThickness(), component.getAftShoulderThickness(), 0.001);
+        handler.closeElement("WallThickness", attributes, "100", warnings);
+        handler.endHandler("Transition", attributes, null, warnings);
+        Assert.assertEquals(aft, component.getThickness(), 0.001);
+        handler.closeElement("WallThickness", attributes, "foo", warnings);
+        handler.endHandler("Transition", attributes, null, warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+        
+        handler.closeElement("ConstructionType", attributes, "1", warnings);
+        component.setAftShoulderRadius(1.1d);
+        handler.closeElement("WallThickness", attributes, "-1", warnings);
+        handler.endHandler("Transition", attributes, null, warnings);
+        Assert.assertEquals(0d, component.getThickness(), 0.001);
+        Assert.assertEquals(0d, component.getAftShoulderThickness(), 0.001);
+        handler.closeElement("WallThickness", attributes, "1.1", warnings);
+        handler.endHandler("Transition", attributes, null, warnings);
+        Assert.assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getThickness(), 0.001);
+        Assert.assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderThickness(), 0.001);
+        
+        handler.closeElement("ShoulderLen", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getAftShoulderLength(), 0.001);
+        handler.closeElement("ShoulderLen", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderLength(), 0.001);
+        handler.closeElement("ShoulderLen", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderLength(), 0.001);
+        handler.closeElement("ShoulderLen", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("ShoulderOD", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getAftShoulderRadius(), 0.001);
+        handler.closeElement("ShoulderOD", attributes, "100", warnings);
+        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getAftShoulderRadius(), 0.001);
+        handler.closeElement("ShoulderOD", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        component.setType(Transition.Shape.HAACK);
+        handler.closeElement("ShapeParameter", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getShapeParameter(), 0.001);
+        handler.closeElement("ShapeParameter", attributes, "100", warnings);
+        Assert.assertEquals(Transition.Shape.HAACK.maxParameter(), component.getShapeParameter(), 0.001);
+        handler.closeElement("ShapeParameter", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        Assert.assertEquals("Could not convert ShapeParameter value of foo.  It is expected to be a number.", 
+                     warnings.iterator().next().toString());
+
+        warnings.clear();
+
+        component.setType(Transition.Shape.CONICAL);
+        component.setShapeParameter(0d);
+        handler.closeElement("ShapeParameter", attributes, "100", warnings);
+        Assert.assertEquals(0d, component.getShapeParameter(), 0.001);
+
+        handler.closeElement("FinishCode", attributes, "-1", warnings);
+        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
+        handler.closeElement("FinishCode", attributes, "100", warnings);
+        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
+        handler.closeElement("FinishCode", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Name", attributes, "Test Name", warnings);
+        Assert.assertEquals("Test Name", component.getName());
+        
+        handler.closeElement("Material", attributes, "Some Material", warnings);
+        handler.endHandler("NoseCone", attributes, null, warnings);
+        Assert.assertTrue(component.getMaterial().getName().contains("Some Material"));
+     }
+
+    /**
+     * Method: getComponent()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testGetComponent() throws Exception {
+        Assert.assertTrue(new NoseConeHandler(new Stage(), new WarningSet()).getComponent() instanceof NoseCone);
+    }
+
+    /**
+     * Method: getMaterialType()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testGetMaterialType() throws Exception {
+        Assert.assertEquals(Material.Type.BULK, new NoseConeHandler(new Stage(), new WarningSet()).getMaterialType());
+    }
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/ParachuteHandlerTest.java b/test/net/sf/openrocket/file/rocksim/importt/ParachuteHandlerTest.java
new file mode 100644 (file)
index 0000000..20ab19f
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * ParachuteHandlerTest.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.PlainTextHandler;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.Parachute;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.junit.Assert;
+
+import java.util.HashMap;
+
+/**
+ * ParachuteHandler Tester.
+ */
+public class ParachuteHandlerTest extends RocksimTestBase {
+
+    /**
+     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testOpenElement() throws Exception {
+        Assert.assertEquals(PlainTextHandler.INSTANCE, new ParachuteHandler(new BodyTube(), new WarningSet()).openElement(null, null, null));
+    }
+
+    /**
+     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testCloseElement() throws Exception {
+
+        BodyTube tube = new BodyTube();
+        ParachuteHandler handler = new ParachuteHandler(tube, new WarningSet());
+        Parachute component = (Parachute) getField(handler, "chute");
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        handler.closeElement("Name", attributes, "Test Name", warnings);
+        Assert.assertEquals("Test Name", component.getName());
+
+        handler.closeElement("DragCoefficient", attributes, "0.94", warnings);
+        Assert.assertEquals(0.94d, component.getCD(), 0.001);
+        handler.closeElement("DragCoefficient", attributes, "-0.94", warnings);
+        Assert.assertEquals(-0.94d, component.getCD(), 0.001);
+        handler.closeElement("DragCoefficient", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Dia", attributes, "-1", warnings);
+        Assert.assertEquals(-1d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getDiameter(), 0.001);
+        handler.closeElement("Dia", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getDiameter(), 0.001);
+        handler.closeElement("Dia", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("ShroudLineCount", attributes, "-1", warnings);
+        Assert.assertEquals(0, component.getLineCount());
+        handler.closeElement("ShroudLineCount", attributes, "10", warnings);
+        Assert.assertEquals(10, component.getLineCount());
+        handler.closeElement("ShroudLineCount", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("ShroudLineLen", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getLineLength(), 0.001);
+        handler.closeElement("ShroudLineLen", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLineLength(), 0.001);
+        handler.closeElement("ShroudLineLen", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+    }
+
+    /**
+     * Method: constructor
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testConstructor() throws Exception {
+
+        try {
+            new ParachuteHandler(null, new WarningSet());
+            Assert.fail("Should have thrown IllegalArgumentException");
+        }
+        catch (IllegalArgumentException iae) {
+            //success
+        }
+
+        BodyTube tube = new BodyTube();
+        ParachuteHandler handler = new ParachuteHandler(tube, new WarningSet());
+        Parachute component = (Parachute) getField(handler, "chute");
+        assertContains(component, tube.getChildren());
+    }
+
+    /**
+     * Method: setRelativePosition(RocketComponent.Position position)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testSetRelativePosition() throws Exception {
+        BodyTube tube = new BodyTube();
+        ParachuteHandler handler = new ParachuteHandler(tube, new WarningSet());
+        Parachute component = (Parachute) getField(handler, "chute");
+        handler.setRelativePosition(RocketComponent.Position.ABSOLUTE);
+        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
+    }
+
+    /**
+     * Method: getComponent()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetComponent() throws Exception {
+        Assert.assertTrue(new ParachuteHandler(new BodyTube(), new WarningSet()).getComponent() instanceof Parachute);
+    }
+
+    /**
+     * Method: getMaterialType()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetMaterialType() throws Exception {
+        Assert.assertEquals(Material.Type.SURFACE, new ParachuteHandler(new BodyTube(), new WarningSet()).getMaterialType());
+    }
+
+    /**
+     * Method: endHandler()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testEndHandler() throws Exception {
+        BodyTube tube = new BodyTube();
+        ParachuteHandler handler = new ParachuteHandler(tube, new WarningSet());
+        Parachute component = (Parachute) getField(handler, "chute");
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        handler.closeElement("Xb", attributes, "-10", warnings);
+        handler.closeElement("LocationMode", attributes, "1", warnings);
+        handler.endHandler("Parachute", attributes, null, warnings);
+        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
+        Assert.assertEquals(component.getPositionValue(), -10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, 0.001);
+
+        handler.closeElement("Xb", attributes, "-10", warnings);
+        handler.closeElement("LocationMode", attributes, "2", warnings);
+        handler.endHandler("Parachute", attributes, null, warnings);
+        Assert.assertEquals(RocketComponent.Position.BOTTOM, component.getRelativePosition());
+        Assert.assertEquals(component.getPositionValue(), 10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, 0.001);
+    }
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/PodFins.rkt b/test/net/sf/openrocket/file/rocksim/importt/PodFins.rkt
new file mode 100644 (file)
index 0000000..a137008
--- /dev/null
@@ -0,0 +1,605 @@
+<RockSimDocument>
+  <FileVersion>4</FileVersion>
+  <DesignInformation>
+    <RocketDesign>
+      <CalculateCD>1</CalculateCD>
+      <ProCalculateCD>1</ProCalculateCD>
+      <ProCalculateCN>1</ProCalculateCN>
+      <FixedCd>0.75</FixedCd>
+      <FixedCd2>0.8</FixedCd2>
+      <FixedCd3>0.81</FixedCd3>
+      <FixedCd2Alone>0.95</FixedCd2Alone>
+      <FixedCd3Alone>0.95</FixedCd3Alone>
+      <StageCount>1</StageCount>
+      <Stage3Mass>0.</Stage3Mass>
+      <Stage2Mass>0.</Stage2Mass>
+      <Stage1Mass>0.</Stage1Mass>
+      <Stage321CG>0.</Stage321CG>
+      <Stage32CG>0.</Stage32CG>
+      <Stage3CG>0.</Stage3CG>
+      <Stage2CGAlone>0.</Stage2CGAlone>
+      <Stage1CGAlone>0.</Stage1CGAlone>
+      <CPCalcFlags>1</CPCalcFlags>
+      <LaunchGuideLength>914.4</LaunchGuideLength>
+      <UseKnownMass>0</UseKnownMass>
+      <DefaultFinish>0</DefaultFinish>
+      <FinishMedium>0</FinishMedium>
+      <FinishCoatCount>1</FinishCoatCount>
+      <GlueType>0</GlueType>
+      <CPSimFlags>1</CPSimFlags>
+      <LastSerialNumber>7</LastSerialNumber>
+      <DisplayFlags>1</DisplayFlags>
+      <MetricsFlags>0</MetricsFlags>
+      <BarromanXN>0,567.719,0,0</BarromanXN>
+      <BarrowmanCNa>0,19.2193,0,0</BarrowmanCNa>
+      <RockSimXN>0,571.25,0,0</RockSimXN>
+      <RockSimCNa>0,28.2677,0,0</RockSimCNa>
+      <RockSimCNa90>0,0,0,0</RockSimCNa90>
+      <RockSimXN90>0,0,0,0</RockSimXN90>
+      <ViewType>0</ViewType>
+      <ViewStageCount>1</ViewStageCount>
+      <ViewTypeEdit>0</ViewTypeEdit>
+      <ViewStageCountEdit>1</ViewStageCountEdit>
+      <ZoomFactor>0.</ZoomFactor>
+      <ZoomFactorEdit>0.</ZoomFactorEdit>
+      <ScrollPosX>0</ScrollPosX>
+      <ScrollPosY>0</ScrollPosY>
+      <ScrollPosXEdit>0</ScrollPosXEdit>
+      <ScrollPosYEdit>0</ScrollPosYEdit>
+      <ThreeDFlags>0</ThreeDFlags>
+      <ThreeDFlagsEdit>0</ThreeDFlagsEdit>
+      <UseModelSprite>0</UseModelSprite>
+      <StaticMarginRef>0</StaticMarginRef>
+      <UserRefDiameter>0.</UserRefDiameter>
+      <SideMarkerHeight>10.</SideMarkerHeight>
+      <SideDimensionHeight>10.</SideDimensionHeight>
+      <BaseMarkerHeight>10.</BaseMarkerHeight>
+      <BaseDimensionHeight>10.</BaseDimensionHeight>
+      <ShowGlideCP>0</ShowGlideCP>
+      <ShowGridTypeSide>0</ShowGridTypeSide>
+      <ShowGridTypeBase>0</ShowGridTypeBase>
+      <GridSpacing>10.</GridSpacing>
+      <GridOpacity>0.15</GridOpacity>
+      <GridColor>black</GridColor>
+      <MaxDiaWithFins>259.588</MaxDiaWithFins>
+      <MaxDiaWithoutFins>56.388</MaxDiaWithoutFins>
+      <MaxLenWithFins>717.499</MaxLenWithFins>
+      <MaxLenWithoutFins>717.499</MaxLenWithoutFins>
+      <MinXExtent>0.</MinXExtent>
+      <MaxXExtent>717.499</MaxXExtent>
+      <CalculatedMaxStageDia>0,56.388,0,0</CalculatedMaxStageDia>
+      <CalculatedStageLen>0,717.499,0,0</CalculatedStageLen>
+      <Cd3>
+        <PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+        <X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+        <A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+        <B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+        <C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+      </PolyData>
+    </Cd3>
+    <Cd32>
+      <PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+      <X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+      <A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+      <B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+      <C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+    </PolyData>
+  </Cd32>
+  <Cd321>
+    <PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+    <X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+    <A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+    <B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+    <C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+  </PolyData>
+</Cd321>
+<Cb3>
+  <PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+  <X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+  <A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+  <B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+  <C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb3>
+<Cb32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb32>
+<Cb321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb321>
+<CNa3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa3>
+<CNa32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa32>
+<CNa321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa321>
+<CP3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP3>
+<CP32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP32>
+<CP321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP321>
+<SimulationEventList>
+</SimulationEventList>
+<Stage3Parts>
+<NoseCone>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>24.0999</KnownMass>
+<Density>1049.21</Density>
+<Material>Polystyrene PS</Material>
+<Name>Nose cone</Name>
+<KnownCG>65.3999</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>94.7384</CalcMass>
+<CalcCG>208.434</CalcCG>
+<WettedSurface>0.0323955</WettedSurface>
+<PaintedSurface>0.0323955</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>19470</PartNo>
+<PartDesc>PNC-70A</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>1</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>2.</BarrowmanCNa>
+<BarrowmanXN>0.126958</BarrowmanXN>
+<RockSimCNa>2.</RockSimCNa>
+<RockSimXN>0.126958</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>0.</Station>
+<Len>272.999</Len>
+<BaseDia>56.2991</BaseDia>
+<FinishCode>0</FinishCode>
+<ShapeCode>1</ShapeCode>
+<ConstructionType>1</ConstructionType>
+<ShoulderLen>58.3997</ShoulderLen>
+<WallThickness>2.159</WallThickness>
+<ShapeParameter>0.</ShapeParameter>
+<ShoulderOD>53.1012</ShoulderOD>
+<BaseExtensionLen>0.</BaseExtensionLen>
+<CoreDia>0.</CoreDia>
+<CoreLen>0.</CoreLen>
+<AttachedParts>
+</AttachedParts>
+</NoseCone>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>44.4492</CalcMass>
+<CalcCG>222.25</CalcCG>
+<WettedSurface>0.0787423</WettedSurface>
+<PaintedSurface>0.0787423</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>Estes</PartNo>
+<PartDesc>BT-70</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>2</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>272.999</Station>
+<OD>56.388</OD>
+<ID>55.372</ID>
+<Len>444.5</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<FinSet>
+<PartMfg>Public Missiles</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1905.24</Density>
+<Material>G10 fiberglass</Material>
+<Name>Fin set</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>273.05</Xb>
+<CalcMass>75.5033</CalcMass>
+<CalcCG>110.067</CalcCG>
+<WettedSurface>0.0167742</WettedSurface>
+<PaintedSurface>0.0503225</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>FIN-A-04</PartNo>
+<PartDesc>Fins</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>4</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>16.5474</BarrowmanCNa>
+<BarrowmanXN>0.628599</BarrowmanXN>
+<RockSimCNa>23.7789</RockSimCNa>
+<RockSimXN>0.628599</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>546.049</Station>
+<FinCount>3</FinCount>
+<RootChord>165.1</RootChord>
+<TipChord>0.</TipChord>
+<SemiSpan>101.6</SemiSpan>
+<MidChordLen>130.909</MidChordLen>
+<SweepDistance>165.1</SweepDistance>
+<Thickness>1.5748</Thickness>
+<ShapeCode>0</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>1</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>1.02001</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>62.0607</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>13.7288</RockSimCNaPerFin>
+<TaperRatio>0.</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+<BodyTube>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>107.95</Xb>
+<CalcMass>1.7435</CalcMass>
+<CalcCG>55.5625</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>10062</PartNo>
+<PartDesc>13 mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>5</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>380.949</Station>
+<OD>13.8176</OD>
+<ID>13.1572</ID>
+<Len>111.125</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>13.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<FinSet>
+<PartMfg>Public Missiles</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1905.24</Density>
+<Material>G10 fiberglass</Material>
+<Name>Fin set</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>5.53666</CalcMass>
+<CalcCG>44.5707</CalcCG>
+<WettedSurface>0.00365927</WettedSurface>
+<PaintedSurface>0.00365927</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>FIN-A-06</PartNo>
+<PartDesc>Fins</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>7</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.671866</BarrowmanCNa>
+<BarrowmanXN>0.380349</BarrowmanXN>
+<RockSimCNa>2.4888</RockSimCNa>
+<RockSimXN>0.380349</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>349.199</Station>
+<FinCount>1</FinCount>
+<RootChord>66.675</RootChord>
+<TipChord>38.1</TipChord>
+<SemiSpan>34.925</SemiSpan>
+<MidChordLen>42.7843</MidChordLen>
+<SweepDistance>39.0017</SweepDistance>
+<Thickness>1.5875</Thickness>
+<ShapeCode>0</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>0</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.366519</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>44.069</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>2.87382</RockSimCNaPerFin>
+<TaperRatio>0.571429</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+</AttachedParts>
+</BodyTube>
+<ExternalPod>
+<PartMfg>Custom</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>0.</Density>
+<Name>Pod</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>76.2</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>0.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>28.194</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>6</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>349.199</Station>
+<Detachable>1</Detachable>
+<AutoCalcRadialDistance>1</AutoCalcRadialDistance>
+<AutoCalcRadialAngle>1</AutoCalcRadialAngle>
+<AttachedParts>
+<FinSet>
+<PartMfg>Public Missiles</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1905.24</Density>
+<Material>G10 fiberglass</Material>
+<Name>Fin set</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>5.53666</CalcMass>
+<CalcCG>44.5707</CalcCG>
+<WettedSurface>0.00365927</WettedSurface>
+<PaintedSurface>0.00365927</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>FIN-A-06</PartNo>
+<PartDesc>Fins</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>7</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.671866</BarrowmanCNa>
+<BarrowmanXN>0.380349</BarrowmanXN>
+<RockSimCNa>2.4888</RockSimCNa>
+<RockSimXN>0.380349</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>349.199</Station>
+<FinCount>1</FinCount>
+<RootChord>66.675</RootChord>
+<TipChord>38.1</TipChord>
+<SemiSpan>34.925</SemiSpan>
+<MidChordLen>42.7843</MidChordLen>
+<SweepDistance>39.0017</SweepDistance>
+<Thickness>1.5875</Thickness>
+<ShapeCode>0</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>0</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.366519</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>44.069</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>2.87382</RockSimCNaPerFin>
+<TaperRatio>0.571429</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+</AttachedParts>
+</ExternalPod>
+</AttachedParts>
+</BodyTube>
+</Stage3Parts>
+<Stage2Parts>
+</Stage2Parts>
+<Stage1Parts>
+</Stage1Parts>
+<SideViewDims>
+</SideViewDims>
+<BaseViewDims>
+</BaseViewDims>
+<VertViewDims>
+</VertViewDims>
+</RocketDesign>
+</DesignInformation>
+<SimulationResultsList>
+</SimulationResultsList>
+</RockSimDocument>
diff --git a/test/net/sf/openrocket/file/rocksim/importt/RingHandlerTest.java b/test/net/sf/openrocket/file/rocksim/importt/RingHandlerTest.java
new file mode 100644 (file)
index 0000000..af64a82
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * RingHandlerTest.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.PlainTextHandler;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.Bulkhead;
+import net.sf.openrocket.rocketcomponent.CenteringRing;
+import net.sf.openrocket.rocketcomponent.EngineBlock;
+import net.sf.openrocket.rocketcomponent.RingComponent;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.TubeCoupler;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+
+/**
+ * RingHandler Tester.
+ */
+public class RingHandlerTest extends RocksimTestBase {
+
+    /**
+     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testOpenElement() throws Exception {
+        Assert.assertEquals(PlainTextHandler.INSTANCE, new RingHandler(new BodyTube(), new WarningSet()).openElement(null, null, null));
+    }
+
+    /**
+     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testCloseElement() throws Exception {
+
+        BodyTube tube = new BodyTube();
+        RingHandler handler = new RingHandler(tube, new WarningSet());
+        CenteringRing component = (CenteringRing) getField(handler, "ring");
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        handler.closeElement("OD", attributes, "0", warnings);
+        Assert.assertEquals(0d, component.getOuterRadius(), 0.001);
+        handler.closeElement("OD", attributes, "75", warnings);
+        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getOuterRadius(), 0.001);
+        handler.closeElement("OD", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("ID", attributes, "0", warnings);
+        Assert.assertEquals(0d, component.getInnerRadius(), 0.001);
+        handler.closeElement("ID", attributes, "75", warnings);
+        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius(), 0.001);
+        handler.closeElement("ID", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Len", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Name", attributes, "Test Name", warnings);
+        Assert.assertEquals("Test Name", component.getName());
+    }
+
+    /**
+     * Test a bulkhead.
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testBulkhead() throws Exception {
+        BodyTube tube = new BodyTube();
+        RingHandler handler = new RingHandler(tube, new WarningSet());
+        CenteringRing component = (CenteringRing) getField(handler, "ring");
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        handler.closeElement("OD", attributes, "75", warnings);
+        handler.closeElement("ID", attributes, "0", warnings);
+        handler.closeElement("Len", attributes, "10", warnings);
+        handler.closeElement("Name", attributes, "Test Name", warnings);
+        handler.closeElement("KnownMass", attributes, "109.9", warnings);
+        handler.closeElement("UsageCode", attributes, "1", warnings);
+        handler.closeElement("UseKnownCG", attributes, "1", warnings);
+        handler.endHandler("", attributes, "", warnings);
+        
+        Assert.assertEquals(1, tube.getChildren().size());
+        RingComponent child = (RingComponent)tube.getChild(0);
+
+        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getOuterRadius(), 0.001);
+        Assert.assertEquals(0d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getInnerRadius(), 0.001);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, child.getLength(), 0.001);
+        Assert.assertEquals("Test Name", child.getName());
+        Assert.assertEquals(109.9/1000, child.getMass(), 0.001);
+        Assert.assertEquals(0, child.getPositionValue(), 0.0);
+        Assert.assertEquals(RocketComponent.Position.TOP, child.getRelativePosition());
+        Assert.assertTrue(child instanceof Bulkhead);
+
+    }
+    
+    /**
+     * Test a tube coupler.
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testTubeCoupler() throws Exception {
+        BodyTube tube = new BodyTube();
+        RingHandler handler = new RingHandler(tube, new WarningSet());
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        handler.closeElement("OD", attributes, "75", warnings);
+        handler.closeElement("ID", attributes, "70", warnings);
+        handler.closeElement("Len", attributes, "10", warnings);
+        handler.closeElement("Name", attributes, "Test Name", warnings);
+        handler.closeElement("KnownMass", attributes, "109.9", warnings);
+        handler.closeElement("UsageCode", attributes, "4", warnings);
+        handler.closeElement("UseKnownCG", attributes, "1", warnings);
+        handler.endHandler("", attributes, "", warnings);
+
+        Assert.assertEquals(1, tube.getChildren().size());
+        RingComponent child = (RingComponent)tube.getChild(0);
+        Assert.assertTrue(child instanceof TubeCoupler);
+
+        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getOuterRadius(), 0.001);
+        Assert.assertEquals(70d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getInnerRadius(), 0.001);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, child.getLength(), 0.001);
+        Assert.assertEquals("Test Name", child.getName());
+        Assert.assertEquals(109.9/1000, child.getMass(), 0.001);
+        Assert.assertEquals(0, child.getPositionValue(), 0.0);
+        Assert.assertEquals(RocketComponent.Position.TOP, child.getRelativePosition());
+    }
+
+    /**
+     * Test a engine block.
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testEngineBlock() throws Exception {
+        BodyTube tube = new BodyTube();
+        RingHandler handler = new RingHandler(tube, new WarningSet());
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        handler.closeElement("OD", attributes, "75", warnings);
+        handler.closeElement("ID", attributes, "70", warnings);
+        handler.closeElement("Len", attributes, "10", warnings);
+        handler.closeElement("Name", attributes, "Test Name", warnings);
+        handler.closeElement("KnownMass", attributes, "109.9", warnings);
+        handler.closeElement("UsageCode", attributes, "2", warnings);
+        handler.closeElement("KnownCG", attributes, "4", warnings);
+        handler.closeElement("UseKnownCG", attributes, "1", warnings);
+        handler.endHandler("", attributes, "", warnings);
+
+        Assert.assertEquals(1, tube.getChildren().size());
+        RingComponent child = (RingComponent)tube.getChild(0);
+        Assert.assertTrue(child instanceof EngineBlock);
+
+        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getOuterRadius(), 0.001);
+        Assert.assertEquals(70d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getInnerRadius(), 0.001);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, child.getLength(), 0.001);
+        Assert.assertEquals("Test Name", child.getName());
+        Assert.assertEquals(109.9/1000, child.getMass(), 0.001);
+        Assert.assertEquals(0, child.getPositionValue(), 0.0);
+        Assert.assertEquals(RocketComponent.Position.TOP, child.getRelativePosition());
+        Assert.assertEquals(4d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, child.getCG().x, 0.000001);
+        
+    }
+
+    /**
+     * Test a centering ring
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testRing() throws Exception {
+        BodyTube tube = new BodyTube();
+        RingHandler handler = new RingHandler(tube, new WarningSet());
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        handler.closeElement("OD", attributes, "75", warnings);
+        handler.closeElement("ID", attributes, "0", warnings);
+        handler.closeElement("Len", attributes, "10", warnings);
+        handler.closeElement("Name", attributes, "Test Name", warnings);
+        handler.closeElement("KnownMass", attributes, "109.9", warnings);
+        handler.closeElement("UsageCode", attributes, "0", warnings);
+        handler.closeElement("UseKnownCG", attributes, "1", warnings);
+        handler.endHandler("", attributes, "", warnings);
+
+        Assert.assertEquals(1, tube.getChildren().size());
+        RingComponent child = (RingComponent)tube.getChild(0);
+
+        Assert.assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getOuterRadius(), 0.001);
+        Assert.assertEquals(0d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, child.getInnerRadius(), 0.001);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, child.getLength(), 0.001);
+        Assert.assertEquals("Test Name", child.getName());
+        Assert.assertEquals(109.9/1000, child.getMass(), 0.001);
+        Assert.assertEquals(0, child.getPositionValue(), 0.0);
+        Assert.assertEquals(RocketComponent.Position.TOP, child.getRelativePosition());
+        Assert.assertTrue(child instanceof CenteringRing);
+    }
+
+    /**
+     * Method: constructor
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testConstructor() throws Exception {
+
+        try {
+            new RingHandler(null, new WarningSet());
+            Assert.fail("Should have thrown IllegalArgumentException");
+        }
+        catch (IllegalArgumentException iae) {
+            //success
+        }
+
+        BodyTube tube = new BodyTube();
+        RingHandler handler = new RingHandler(tube, new WarningSet());
+        CenteringRing component = (CenteringRing) getField(handler, "ring");
+    }
+
+    /**
+     * Method: setRelativePosition(RocketComponent.Position position)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testSetRelativePosition() throws Exception {
+        BodyTube tube = new BodyTube();
+        RingHandler handler = new RingHandler(tube, new WarningSet());
+        CenteringRing component = (CenteringRing) getField(handler, "ring");
+        handler.setRelativePosition(RocketComponent.Position.ABSOLUTE);
+        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
+    }
+
+    
+    /**
+     * Method: getComponent()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetComponent() throws Exception {
+        Assert.assertTrue(new RingHandler(new BodyTube(), new WarningSet()).getComponent() instanceof CenteringRing);
+    }
+
+    /**
+     * Method: getMaterialType()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetMaterialType() throws Exception {
+        Assert.assertEquals(Material.Type.BULK, new RingHandler(new BodyTube(), new WarningSet()).getMaterialType());
+    }
+
+
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/RocksimContentHandlerTest.java b/test/net/sf/openrocket/file/rocksim/importt/RocksimContentHandlerTest.java
new file mode 100644 (file)
index 0000000..0eb1d62
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * RocksimContentHandlerTest.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import org.junit.Assert;
+
+/**
+ * RocksimContentHandler Tester.
+ *
+ */
+public class RocksimContentHandlerTest {
+
+    /**
+     *
+     * Method: getDocument()
+     *
+     * @throws Exception  thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetDocument() throws Exception {
+        RocksimContentHandler handler = new RocksimContentHandler();
+        Assert.assertNotNull(handler.getDocument());
+    }
+
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/RocksimLoaderTest.java b/test/net/sf/openrocket/file/rocksim/importt/RocksimLoaderTest.java
new file mode 100644 (file)
index 0000000..92a0eea
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * RocksimLoaderTest.java
+ *
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.file.RocketLoadException;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.LaunchLug;
+import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.rocketcomponent.Stage;
+import org.junit.Assert;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * RocksimLoader Tester.
+ */
+public class RocksimLoaderTest {
+
+    /**
+     * Test a bug reported via automated bug report.  I have been unable to reproduce this bug
+     * (hanging finset off of an inner body tube) when creating a Rocksim file using Rocksim.  The bug
+     * is reproducible when manually modifying the Rocksim file, which is what is tested here.
+     */
+    @org.junit.Test
+    public void testFinsOnInnerTube() throws Exception {
+        RocksimLoader loader = new RocksimLoader();
+        InputStream stream = this.getClass().getResourceAsStream("PodFins.rkt");
+        Assert.assertNotNull("Could not open PodFins.rkt", stream);
+        try {
+            OpenRocketDocument doc = loader.loadFromStream(new BufferedInputStream(stream));
+            Assert.assertNotNull(doc);
+            Rocket rocket = doc.getRocket();
+            Assert.assertNotNull(rocket);
+        } catch (IllegalStateException ise) {
+            Assert.fail(ise.getMessage());
+        }
+        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 = loader.loadFromStream(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(1, loader.getWarnings().size());
+        Assert.assertEquals(3, rocket.getStageCount());
+        Stage stage1 = (Stage) rocket.getChild(0);
+        Assert.assertFalse(stage1.isMassOverridden());
+        Assert.assertFalse(stage1.isCGOverridden());
+        Stage stage2 = (Stage) rocket.getChild(1);
+        Assert.assertFalse(stage2.isMassOverridden());
+        Assert.assertFalse(stage2.isCGOverridden());
+        Stage stage3 = (Stage) 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 = loader.loadFromStream(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 = (Stage) rocket.getChild(0);
+        stage2 = (Stage) rocket.getChild(1);
+        stage3 = (Stage) 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(4, 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.getRadialDirection(), 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 loadRocksimRocket(RocksimLoader theLoader) throws IOException, RocketLoadException {
+        InputStream stream = RocksimLoaderTest.class.getResourceAsStream("rocksimTestRocket1.rkt");
+        try {
+            Assert.assertNotNull("Could not open rocksimTestRocket1.rkt", stream);
+            return theLoader.loadFromStream(new BufferedInputStream(stream));
+        } finally {
+            stream.close();
+        }
+    }
+
+    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);
+            return theLoader.loadFromStream(new BufferedInputStream(stream));
+        } finally {
+            stream.close();
+        }
+    }
+
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/RocksimTestBase.java b/test/net/sf/openrocket/file/rocksim/importt/RocksimTestBase.java
new file mode 100644 (file)
index 0000000..14b2494
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * BaseRocksimTest.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.gui.util.SwingPreferences;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.startup.Application;
+import org.junit.Assert;
+import org.junit.Before;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+/**
+ * A base class for the Rocksim tests.  Includes code from the junitx.addons project.
+ */
+public abstract class RocksimTestBase {
+       
+       /* (non-Javadoc)
+        * @see junit.framework.TestCase#setUp()
+        */
+       @Before
+    public void setUp() throws Exception {
+        Application.setPreferences( new SwingPreferences() );
+       }
+
+
+       public void assertContains(RocketComponent child, List<RocketComponent> components) {
+               Assert.assertTrue("Components did not contain child", components.contains(child));
+       }
+       
+       /**
+        * Returns the value of the field on the specified object.  The name
+        * parameter is a <code>String</code> specifying the simple name of the
+        * desired field.<p>
+        *
+        * The object is first searched for any matching field.  If no matching
+        * field is found, the superclasses are recursively searched.
+        *
+        * @exception NoSuchFieldException if a field with the specified name is
+        * not found.
+        */
+       public static Object getField(Object object,
+                                                                       String name)
+                       throws NoSuchFieldException {
+               if (object == null) {
+                       throw new IllegalArgumentException("Invalid null object argument");
+               }
+               for (Class cls = object.getClass(); cls != null; cls = cls.getSuperclass()) {
+                       try {
+                               Field field = cls.getDeclaredField(name);
+                               field.setAccessible(true);
+                               return field.get(object);
+                       } catch (Exception ex) {
+                               /* in case of an exception, we will throw a new
+                                * NoSuchFieldException object */
+                               ;
+                       }
+               }
+               throw new NoSuchFieldException("Could get value for field " +
+                               object.getClass().getName() + "." + name);
+       }
+       
+       /**
+        * Returns the value of the field on the specified class.  The name
+        * parameter is a <code>String</code> specifying the simple name of the
+        * desired field.<p>
+        *
+        * The class is first searched for any matching field.  If no matching
+        * field is found, the superclasses are recursively searched.
+        *
+        * @exception NoSuchFieldException if a field with the specified name is
+        * not found.
+        */
+       public static Object getField(Class cls,
+                                                                       String name)
+                       throws NoSuchFieldException {
+               if (cls == null) {
+                       throw new IllegalArgumentException("Invalid null cls argument");
+               }
+               Class base = cls;
+               while (base != null) {
+                       try {
+                               Field field = base.getDeclaredField(name);
+                               field.setAccessible(true);
+                               return field.get(base);
+                       } catch (Exception ex) {
+                               /* in case of an exception, we will throw a new
+                                * NoSuchFieldException object */
+                               ;
+                       }
+                       base = base.getSuperclass();
+               }
+               throw new NoSuchFieldException("Could get value for static field " +
+                               cls.getName() + "." + name);
+       }
+       
+
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/StreamerHandlerTest.java b/test/net/sf/openrocket/file/rocksim/importt/StreamerHandlerTest.java
new file mode 100644 (file)
index 0000000..a1dea0a
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * StreamerHandlerTest.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.PlainTextHandler;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.Streamer;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+
+/**
+ * StreamerHandler Tester.
+ */
+public class StreamerHandlerTest extends RocksimTestBase {
+
+    /**
+     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testOpenElement() throws Exception {
+        Assert.assertEquals(PlainTextHandler.INSTANCE, new StreamerHandler(new BodyTube(), new WarningSet()).openElement(null, null, null));
+    }
+
+    /**
+     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testCloseElement() throws Exception {
+
+        BodyTube tube = new BodyTube();
+        StreamerHandler handler = new StreamerHandler(tube, new WarningSet());
+        Streamer component = (Streamer) getField(handler, "streamer");
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        handler.closeElement("Width", attributes, "0", warnings);
+        Assert.assertEquals(0d/ RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getStripWidth(), 0.001);
+        handler.closeElement("Width", attributes, "10", warnings);
+        Assert.assertEquals(10d/ RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getStripWidth(), 0.001);
+        handler.closeElement("Width", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Len", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getStripLength(), 0.001);
+        handler.closeElement("Len", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getStripLength(), 0.001);
+        handler.closeElement("Len", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getStripLength(), 0.001);
+        handler.closeElement("Len", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Name", attributes, "Test Name", warnings);
+        Assert.assertEquals("Test Name", component.getName());
+
+        handler.closeElement("DragCoefficient", attributes, "0.94", warnings);
+        Assert.assertEquals(0.94d, component.getCD(), 0.001);
+        handler.closeElement("DragCoefficient", attributes, "-0.94", warnings);
+        Assert.assertEquals(-0.94d, component.getCD(), 0.001);
+        handler.closeElement("DragCoefficient", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+    }
+
+    /**
+     * Method: constructor
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testConstructor() throws Exception {
+
+        try {
+            new StreamerHandler(null, new WarningSet());
+            Assert.fail("Should have thrown IllegalArgumentException");
+        }
+        catch (IllegalArgumentException iae) {
+            //success
+        }
+
+        BodyTube tube = new BodyTube();
+        StreamerHandler handler = new StreamerHandler(tube, new WarningSet());
+        Streamer component = (Streamer) getField(handler, "streamer");
+        assertContains(component, tube.getChildren());
+    }
+
+    /**
+     * Method: setRelativePosition(RocketComponent.Position position)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testSetRelativePosition() throws Exception {
+        BodyTube tube = new BodyTube();
+        StreamerHandler handler = new StreamerHandler(tube, new WarningSet());
+        Streamer component = (Streamer) getField(handler, "streamer");
+        handler.setRelativePosition(RocketComponent.Position.ABSOLUTE);
+        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
+    }
+
+    /**
+     * Method: getComponent()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testGetComponent() throws Exception {
+        Assert.assertTrue(new StreamerHandler(new BodyTube(), new WarningSet()).getComponent() instanceof Streamer);
+    }
+
+    /**
+     * Method: getMaterialType()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testGetMaterialType() throws Exception {
+        Assert.assertEquals(Material.Type.SURFACE, new StreamerHandler(new BodyTube(), new WarningSet()).getMaterialType());
+    }
+
+    /**
+     * Method: endHandler()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @Test
+    public void testEndHandler() throws Exception {
+        BodyTube tube = new BodyTube();
+        StreamerHandler handler = new StreamerHandler(tube, new WarningSet());
+        Streamer component = (Streamer) getField(handler, "streamer");
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        handler.closeElement("Xb", attributes, "-10", warnings);
+        handler.closeElement("LocationMode", attributes, "1", warnings);
+        handler.endHandler("Streamer", attributes, null, warnings);
+        Assert.assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition());
+        Assert.assertEquals(component.getPositionValue(), -10d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, 0.001);
+
+        handler.closeElement("Xb", attributes, "-10", warnings);
+        handler.closeElement("LocationMode", attributes, "2", warnings);
+        handler.endHandler("Streamer", attributes, null, warnings);
+        Assert.assertEquals(RocketComponent.Position.BOTTOM, component.getRelativePosition());
+        Assert.assertEquals(component.getPositionValue(), 10d/ RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, 0.001);
+
+        handler.closeElement("Thickness", attributes, "0.02", warnings);
+        Assert.assertEquals(0.01848, handler.computeDensity(RocksimDensityType.ROCKSIM_BULK, 924d), 0.001);
+
+        //Test Density Type 0 (Bulk)
+        handler.closeElement("Density", attributes, "924.0", warnings);
+        handler.closeElement("DensityType", attributes, "0", warnings);
+        handler.endHandler("Streamer", attributes, null, warnings);
+        Assert.assertEquals(0.01848d, component.getMaterial().getDensity(), 0.001);
+
+        //Test Density Type 1 (Surface)
+        handler.closeElement("Density", attributes, "0.006685", warnings);
+        handler.closeElement("DensityType", attributes, "1", warnings);
+        handler.endHandler("Streamer", attributes, null, warnings);
+        Assert.assertTrue(Math.abs(0.06685d - component.getMaterial().getDensity()) < 0.00001);
+
+        //Test Density Type 2 (Line)
+        handler.closeElement("Density", attributes, "0.223225", warnings);
+        handler.closeElement("DensityType", attributes, "2", warnings);
+        handler.closeElement("Len", attributes, "3810.", warnings);
+        handler.closeElement("Width", attributes, "203.2", warnings);
+        handler.endHandler("Streamer", attributes, null, warnings);
+
+        Assert.assertEquals(1.728190092, component.getMass(), 0.001);
+
+    }
+
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/TransitionHandlerTest.java b/test/net/sf/openrocket/file/rocksim/importt/TransitionHandlerTest.java
new file mode 100644 (file)
index 0000000..cea3a07
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * TransitionHandlerTest.java
+ */
+package net.sf.openrocket.file.rocksim.importt;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.PlainTextHandler;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.ExternalComponent;
+import net.sf.openrocket.rocketcomponent.Stage;
+import net.sf.openrocket.rocketcomponent.Transition;
+import org.junit.Assert;
+
+import java.util.HashMap;
+
+/**
+ * TransitionHandler Tester.
+ */
+public class TransitionHandlerTest extends RocksimTestBase {
+
+    /**
+     * Method: constructor
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testConstructor() throws Exception {
+
+        try {
+            new TransitionHandler(null, new WarningSet());
+            Assert.fail("Should have thrown IllegalArgumentException");
+        }
+        catch (IllegalArgumentException iae) {
+            //success
+        }
+
+        Stage stage = new Stage();
+        TransitionHandler handler = new TransitionHandler(stage, new WarningSet());
+        Transition component = (Transition) getField(handler, "transition");
+        assertContains(component, stage.getChildren());
+    }
+
+    /**
+     * Method: openElement(String element, HashMap<String, String> attributes, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testOpenElement() throws Exception {
+        Assert.assertEquals(PlainTextHandler.INSTANCE, new TransitionHandler(new Stage(), new WarningSet()).openElement(null, null, null));
+    }
+
+    /**
+     * Method: closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testCloseElement() throws Exception {
+
+        Stage stage = new Stage();
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        WarningSet warnings = new WarningSet();
+
+        TransitionHandler handler = new TransitionHandler(stage, new WarningSet());
+        Transition component = (Transition) getField(handler, "transition");
+
+        handler.closeElement("ShapeCode", attributes, "0", warnings);
+        Assert.assertEquals(Transition.Shape.CONICAL, component.getType());
+        handler.closeElement("ShapeCode", attributes, "1", warnings);
+        Assert.assertEquals(Transition.Shape.OGIVE, component.getType());
+        handler.closeElement("ShapeCode", attributes, "17", warnings);
+        Assert.assertEquals(RocksimNoseConeCode.PARABOLIC.asOpenRocket(), component.getType());  //test of default
+        handler.closeElement("ShapeCode", attributes, "foo", warnings);
+        Assert.assertNotNull(component.getType());
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Len", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength(), 0.001);
+        handler.closeElement("Len", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("FrontDia", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getForeRadius(), 0.001);
+        handler.closeElement("FrontDia", attributes, "100", warnings);
+        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getForeRadius(), 0.001);
+        handler.closeElement("FrontDia", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("RearDia", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getAftRadius(), 0.001);
+        handler.closeElement("RearDia", attributes, "100", warnings);
+        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getAftRadius(), 0.001);
+        handler.closeElement("RearDia", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        final double aft = 100d;
+        component.setAftRadius(aft);
+        
+        handler.closeElement("ConstructionType", attributes, "0", warnings);
+        component.setAftShoulderRadius(1.1d);
+        component.setForeShoulderRadius(1.1d);
+        handler.closeElement("WallThickness", attributes, "-1", warnings);
+        handler.endHandler("Transition", attributes, null, warnings);
+        Assert.assertEquals(component.getAftRadius(), component.getThickness(), 0.001);
+        Assert.assertEquals(component.getAftShoulderThickness(), component.getAftShoulderThickness(), 0.001);
+        Assert.assertEquals(component.getForeShoulderThickness(), component.getForeShoulderThickness(), 0.001);
+        handler.closeElement("WallThickness", attributes, "100", warnings);
+        handler.endHandler("Transition", attributes, null, warnings);
+        Assert.assertEquals(aft, component.getThickness(), 0.001);
+        handler.closeElement("WallThickness", attributes, "foo", warnings);
+        handler.endHandler("Transition", attributes, null, warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+        
+        handler.closeElement("ConstructionType", attributes, "1", warnings);
+        component.setAftShoulderRadius(1.1d);
+        component.setForeShoulderRadius(1.1d);
+        handler.closeElement("WallThickness", attributes, "-1", warnings);
+        handler.endHandler("Transition", attributes, null, warnings);
+        Assert.assertEquals(0d, component.getThickness(), 0.001);
+        Assert.assertEquals(0d, component.getAftShoulderThickness(), 0.001);
+        Assert.assertEquals(0d, component.getForeShoulderThickness(), 0.001);
+        handler.closeElement("WallThickness", attributes, "1.1", warnings);
+        handler.endHandler("Transition", attributes, null, warnings);
+        Assert.assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getThickness(), 0.001);
+        Assert.assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderThickness(), 0.001);
+        Assert.assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getForeShoulderThickness(), 0.001);
+        
+
+        handler.closeElement("FrontShoulderLen", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getForeShoulderLength(), 0.001);
+        handler.closeElement("FrontShoulderLen", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getForeShoulderLength(), 0.001);
+        handler.closeElement("FrontShoulderLen", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getForeShoulderLength(), 0.001);
+        handler.closeElement("FrontShoulderLen", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("RearShoulderLen", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getAftShoulderLength(), 0.001);
+        handler.closeElement("RearShoulderLen", attributes, "10", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderLength(), 0.001);
+        handler.closeElement("RearShoulderLen", attributes, "10.0", warnings);
+        Assert.assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderLength(), 0.001);
+        handler.closeElement("RearShoulderLen", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("FrontShoulderDia", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getForeShoulderRadius(), 0.001);
+        handler.closeElement("FrontShoulderDia", attributes, "100", warnings);
+        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getForeShoulderRadius(), 0.001);
+        handler.closeElement("FrontShoulderDia", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("RearShoulderDia", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getAftShoulderRadius(), 0.001);
+        handler.closeElement("RearShoulderDia", attributes, "100", warnings);
+        Assert.assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getAftShoulderRadius(), 0.001);
+        handler.closeElement("RearShoulderDia", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        component.setType(Transition.Shape.HAACK);
+        handler.closeElement("ShapeParameter", attributes, "-1", warnings);
+        Assert.assertEquals(0d, component.getShapeParameter(), 0.001);
+        handler.closeElement("ShapeParameter", attributes, "100", warnings);
+        Assert.assertEquals(Transition.Shape.HAACK.maxParameter(), component.getShapeParameter(), 0.001);
+        handler.closeElement("ShapeParameter", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        Assert.assertEquals("Could not convert ShapeParameter value of foo.  It is expected to be a number.", 
+                     warnings.iterator().next().toString());
+
+        warnings.clear();
+
+        component.setType(Transition.Shape.CONICAL);
+        component.setShapeParameter(0d);
+        handler.closeElement("ShapeParameter", attributes, "100", warnings);
+        Assert.assertEquals(0d, component.getShapeParameter(), 0.001);
+
+        handler.closeElement("FinishCode", attributes, "-1", warnings);
+        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
+        handler.closeElement("FinishCode", attributes, "100", warnings);
+        Assert.assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish());
+        handler.closeElement("FinishCode", attributes, "foo", warnings);
+        Assert.assertEquals(1, warnings.size());
+        warnings.clear();
+
+        handler.closeElement("Name", attributes, "Test Name", warnings);
+        Assert.assertEquals("Test Name", component.getName());
+        
+        handler.closeElement("Material", attributes, "Some Material", warnings);
+        handler.endHandler("Transition", attributes, null, warnings);
+        Assert.assertTrue(component.getMaterial().getName().contains("Some Material"));
+    }
+
+    /**
+     * Method: getComponent()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetComponent() throws Exception {
+        Assert.assertTrue(new TransitionHandler(new Stage(), new WarningSet()).getComponent() instanceof Transition);
+    }
+
+    /**
+     * Method: getMaterialType()
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    @org.junit.Test
+    public void testGetMaterialType() throws Exception {
+        Assert.assertEquals(Material.Type.BULK, new TransitionHandler(new Stage(), new WarningSet()).getMaterialType());
+    }
+
+
+}
diff --git a/test/net/sf/openrocket/file/rocksim/importt/rocksimTestRocket1.rkt b/test/net/sf/openrocket/file/rocksim/importt/rocksimTestRocket1.rkt
new file mode 100644 (file)
index 0000000..79f7b00
--- /dev/null
@@ -0,0 +1,743 @@
+<RockSimDocument>
+<FileVersion>3</FileVersion>
+<DesignInformation>
+<RocketDesign>
+    <Name>FooBar Test</Name>
+<CalculateCD>1</CalculateCD>
+<ProCalculateCD>1</ProCalculateCD>
+<ProCalculateCN>1</ProCalculateCN>
+<FixedCd>0.75</FixedCd>
+<FixedCd2>0.8</FixedCd2>
+<FixedCd3>0.81</FixedCd3>
+<FixedCd2Alone>0.95</FixedCd2Alone>
+<FixedCd3Alone>0.95</FixedCd3Alone>
+<StageCount>1</StageCount>
+<Stage3Mass>0.</Stage3Mass>
+<Stage2Mass>0.</Stage2Mass>
+<Stage1Mass>0.</Stage1Mass>
+<Stage321CG>0.</Stage321CG>
+<Stage32CG>0.</Stage32CG>
+<Stage3CG>0.</Stage3CG>
+<Stage2CGAlone>0.</Stage2CGAlone>
+<Stage1CGAlone>0.</Stage1CGAlone>
+<CPCalcFlags>1</CPCalcFlags>
+<LaunchGuideLength>914.4</LaunchGuideLength>
+<UseKnownMass>0</UseKnownMass>
+<DefaultFinish>0</DefaultFinish>
+<FinishMedium>0</FinishMedium>
+<FinishCoatCount>1</FinishCoatCount>
+<GlueType>0</GlueType>
+<CPSimFlags>1</CPSimFlags>
+<LastSerialNumber>11</LastSerialNumber>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<BarromanXN>0,1215.49,0,0</BarromanXN>
+<BarrowmanCNa>0,35.9506,0,0</BarrowmanCNa>
+<RockSimXN>0,1226.38,0,0</RockSimXN>
+<RockSimCNa>0,47.5027,0,0</RockSimCNa>
+<RockSimCNa90>0,0,0,0</RockSimCNa90>
+<RockSimXN90>0,0,0,0</RockSimXN90>
+<ViewType>0</ViewType>
+<ViewStageCount>1</ViewStageCount>
+<ViewTypeEdit>0</ViewTypeEdit>
+<ViewStageCountEdit>1</ViewStageCountEdit>
+<ZoomFactor>0.</ZoomFactor>
+<ZoomFactorEdit>0.</ZoomFactorEdit>
+<ScrollPosX>0</ScrollPosX>
+<ScrollPosY>0</ScrollPosY>
+<ScrollPosXEdit>0</ScrollPosXEdit>
+<ScrollPosYEdit>0</ScrollPosYEdit>
+<ThreeDFlags>0</ThreeDFlags>
+<ThreeDFlagsEdit>0</ThreeDFlagsEdit>
+<UseModelSprite>0</UseModelSprite>
+<StaticMarginRef>0</StaticMarginRef>
+<UserRefDiameter>0.</UserRefDiameter>
+<SideMarkerHeight>10.</SideMarkerHeight>
+<SideDimensionHeight>10.</SideDimensionHeight>
+<BaseMarkerHeight>10.</BaseMarkerHeight>
+<BaseDimensionHeight>10.</BaseDimensionHeight>
+<ShowGlideCP>0</ShowGlideCP>
+<ShowGridTypeSide>0</ShowGridTypeSide>
+<ShowGridTypeBase>0</ShowGridTypeBase>
+<GridSpacing>10.</GridSpacing>
+<GridOpacity>0.15</GridOpacity>
+<GridColor>black</GridColor>
+<MaxDiaWithFins>424.688</MaxDiaWithFins>
+<MaxDiaWithoutFins>66.04</MaxDiaWithoutFins>
+<MaxLenWithFins>1417.95</MaxLenWithFins>
+<MaxLenWithoutFins>1332.23</MaxLenWithoutFins>
+<MinXExtent>0.</MinXExtent>
+<MaxXExtent>1417.95</MaxXExtent>
+<CalculatedMaxStageDia>0,66.04,0,0</CalculatedMaxStageDia>
+<CalculatedStageLen>0,1332.23,0,0</CalculatedStageLen>
+<Cd3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd3>
+<Cd32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd32>
+<Cd321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd321>
+<Cb3>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb3>
+<Cb32>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb32>
+<Cb321>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb321>
+<CNa3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa3>
+<CNa32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa32>
+<CNa321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa321>
+<CP3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP3>
+<CP32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP32>
+<CP321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP321>
+<SimulationEventList>
+</SimulationEventList>
+<Stage3Parts>
+<NoseCone>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>24.1</KnownMass>
+<Density>1049.21</Density>
+<Material>Polystyrene PS</Material>
+<Name>Nose cone</Name>
+<KnownCG>65.3999</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>126.438</CalcMass>
+<CalcCG>348.443</CalcCG>
+<WettedSurface>0.0356487</WettedSurface>
+<PaintedSurface>0.0356487</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>19470</PartNo>
+<PartDesc>PNC-70A</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>2</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>2.</BarrowmanCNa>
+<BarrowmanXN>0.264319</BarrowmanXN>
+<RockSimCNa>2.</RockSimCNa>
+<RockSimXN>0.264319</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>0.</Station>
+<Len>396.875</Len>
+<BaseDia>57.15</BaseDia>
+<FinishCode>0</FinishCode>
+<ShapeCode>0</ShapeCode>
+<ConstructionType>1</ConstructionType>
+<ShoulderLen>58.3997</ShoulderLen>
+<WallThickness>2.159</WallThickness>
+<ShapeParameter>0.</ShapeParameter>
+<ShoulderOD>53.1012</ShoulderOD>
+<BaseExtensionLen>66.675</BaseExtensionLen>
+<CoreDia>0.</CoreDia>
+<CoreLen>0.</CoreLen>
+<AttachedParts>
+</AttachedParts>
+</NoseCone>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>10.636</CalcMass>
+<CalcCG>180.34</CalcCG>
+<WettedSurface>0.0748306</WettedSurface>
+<PaintedSurface>0.0748306</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3090</PartNo>
+<PartDesc>BT-80</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>3</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>463.55</Station>
+<OD>66.04</OD>
+<ID>65.786</ID>
+<Len>360.68</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+<Transition>
+<PartMfg>BalsaMachining.com</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Transition</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>39.355</CalcMass>
+<CalcCG>37.0332</CalcCG>
+<WettedSurface>0.0096001</WettedSurface>
+<PaintedSurface>0.0096001</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TA7080</PartNo>
+<PartDesc>Transition T70 to T80 2 in long</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>7</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>-0.92852</BarrowmanCNa>
+<BarrowmanXN>0.848729</BarrowmanXN>
+<RockSimCNa>-0.92852</RockSimCNa>
+<RockSimXN>0.848729</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>824.23</Station>
+<FrontDia>66.04</FrontDia>
+<RearDia>53.34</RearDia>
+<Len>50.8</Len>
+<FinishCode>0</FinishCode>
+<FrontShoulderLen>35.56</FrontShoulderLen>
+<RearShoulderLen>35.56</RearShoulderLen>
+<ConstructionType>0</ConstructionType>
+<WallThickness>0.</WallThickness>
+<FrontShoulderDia>55.118</FrontShoulderDia>
+<RearShoulderDia>53.34</RearShoulderDia>
+<CoreDia>0.</CoreDia>
+<ShapeCode>0</ShapeCode>
+<ShapeParameter>0.</ShapeParameter>
+<EquivNoseLen>264.12</EquivNoseLen>
+<EquivNoseOffset>213.32</EquivNoseOffset>
+<AttachedParts>
+</AttachedParts>
+</Transition>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>44.449</CalcMass>
+<CalcCG>222.25</CalcCG>
+<WettedSurface>0.0787423</WettedSurface>
+<PaintedSurface>0.0787423</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>Estes</PartNo>
+<PartDesc>BT-70</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>8</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>875.03</Station>
+<OD>56.388</OD>
+<ID>55.372</ID>
+<Len>444.5</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<FinSet>
+<PartMfg>Public Missiles</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1905.24</Density>
+<Material>G10 fiberglass</Material>
+<Name>Fin set</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>260.35</Xb>
+<CalcMass>153.85</CalcMass>
+<CalcCG>155.575</CalcCG>
+<WettedSurface>0.0339112</WettedSurface>
+<PaintedSurface>0.101734</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>FIN-A-01</PartNo>
+<PartDesc>Fins</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>9</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>34.8792</BarrowmanCNa>
+<BarrowmanXN>1.26026</BarrowmanXN>
+<RockSimCNa>46.4312</RockSimCNa>
+<RockSimXN>1.26026</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>1135.38</Station>
+<FinCount>3</FinCount>
+<RootChord>184.15</RootChord>
+<TipChord>0.</TipChord>
+<SemiSpan>184.15</SemiSpan>
+<MidChordLen>264.956</MidChordLen>
+<SweepDistance>282.575</SweepDistance>
+<Thickness>1.5875</Thickness>
+<ShapeCode>0</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>0</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.990003</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>89.5773</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>26.8071</RockSimCNaPerFin>
+<TaperRatio>0.</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>13.008</CalcMass>
+<CalcCG>228.6</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3086</PartNo>
+<PartDesc>BT-50</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>11</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>875.03</Station>
+<OD>24.7904</OD>
+<ID>24.13</ID>
+<Len>457.2</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>24.</MotorDia>
+<EngineOverhang>12.7</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</BodyTube>
+</Stage3Parts>
+<Stage2Parts>
+</Stage2Parts>
+<Stage1Parts>
+</Stage1Parts>
+<SideViewDims>
+</SideViewDims>
+<BaseViewDims>
+</BaseViewDims>
+<VertViewDims>
+</VertViewDims>
+</RocketDesign>
+</DesignInformation>
+<SimulationResultsList>
+<SimulationResults>
+<MaxAltitude>445.129</MaxAltitude>
+<MaxVelocity>68.7587</MaxVelocity>
+<MaxAcceleration>76.6476</MaxAcceleration>
+<TimeToApogee>10.8263</TimeToApogee>
+<OptimalDelay>4.765</OptimalDelay>
+<MultiDelayCount>1</MultiDelayCount>
+<VelocityAtDeplyment>33.4284</VelocityAtDeplyment>
+<AltitudeAtDeployment>405.535</AltitudeAtDeployment>
+<DelayTime>2</DelayTime>
+<EjectTime>8.06125</EjectTime>
+<FinalState>4</FinalState>
+<TimeToBurnout>6.06125</TimeToBurnout>
+<TimeToLanding>22.4787</TimeToLanding>
+<TimeToEject>8.06125</TimeToEject>
+<MinLaunchGuideLen>1.35915</MinLaunchGuideLen>
+<MaxVertVelocity>65.9349</MaxVertVelocity>
+<MaxHorzVelocity>1.0686</MaxHorzVelocity>
+<MaxVertAcceleration>76.5426</MaxVertAcceleration>
+<MaxHorzAcceleration>4.01173</MaxHorzAcceleration>
+<MaxRange>172.076</MaxRange>
+<LaunchStartVelocity>0.</LaunchStartVelocity>
+<LaunchStartRollRate>0.</LaunchStartRollRate>
+<LaunchGuideType>0</LaunchGuideType>
+<LaunchGuideLen>1828.8</LaunchGuideLen>
+<LaunchWindDirection>0</LaunchWindDirection>
+<LaunchWindSpeed>0.</LaunchWindSpeed>
+<LaunchDirection>0</LaunchDirection>
+<LaunchAngle>0.0523599</LaunchAngle>
+<LaunchGuideAzimuth>0.</LaunchGuideAzimuth>
+<LaunchGuideElevation>0.</LaunchGuideElevation>
+<LaunchBarometer>770.314</LaunchBarometer>
+<LaunchLatitude>43.</LaunchLatitude>
+<LaunchLongitude>0.</LaunchLongitude>
+<LaunchHumidity>70.</LaunchHumidity>
+<LaunchTemperature>7.22222</LaunchTemperature>
+<LaunchAltitude>304.8</LaunchAltitude>
+<LaunchLandingAltitude>0.</LaunchLandingAltitude>
+<CompStateMask>0</CompStateMask>
+<LaunchWindPreset>3</LaunchWindPreset>
+<LaunchWindLowSpeed>1.34112</LaunchWindLowSpeed>
+<LaunchWindHighSpeed>3.53162</LaunchWindHighSpeed>
+<LaunchWindTurbulencePreset>2</LaunchWindTurbulencePreset>
+<LaunchWindFrequency>0.01</LaunchWindFrequency>
+<LaunchWindDeltaFrequency>0.02</LaunchWindDeltaFrequency>
+<LaunchUseRandomConditions>0</LaunchUseRandomConditions>
+<LaunchCloudCoverPreset>5</LaunchCloudCoverPreset>
+<LaunchCCLow>0.</LaunchCCLow>
+<LaunchCCHigh>0.1</LaunchCCHigh>
+<LaunchThermalPosPreset>1</LaunchThermalPosPreset>
+<LaunchThermalPos>0.</LaunchThermalPos>
+<LaunchMultipleThermals>0</LaunchMultipleThermals>
+<LaunchMaxThermals>3</LaunchMaxThermals>
+<LaunchThermalDia>300.</LaunchThermalDia>
+<LaunchThermalHeight>2000.</LaunchThermalHeight>
+<LaunchThermalSpeedPreset>1</LaunchThermalSpeedPreset>
+<LaunchThermalSpeed>5.99999</LaunchThermalSpeed>
+<LaunchWindTableSize>0</LaunchWindTableSize>
+<LaunchWindAltTable>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</LaunchWindAltTable>
+<LaunchWindSpeedTable>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</LaunchWindSpeedTable>
+<LaunchWindDirectionTable>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</LaunchWindDirectionTable>
+<LaunchLossPreset>2</LaunchLossPreset>
+<LaunchLossPercent>0.99</LaunchLossPercent>
+<LaunchSiteDia>2000.</LaunchSiteDia>
+<LaunchDriftRangeToLoss>1500.</LaunchDriftRangeToLoss>
+<LaunchPayloadDamagePreset>2</LaunchPayloadDamagePreset>
+<LaunchPayloadDamagePercent>0.98</LaunchPayloadDamagePercent>
+<LaunchEngineMisfirePreset>1</LaunchEngineMisfirePreset>
+<LaunchEngineMisfirePercent>0.</LaunchEngineMisfirePercent>
+<LaunchVariableIgnitionDelay>0</LaunchVariableIgnitionDelay>
+<LaunchVariableIgnitionDelaySec>0.08</LaunchVariableIgnitionDelaySec>
+<LaunchRecDeviceFailurePreset>1</LaunchRecDeviceFailurePreset>
+<LaunchRecDeviceFailurePercent>0.</LaunchRecDeviceFailurePercent>
+<LaunchAriframeFailurePreset>1</LaunchAriframeFailurePreset>
+<LaunchAirframeFailurePercent>0.</LaunchAirframeFailurePercent>
+<LaunchTrackLossPreset>1</LaunchTrackLossPreset>
+<LaunchTeckLossPercent>0.</LaunchTeckLossPercent>
+<CNaMultiplier>1.</CNaMultiplier>
+<CdMultiplier>1.</CdMultiplier>
+<CPOffset>0.</CPOffset>
+<SaveSimAsText>0</SaveSimAsText>
+<OutputAtMaxRes>0</OutputAtMaxRes>
+<MaxSimTim>3600.</MaxSimTim>
+<MassUncertainty>0.</MassUncertainty>
+<MOIUncertainty>0.</MOIUncertainty>
+<CGUncertainty>0.</CGUncertainty>
+<CdUncertainty>0.</CdUncertainty>
+<CnaUncertainty>0.</CnaUncertainty>
+<CPUncertainty>0.</CPUncertainty>
+<FinCantUncertainty>0.</FinCantUncertainty>
+<TotImpulseUncertainty>0.</TotImpulseUncertainty>
+<PropellantUncertainty>0.</PropellantUncertainty>
+<ThrustAxisUncertainty>0.</ThrustAxisUncertainty>
+<WindDirectionUncertainty>0.</WindDirectionUncertainty>
+<WindVelocityUncertainty>0.</WindVelocityUncertainty>
+<LaunchGuideAzimuthUncertainty>0.</LaunchGuideAzimuthUncertainty>
+<LaunchGuideElevationUncertainty>0.</LaunchGuideElevationUncertainty>
+<IgnitionUncertainty>0.</IgnitionUncertainty>
+<CATOUncertainty>0.</CATOUncertainty>
+<DeploymentUncertainty>0.</DeploymentUncertainty>
+<RecoveryDeviceUncertainty>0.</RecoveryDeviceUncertainty>
+<SimulationName>[E6-2] </SimulationName>
+<VelocityAtLaunchGuideEnd>15.4098</VelocityAtLaunchGuideEnd>
+<WindStartAltitude>0.</WindStartAltitude>
+<TimeToWindShear>0.</TimeToWindShear>
+<TimeToFreeFlight>0.25875</TimeToFreeFlight>
+<TimeToMaxVelocity>5.69125</TimeToMaxVelocity>
+<TimeToMaxAcceleration>0.11125</TimeToMaxAcceleration>
+<Nsims>10</Nsims>
+<CalcResolution>1</CalcResolution>
+<SamplesPerSecond>800.</SamplesPerSecond>
+<SimulationType>0</SimulationType>
+<LocationDataServerName>Earth</LocationDataServerName>
+<LocationDataServerDisplayName>Standard earth condistions.</LocationDataServerDisplayName>
+<ExecutionTime>4.078</ExecutionTime>
+<RangeAtLanding>-172.076</RangeAtLanding>
+<DirectionAtLanding>0.</DirectionAtLanding>
+<VelocityAtLanding>56.537</VelocityAtLanding>
+<XVelcoityAtLanding>-3.38254</XVelcoityAtLanding>
+<YVelocityAtLanding>-56.4357</YVelocityAtLanding>
+<ZVelocityAtLanding>0.</ZVelocityAtLanding>
+<StageSeparationTime>0,0,8.06125,0,0</StageSeparationTime>
+<StageEjectTime>-1,-1,-1,-1,-1</StageEjectTime>
+<TimeToDeployment>0,0,0,0,0</TimeToDeployment>
+<DeploymentType>32,32,32,32,32</DeploymentType>
+<SamplesPerSecondDescent>1.</SamplesPerSecondDescent>
+<CalculationFlags>1</CalculationFlags>
+<Mass0>0.233111</Mass0>
+<CG0>0.739954</CG0>
+<LaterialMOI0>0.0208295</LaterialMOI0>
+<RadialMOI0>0.000194272</RadialMOI0>
+<GUID>{b33e529e-1ada-4524-9885-7382d7cf4d64}</GUID>
+<Booster1Staging>
+<SimulationEvent>
+<PartSerialNo>0</PartSerialNo>
+<Type>0</Type>
+<DeployAltitude>0.</DeployAltitude>
+<DeplyTime>0.</DeplyTime>
+<HasDeployed>0</HasDeployed>
+<DeployedAt_Altitude>0.</DeployedAt_Altitude>
+<DeployedAt_Velocity>0.</DeployedAt_Velocity>
+<DeployedAt_Range>0.</DeployedAt_Range>
+<DeployedAt_Time>0.</DeployedAt_Time>
+<DeviceID>-1</DeviceID>
+<TestType>0,0,0</TestType>
+<TestCondition>0,0,0</TestCondition>
+<TestValueAltitude>0,0,0</TestValueAltitude>
+<TestValueDegrees>0,0,0</TestValueDegrees>
+<TestValuePressure>0,0,0</TestValuePressure>
+<TestValueMach>0,0,0</TestValueMach>
+<TestValueTime>0,0,0</TestValueTime>
+<TestValueQ>0,0,0</TestValueQ>
+</SimulationEvent>
+</Booster1Staging>
+<Booster2Staging>
+<SimulationEvent>
+<PartSerialNo>0</PartSerialNo>
+<Type>0</Type>
+<DeployAltitude>0.</DeployAltitude>
+<DeplyTime>0.</DeplyTime>
+<HasDeployed>0</HasDeployed>
+<DeployedAt_Altitude>0.</DeployedAt_Altitude>
+<DeployedAt_Velocity>0.</DeployedAt_Velocity>
+<DeployedAt_Range>0.</DeployedAt_Range>
+<DeployedAt_Time>0.</DeployedAt_Time>
+<DeviceID>-1</DeviceID>
+<TestType>0,0,0</TestType>
+<TestCondition>0,0,0</TestCondition>
+<TestValueAltitude>0,0,0</TestValueAltitude>
+<TestValueDegrees>0,0,0</TestValueDegrees>
+<TestValuePressure>0,0,0</TestValuePressure>
+<TestValueMach>0,0,0</TestValueMach>
+<TestValueTime>0,0,0</TestValueTime>
+<TestValueQ>0,0,0</TestValueQ>
+</SimulationEvent>
+</Booster2Staging>
+<SimulationEvents>
+</SimulationEvents>
+<Stage1Engines>
+</Stage1Engines>
+<Stage2Engines>
+</Stage2Engines>
+<Stage3Engines>
+<EngineSet>
+<EngineCount>1</EngineCount>
+<EngineCode>E6</EngineCode>
+<IgnitionDelay>0.</IgnitionDelay>
+<EngineMfg>Apogee</EngineMfg>
+<EngineOverhang>0.50038</EngineOverhang>
+<CasingCG>0.</CasingCG>
+<MountSerialNo>5</MountSerialNo>
+<EjectionDelay>2.</EjectionDelay>
+<RotateXaboutY>0.</RotateXaboutY>
+<RotateEngineAxisAboutX>0.</RotateEngineAxisAboutX>
+</EngineSet>
+</Stage3Engines>
+<DropItems>
+</DropItems>
+</SimulationResults>
+</SimulationResultsList>
+</RockSimDocument>
diff --git a/test/net/sf/openrocket/file/rocksim/importt/rocksimTestRocket2.rkt b/test/net/sf/openrocket/file/rocksim/importt/rocksimTestRocket2.rkt
new file mode 100644 (file)
index 0000000..39b3411
--- /dev/null
@@ -0,0 +1,1583 @@
+<RockSimDocument>
+<FileVersion>3</FileVersion>
+<DesignInformation>
+<RocketDesign>
+<Name>Three Stage Everything Included Rocket</Name>
+<CalculateCD>1</CalculateCD>
+<ProCalculateCD>1</ProCalculateCD>
+<ProCalculateCN>1</ProCalculateCN>
+<FixedCd>0.75</FixedCd>
+<FixedCd2>0.8</FixedCd2>
+<FixedCd3>0.81</FixedCd3>
+<FixedCd2Alone>0.95</FixedCd2Alone>
+<FixedCd3Alone>0.95</FixedCd3Alone>
+<StageCount>3</StageCount>
+<Stage3Mass>0.</Stage3Mass>
+<Stage2Mass>0.</Stage2Mass>
+<Stage1Mass>0.</Stage1Mass>
+<Stage321CG>0.</Stage321CG>
+<Stage32CG>0.</Stage32CG>
+<Stage3CG>0.</Stage3CG>
+<Stage2CGAlone>0.</Stage2CGAlone>
+<Stage1CGAlone>0.</Stage1CGAlone>
+<CPCalcFlags>1</CPCalcFlags>
+<LaunchGuideLength>914.4</LaunchGuideLength>
+<UseKnownMass>0</UseKnownMass>
+<DefaultFinish>0</DefaultFinish>
+<FinishMedium>0</FinishMedium>
+<FinishCoatCount>1</FinishCoatCount>
+<GlueType>0</GlueType>
+<CPSimFlags>1</CPSimFlags>
+<LastSerialNumber>25</LastSerialNumber>
+<DisplayFlags>7</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<BarromanXN>0,29.6333,326.159,887.03</BarromanXN>
+<BarrowmanCNa>0,2,4.93008,33.0782</BarrowmanCNa>
+<RockSimXN>0,29.6333,384.174,883.929</RockSimXN>
+<RockSimCNa>0,2,6.91103,47.1184</RockSimCNa>
+<RockSimCNa90>0,0,0,0</RockSimCNa90>
+<RockSimXN90>0,0,0,0</RockSimXN90>
+<ViewType>0</ViewType>
+<ViewStageCount>3</ViewStageCount>
+<ViewTypeEdit>0</ViewTypeEdit>
+<ViewStageCountEdit>3</ViewStageCountEdit>
+<ZoomFactor>0.</ZoomFactor>
+<ZoomFactorEdit>0.</ZoomFactorEdit>
+<ScrollPosX>0</ScrollPosX>
+<ScrollPosY>0</ScrollPosY>
+<ScrollPosXEdit>0</ScrollPosXEdit>
+<ScrollPosYEdit>0</ScrollPosYEdit>
+<ThreeDFlags>0</ThreeDFlags>
+<ThreeDFlagsEdit>0</ThreeDFlagsEdit>
+<UseModelSprite>0</UseModelSprite>
+<StaticMarginRef>0</StaticMarginRef>
+<UserRefDiameter>0.</UserRefDiameter>
+<SideMarkerHeight>10.</SideMarkerHeight>
+<SideDimensionHeight>10.</SideDimensionHeight>
+<BaseMarkerHeight>10.</BaseMarkerHeight>
+<BaseDimensionHeight>10.</BaseDimensionHeight>
+<ShowGlideCP>0</ShowGlideCP>
+<ShowGridTypeSide>0</ShowGridTypeSide>
+<ShowGridTypeBase>0</ShowGridTypeBase>
+<GridSpacing>10.</GridSpacing>
+<GridOpacity>0.15</GridOpacity>
+<GridColor>black</GridColor>
+<MaxDiaWithFins>339.43</MaxDiaWithFins>
+<MaxDiaWithoutFins>66.3</MaxDiaWithoutFins>
+<MaxLenWithFins>2104.53</MaxLenWithFins>
+<MaxLenWithoutFins>2104.53</MaxLenWithoutFins>
+<MinXExtent>0.</MinXExtent>
+<MaxXExtent>1150.33</MaxXExtent>
+<CalculatedMaxStageDia>0,66.3,66.3,66.3</CalculatedMaxStageDia>
+<CalculatedStageLen>0,296.8,954.2,2104.53</CalculatedStageLen>
+<Cd3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd3>
+<Cd32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd32>
+<Cd321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd321>
+<Cb3>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb3>
+<Cb32>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb32>
+<Cb321>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb321>
+<CNa3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa3>
+<CNa32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa32>
+<CNa321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa321>
+<CP3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP3>
+<CP32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP32>
+<CP321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP321>
+<SimulationEventList>
+</SimulationEventList>
+<Stage3Parts>
+<NoseCone>
+<PartMfg>Aerospace Speciality Products</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Nose cone</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>42.0747</CalcMass>
+<CalcCG>75.3029</CalcCG>
+<WettedSurface>0.0152945</WettedSurface>
+<PaintedSurface>0.0152945</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>BNC80S</PartNo>
+<PartDesc><![CDATA[T-80H Balsa Nose Cone "S"]]></PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>1</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>2.</BarrowmanCNa>
+<BarrowmanXN>0.0296333</BarrowmanXN>
+<RockSimCNa>2.</RockSimCNa>
+<RockSimXN>0.0296333</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>0.</Station>
+<Len>88.9</Len>
+<BaseDia>66.3</BaseDia>
+<FinishCode>0</FinishCode>
+<ShapeCode>3</ShapeCode>
+<ConstructionType>0</ConstructionType>
+<ShoulderLen>38.1</ShoulderLen>
+<WallThickness>0.</WallThickness>
+<ShapeParameter>0.</ShapeParameter>
+<ShoulderOD>64.3</ShoulderOD>
+<BaseExtensionLen>0.</BaseExtensionLen>
+<CoreDia>0.</CoreDia>
+<CoreLen>0.</CoreLen>
+<AttachedParts>
+<MassObject>
+<PartMfg>Custom</PartMfg>
+<KnownMass>20.</KnownMass>
+<Density>0.</Density>
+<Material>Custom</Material>
+<Name>Clay</Name>
+<KnownCG>17.8</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>17.8</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>0.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>2</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>17.8</Station>
+<TypeCode>0</TypeCode>
+<Len>0.</Len>
+<AttachedParts>
+</AttachedParts>
+</MassObject>
+<BodyTube>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Attachment Rod</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>6.1</Xb>
+<CalcMass>2.47301</CalcMass>
+<CalcCG>78.85</CalcCG>
+<WettedSurface>0.00684683</WettedSurface>
+<PaintedSurface>0.00684683</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>10062</PartNo>
+<PartDesc>13 mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>3</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>6.1</Station>
+<OD>13.82</OD>
+<ID>13.16</ID>
+<Len>157.7</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Plate</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>78.9</Xb>
+<CalcMass>7.86272</CalcMass>
+<CalcCG>1.585</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-(2)0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>4</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>85.</Station>
+<OD>66.</OD>
+<ID>13.82</ID>
+<Len>3.17</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>Custom</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1400.</Density>
+<Material>Carbon Fiber</Material>
+<Name>Sleeve </Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>17.5527</CalcMass>
+<CalcCG>13.85</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>5</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>2</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>136.1</Station>
+<OD>27.7</OD>
+<ID>13.82</ID>
+<Len>27.7</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>3</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Parachute>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>170.</KnownMass>
+<Density>0.006685</Density>
+<Material>Rip stop nylon</Material>
+<Name>Nose Cone Parachute</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>142.6</Xb>
+<CalcMass>15.8812</CalcMass>
+<CalcCG>34.5417</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>1</DensityType>
+<PartNo>LP-50</PartNo>
+<PartDesc>50 In. 16 lines</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>6</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>148.7</Station>
+<Dia>414.5</Dia>
+<SpillHoleDia>0.</SpillHoleDia>
+<SideCount>15</SideCount>
+<ShroudLineCount>16</ShroudLineCount>
+<Thickness>0.05</Thickness>
+<ShroudLineLen>1350.</ShroudLineLen>
+<ChuteCount>1</ChuteCount>
+<ShroudLineMassPerMM>0.00032972</ShroudLineMassPerMM>
+<ShroudLineMaterial>Carpet String (Apogee 29500)</ShroudLineMaterial>
+<DragCoefficient>0.95</DragCoefficient>
+<AttachedParts>
+</AttachedParts>
+</Parachute>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</NoseCone>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>15.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>100.</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>5.80486</CalcMass>
+<CalcCG>100.</CalcCG>
+<WettedSurface>0.0414942</WettedSurface>
+<PaintedSurface>0.0414942</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3090</PartNo>
+<PartDesc>BT-80</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>7</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>88.9</Station>
+<OD>66.04</OD>
+<ID>65.79</ID>
+<Len>200.</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>190.2</Xb>
+<CalcMass>7.65502</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>8</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>279.1</Station>
+<OD>65.02</OD>
+<ID>25.4</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>165.</Xb>
+<CalcMass>7.62626</CalcMass>
+<CalcCG>1.585</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-(2)0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>9</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>253.9</Station>
+<OD>65.</OD>
+<ID>25.4</ID>
+<Len>3.17</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<BodyTube>
+<PartMfg>Public Missiles Ltd.</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>958.705</Density>
+<Material>Kraft phenolic</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>137.9</Xb>
+<CalcMass>9.8818</CalcMass>
+<CalcCG>35.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>KS-1.1</PartNo>
+<PartDesc>KwikSwitch MMT 29mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>-1.58371</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>10</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>226.8</Station>
+<OD>32.26</OD>
+<ID>29.21</ID>
+<Len>70.</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>29.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</BodyTube>
+</Stage3Parts>
+<Stage2Parts>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>2nd Stage Tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>10.4685</CalcMass>
+<CalcCG>180.34</CalcCG>
+<WettedSurface>0.0748306</WettedSurface>
+<PaintedSurface>0.0748306</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3090</PartNo>
+<PartDesc>BT-80</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>11</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>288.9</Station>
+<OD>66.04</OD>
+<ID>65.79</ID>
+<Len>360.68</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>15.025</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Tube coupler</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>-10.</Xb>
+<CalcMass>20.465</CalcMass>
+<CalcCG>35.45</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TC-2.56</PartNo>
+<PartDesc>Tube Coupler</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>12</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>278.9</Station>
+<OD>65.79</OD>
+<ID>63.25</ID>
+<Len>70.9</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>4</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<MassObject>
+<PartMfg>Custom</PartMfg>
+<KnownMass>40.</KnownMass>
+<Density>0.</Density>
+<Material>Custom</Material>
+<Name>Electronics</Name>
+<KnownCG>138.3</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>138.3</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>0.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>13</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>427.2</Station>
+<TypeCode>0</TypeCode>
+<Len>0.</Len>
+<AttachedParts>
+</AttachedParts>
+</MassObject>
+<FinSet>
+<PartMfg>Quest</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Fin set</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>228.6</Xb>
+<CalcMass>1.32269</CalcMass>
+<CalcCG>19.05</CalcCG>
+<WettedSurface>0.0028791</WettedSurface>
+<PaintedSurface>0.0086373</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>Payloader One</PartNo>
+<PartDesc>Fin</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.0830777</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>14</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>2.93008</BarrowmanCNa>
+<BarrowmanXN>0.52856</BarrowmanXN>
+<RockSimCNa>5.49629</RockSimCNa>
+<RockSimXN>0.52856</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>517.5</Station>
+<FinCount>3</FinCount>
+<RootChord>38.1</RootChord>
+<TipChord>24.9</TipChord>
+<SemiSpan>45.7</SemiSpan>
+<MidChordLen>45.7</MidChordLen>
+<SweepDistance>6.6</SweepDistance>
+<Thickness>2.39</Thickness>
+<ShapeCode>0</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>2</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.139993</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>54.2741</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>2.83538</RockSimCNaPerFin>
+<TaperRatio>0.653543</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>302.</Xb>
+<CalcMass>7.65502</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>15</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>590.9</Station>
+<OD>65.02</OD>
+<ID>25.4</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>335.5</Xb>
+<CalcMass>7.62626</CalcMass>
+<CalcCG>1.585</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-(2)0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>16</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>624.4</Station>
+<OD>65.</OD>
+<ID>25.4</ID>
+<Len>3.17</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<BodyTube>
+<PartMfg>Public Missiles Ltd.</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>958.705</Density>
+<Material>Kraft phenolic</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>587.4</Xb>
+<CalcMass>9.8818</CalcMass>
+<CalcCG>35.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>KS-1.1</PartNo>
+<PartDesc>KwikSwitch MMT 29mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>-1.58371</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>17</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>1</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>587.4</Station>
+<OD>32.26</OD>
+<ID>29.21</ID>
+<Len>70.</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>29.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>Semroc</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Engine block</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>2.69315</CalcMass>
+<CalcCG>2.39</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TB-7</PartNo>
+<PartDesc>Thrust Block</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>18</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>587.4</Station>
+<OD>29.21</OD>
+<ID>14.61</ID>
+<Len>4.78</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>2</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</BodyTube>
+</Stage2Parts>
+<Stage1Parts>
+<Transition>
+<PartMfg>BalsaMachining.com</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Transition</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>8.62096</CalcMass>
+<CalcCG>25.1578</CalcCG>
+<WettedSurface>0.00986655</WettedSurface>
+<PaintedSurface>0.00986655</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TA6080</PartNo>
+<PartDesc>Transition T60 to T80 2.25 in long</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>19</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>-1.20451</BarrowmanCNa>
+<BarrowmanXN>0.675971</BarrowmanXN>
+<RockSimCNa>-1.20451</RockSimCNa>
+<RockSimXN>0.675971</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>649.58</Station>
+<FrontDia>66.04</FrontDia>
+<RearDia>41.4</RearDia>
+<Len>57.15</Len>
+<FinishCode>0</FinishCode>
+<FrontShoulderLen>20.</FrontShoulderLen>
+<RearShoulderLen>38.1</RearShoulderLen>
+<ConstructionType>1</ConstructionType>
+<WallThickness>3.</WallThickness>
+<FrontShoulderDia>64.77</FrontShoulderDia>
+<RearShoulderDia>41.38</RearShoulderDia>
+<CoreDia>0.</CoreDia>
+<ShapeCode>0</ShapeCode>
+<ShapeParameter>0.</ShapeParameter>
+<EquivNoseLen>153.172</EquivNoseLen>
+<EquivNoseOffset>96.022</EquivNoseOffset>
+<AttachedParts>
+</AttachedParts>
+</Transition>
+<BodyTube>
+<PartMfg>LOC/Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>33.5306</CalcMass>
+<CalcCG>209.2</CalcCG>
+<WettedSurface>0.0604643</WettedSurface>
+<PaintedSurface>0.0604643</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC BT-2.14</PartNo>
+<PartDesc>Airframe tube</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>20</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>706.73</Station>
+<OD>46.</OD>
+<ID>45.</ID>
+<Len>418.4</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<FinSet>
+<PartMfg>Quest</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Elliptical Fins</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>69.7</Xb>
+<CalcMass>36.2048</CalcMass>
+<CalcCG>46.</CalcCG>
+<WettedSurface>0.00676907</WettedSurface>
+<PaintedSurface>0.0203072</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>-0.519061</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>21</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>3.64017</BarrowmanCNa>
+<BarrowmanXN>0.802926</BarrowmanXN>
+<RockSimCNa>6.19583</RockSimCNa>
+<RockSimXN>0.802926</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>776.43</Station>
+<FinCount>3</FinCount>
+<RootChord>92.</RootChord>
+<TipChord>46.</TipChord>
+<SemiSpan>46.9</SemiSpan>
+<MidChordLen>46.9</MidChordLen>
+<SweepDistance>33.49</SweepDistance>
+<Thickness>3.18</Thickness>
+<ShapeCode>1</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>0</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.349066</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>43.8444</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>3.30201</RockSimCNaPerFin>
+<TaperRatio>0.5</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+<CustomFinSet>
+<PartMfg>Public Missiles</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1905.24</Density>
+<Material>G10 fiberglass</Material>
+<Name>Custom Fins</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>241.7</Xb>
+<CalcMass>256.292</CalcMass>
+<CalcCG>78.9922</CalcCG>
+<WettedSurface>0.0355266</WettedSurface>
+<PaintedSurface>0.10658</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>FIN-C-02</PartNo>
+<PartDesc>Fins</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.357967</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>22</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>25.7124</BarrowmanCNa>
+<BarrowmanXN>0.996591</BarrowmanXN>
+<RockSimCNa>34.6308</RockSimCNa>
+<RockSimXN>0.996926</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>948.43</Station>
+<FinCount>3</FinCount>
+<RootChord>152.4</RootChord>
+<TipChord>83.83</TipChord>
+<SemiSpan>146.72</SemiSpan>
+<MidChordLen>146.81</MidChordLen>
+<SweepDistance>39.42</SweepDistance>
+<Thickness>2.38</Thickness>
+<ShapeCode>2</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>2</TipShapeCode>
+<TabLength>101.6</TabLength>
+<TabDepth>10.6</TabDepth>
+<TabOffset>35.6</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>89.2598</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>19.9941</RockSimCNaPerFin>
+<TaperRatio>0.550066</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AverageChord>121.07</AverageChord>
+<EffectiveTipChord>83.8257</EffectiveTipChord>
+<PointList>152.4,0|126.202,146.715|36.455,146.715|0,0|</PointList>
+<AutoCalcGridStepX>0,0,0,0,0,0,0</AutoCalcGridStepX>
+<GridStepCountX>10,10,10,10,10,10,10</GridStepCountX>
+<UseAbsoluteGridStepsX>0,0,0,0,0,0,0</UseAbsoluteGridStepsX>
+<GridStepSizeX>0.5,10,0.5,0.5,0.00018939,0.001,1</GridStepSizeX>
+<SnapToSizeX>0.25,5,0.1,0.1,0.00018939,0.001,1</SnapToSizeX>
+<AutoCalcGridStepY>0,0,0,0,0,0,0</AutoCalcGridStepY>
+<GridStepCountY>10,10,10,10,10,10,10</GridStepCountY>
+<UseAbsoluteGridStepsY>0,0,0,0,0,0,0</UseAbsoluteGridStepsY>
+<GridStepSizeY>0.5,10,0.5,0.5,0.00018939,0.001,1</GridStepSizeY>
+<SnapToSizeY>0.25,5,0.1,0.1,0.00018939,0.001,1</SnapToSizeY>
+<AttachedParts>
+</AttachedParts>
+</CustomFinSet>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>379.5</Xb>
+<CalcMass>2.55395</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC FCR-1.52-1.14</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>23</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>1086.23</Station>
+<OD>45.</OD>
+<ID>24.79</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>272.</Xb>
+<CalcMass>2.55395</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC FCR-1.52-1.14</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>24</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>978.73</Station>
+<OD>45.</OD>
+<ID>24.79</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>259.7</Xb>
+<CalcMass>5.22902</CalcMass>
+<CalcCG>91.95</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3086</PartNo>
+<PartDesc>BT-50</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>25</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>966.43</Station>
+<OD>24.79</OD>
+<ID>24.13</ID>
+<Len>183.9</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>24.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</BodyTube>
+</Stage1Parts>
+<SideViewDims>
+</SideViewDims>
+<BaseViewDims>
+</BaseViewDims>
+<VertViewDims>
+</VertViewDims>
+</RocketDesign>
+</DesignInformation>
+<SimulationResultsList>
+</SimulationResultsList>
+</RockSimDocument>
diff --git a/test/net/sf/openrocket/file/rocksim/importt/rocksimTestRocket3.rkt b/test/net/sf/openrocket/file/rocksim/importt/rocksimTestRocket3.rkt
new file mode 100644 (file)
index 0000000..df1788c
--- /dev/null
@@ -0,0 +1,1961 @@
+<RockSimDocument>
+<FileVersion>3</FileVersion>
+<DesignInformation>
+<RocketDesign>
+<Name>Three Stage Everything Included Rocket - Override Total Mass/CG</Name>
+<CalculateCD>1</CalculateCD>
+<ProCalculateCD>1</ProCalculateCD>
+<ProCalculateCN>1</ProCalculateCN>
+<FixedCd>0.75</FixedCd>
+<FixedCd2>0.8</FixedCd2>
+<FixedCd3>0.81</FixedCd3>
+<FixedCd2Alone>0.95</FixedCd2Alone>
+<FixedCd3Alone>0.95</FixedCd3Alone>
+<StageCount>3</StageCount>
+<Stage3Mass>185.</Stage3Mass>
+<Stage2Mass>210.</Stage2Mass>
+<Stage1Mass>330.</Stage1Mass>
+<Stage321CG>0.</Stage321CG>
+<Stage32CG>0.</Stage32CG>
+<Stage3CG>300.</Stage3CG>
+<Stage2CGAlone>400.</Stage2CGAlone>
+<Stage1CGAlone>500.</Stage1CGAlone>
+<CPCalcFlags>1</CPCalcFlags>
+<LaunchGuideLength>914.4</LaunchGuideLength>
+<UseKnownMass>0</UseKnownMass>
+<DefaultFinish>0</DefaultFinish>
+<FinishMedium>0</FinishMedium>
+<FinishCoatCount>1</FinishCoatCount>
+<GlueType>0</GlueType>
+<CPSimFlags>1</CPSimFlags>
+<LastSerialNumber>32</LastSerialNumber>
+<DisplayFlags>7</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<BarromanXN>0,29.6333,327.236,966.855</BarromanXN>
+<BarrowmanCNa>0,2,4.95647,83.562</BarrowmanCNa>
+<RockSimXN>0,29.6333,385.082,953.76</RockSimXN>
+<RockSimCNa>0,2,6.95476,97.0629</RockSimCNa>
+<RockSimCNa90>0,0,0,0</RockSimCNa90>
+<RockSimXN90>0,0,0,0</RockSimXN90>
+<ViewType>0</ViewType>
+<ViewStageCount>3</ViewStageCount>
+<ViewTypeEdit>0</ViewTypeEdit>
+<ViewStageCountEdit>3</ViewStageCountEdit>
+<ZoomFactor>0.</ZoomFactor>
+<ZoomFactorEdit>0.</ZoomFactorEdit>
+<ScrollPosX>0</ScrollPosX>
+<ScrollPosY>0</ScrollPosY>
+<ScrollPosXEdit>0</ScrollPosXEdit>
+<ScrollPosYEdit>0</ScrollPosYEdit>
+<ThreeDFlags>0</ThreeDFlags>
+<ThreeDFlagsEdit>0</ThreeDFlagsEdit>
+<UseModelSprite>0</UseModelSprite>
+<StaticMarginRef>0</StaticMarginRef>
+<UserRefDiameter>0.</UserRefDiameter>
+<SideMarkerHeight>10.</SideMarkerHeight>
+<SideDimensionHeight>10.</SideDimensionHeight>
+<BaseMarkerHeight>10.</BaseMarkerHeight>
+<BaseDimensionHeight>10.</BaseDimensionHeight>
+<ShowGlideCP>0</ShowGlideCP>
+<ShowGridTypeSide>0</ShowGridTypeSide>
+<ShowGridTypeBase>0</ShowGridTypeBase>
+<GridSpacing>10.</GridSpacing>
+<GridOpacity>0.15</GridOpacity>
+<GridColor>black</GridColor>
+<MaxDiaWithFins>334.83</MaxDiaWithFins>
+<MaxDiaWithoutFins>66.</MaxDiaWithoutFins>
+<MaxLenWithFins>2155.23</MaxLenWithFins>
+<MaxLenWithoutFins>2155.23</MaxLenWithoutFins>
+<MinXExtent>0.</MinXExtent>
+<MaxXExtent>1150.33</MaxXExtent>
+<CalculatedMaxStageDia>0,66,66,66</CalculatedMaxStageDia>
+<CalculatedStageLen>0,347.5,1004.9,2155.23</CalculatedStageLen>
+<Cd3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd3>
+<Cd32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd32>
+<Cd321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd321>
+<Cb3>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb3>
+<Cb32>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb32>
+<Cb321>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb321>
+<CNa3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa3>
+<CNa32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa32>
+<CNa321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa321>
+<CP3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP3>
+<CP32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP32>
+<CP321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP321>
+<SimulationEventList>
+</SimulationEventList>
+<Stage3Parts>
+<NoseCone>
+<PartMfg>Aerospace Speciality Products</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Nose cone</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>42.6368</CalcMass>
+<CalcCG>76.0242</CalcCG>
+<WettedSurface>0.0152192</WettedSurface>
+<PaintedSurface>0.0152192</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>BNC80S</PartNo>
+<PartDesc><![CDATA[T-80H Balsa Nose Cone "S"]]></PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>1</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>2.</BarrowmanCNa>
+<BarrowmanXN>0.0296333</BarrowmanXN>
+<RockSimCNa>2.</RockSimCNa>
+<RockSimXN>0.0296333</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>0.</Station>
+<Len>88.9</Len>
+<BaseDia>66.</BaseDia>
+<FinishCode>0</FinishCode>
+<ShapeCode>3</ShapeCode>
+<ConstructionType>0</ConstructionType>
+<ShoulderLen>38.1</ShoulderLen>
+<WallThickness>0.</WallThickness>
+<ShapeParameter>0.</ShapeParameter>
+<ShoulderOD>65.9</ShoulderOD>
+<BaseExtensionLen>0.</BaseExtensionLen>
+<CoreDia>0.</CoreDia>
+<CoreLen>0.</CoreLen>
+<AttachedParts>
+<MassObject>
+<PartMfg>Custom</PartMfg>
+<KnownMass>20.</KnownMass>
+<Density>0.</Density>
+<Material>Custom</Material>
+<Name>Clay</Name>
+<KnownCG>17.8</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>17.8</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>0.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>2</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>17.8</Station>
+<TypeCode>0</TypeCode>
+<Len>0.</Len>
+<AttachedParts>
+</AttachedParts>
+</MassObject>
+<BodyTube>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Attachment Rod</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>6.1</Xb>
+<CalcMass>2.47301</CalcMass>
+<CalcCG>78.85</CalcCG>
+<WettedSurface>0.00684683</WettedSurface>
+<PaintedSurface>0.00684683</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>10062</PartNo>
+<PartDesc>13 mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>3</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>6.1</Station>
+<OD>13.82</OD>
+<ID>13.16</ID>
+<Len>157.7</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Plate</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>78.9</Xb>
+<CalcMass>7.86272</CalcMass>
+<CalcCG>1.585</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-(2)0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>4</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>85.</Station>
+<OD>66.</OD>
+<ID>13.82</ID>
+<Len>3.17</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>Custom</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1400.</Density>
+<Material>Carbon Fiber</Material>
+<Name>Sleeve </Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>17.5527</CalcMass>
+<CalcCG>13.85</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>5</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>2</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>136.1</Station>
+<OD>27.7</OD>
+<ID>13.82</ID>
+<Len>27.7</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>3</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Parachute>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>170.</KnownMass>
+<Density>0.006685</Density>
+<Material>Rip stop nylon</Material>
+<Name>Nose Cone Parachute</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>142.6</Xb>
+<CalcMass>15.8812</CalcMass>
+<CalcCG>34.5417</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>1</DensityType>
+<PartNo>LP-50</PartNo>
+<PartDesc>50 In. 16 lines</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>6</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>148.7</Station>
+<Dia>414.5</Dia>
+<SpillHoleDia>0.</SpillHoleDia>
+<SideCount>15</SideCount>
+<ShroudLineCount>16</ShroudLineCount>
+<Thickness>0.05</Thickness>
+<ShroudLineLen>1350.</ShroudLineLen>
+<ChuteCount>1</ChuteCount>
+<ShroudLineMassPerMM>0.00032972</ShroudLineMassPerMM>
+<ShroudLineMaterial>Carpet String (Apogee 29500)</ShroudLineMaterial>
+<DragCoefficient>0.95</DragCoefficient>
+<AttachedParts>
+</AttachedParts>
+</Parachute>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</NoseCone>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>15.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>100.</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>5.805</CalcMass>
+<CalcCG>100.</CalcCG>
+<WettedSurface>0.0414942</WettedSurface>
+<PaintedSurface>0.0414942</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3090</PartNo>
+<PartDesc>BT-80</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>7</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>88.9</Station>
+<OD>66.</OD>
+<ID>65.79</ID>
+<Len>200.</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>190.2</Xb>
+<CalcMass>7.65502</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>8</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>279.1</Station>
+<OD>65.02</OD>
+<ID>25.4</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>165.</Xb>
+<CalcMass>7.62626</CalcMass>
+<CalcCG>1.585</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-(2)0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>9</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>253.9</Station>
+<OD>65.</OD>
+<ID>25.4</ID>
+<Len>3.17</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<BodyTube>
+<PartMfg>Public Missiles Ltd.</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>958.705</Density>
+<Material>Kraft phenolic</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>137.9</Xb>
+<CalcMass>9.8818</CalcMass>
+<CalcCG>35.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>KS-1.1</PartNo>
+<PartDesc>KwikSwitch MMT 29mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>-1.58371</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>10</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>226.8</Station>
+<OD>32.26</OD>
+<ID>29.21</ID>
+<Len>70.</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>29.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+<LaunchLug>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Launch lug</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>77.2</Xb>
+<CalcMass>1.11942</CalcMass>
+<CalcCG>38.1</CalcCG>
+<WettedSurface>0.00374518</WettedSurface>
+<PaintedSurface>0.00199411</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>13056</PartNo>
+<PartDesc><![CDATA[1/4" X 3]]></PartDesc>
+<RadialLoc>37.185</RadialLoc>
+<RadialAngle>3.14</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>26</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>166.1</Station>
+<OD>8.33</OD>
+<ID>7.26</ID>
+<Len>76.2</Len>
+<FinishCode>0</FinishCode>
+<AttachedParts>
+</AttachedParts>
+</LaunchLug>
+<ExternalPod>
+<PartMfg>Custom</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>0.</Density>
+<Name>Pod</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>200.</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>0.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>36.175</RadialLoc>
+<RadialAngle>-1.50735</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>29</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>288.9</Station>
+<Detachable>1</Detachable>
+<AutoCalcRadialDistance>1</AutoCalcRadialDistance>
+<AutoCalcRadialAngle>1</AutoCalcRadialAngle>
+<AttachedParts>
+<BodyTube>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>958.705</Density>
+<Material>Kraft phenolic</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>0.400397</CalcMass>
+<CalcCG>29.3</CalcCG>
+<WettedSurface>0.00116902</WettedSurface>
+<PaintedSurface>0.00116902</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>9601</PartNo>
+<PartDesc>6 mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>30</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>288.9</Station>
+<OD>6.35</OD>
+<ID>5.59</ID>
+<Len>58.6</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</ExternalPod>
+</AttachedParts>
+</BodyTube>
+</Stage3Parts>
+<Stage2Parts>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>2nd Stage Tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>10.468</CalcMass>
+<CalcCG>180.34</CalcCG>
+<WettedSurface>0.0748306</WettedSurface>
+<PaintedSurface>0.0748306</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3090</PartNo>
+<PartDesc>BT-80</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>11</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>288.9</Station>
+<OD>66.</OD>
+<ID>65.79</ID>
+<Len>360.68</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>15.025</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Tube coupler</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>-10.</Xb>
+<CalcMass>20.465</CalcMass>
+<CalcCG>35.45</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TC-2.56</PartNo>
+<PartDesc>Tube Coupler</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>12</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>278.9</Station>
+<OD>65.79</OD>
+<ID>63.25</ID>
+<Len>70.9</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>4</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<MassObject>
+<PartMfg>Custom</PartMfg>
+<KnownMass>40.</KnownMass>
+<Density>0.</Density>
+<Material>Custom</Material>
+<Name>Electronics</Name>
+<KnownCG>138.3</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>138.3</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>0.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>13</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>427.2</Station>
+<TypeCode>0</TypeCode>
+<Len>0.</Len>
+<AttachedParts>
+</AttachedParts>
+</MassObject>
+<FinSet>
+<PartMfg>Quest</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Fin set</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>228.6</Xb>
+<CalcMass>1.32269</CalcMass>
+<CalcCG>19.05</CalcCG>
+<WettedSurface>0.0028791</WettedSurface>
+<PaintedSurface>0.0086373</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>Payloader One</PartNo>
+<PartDesc>Fin</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.0830777</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>14</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>2.95647</BarrowmanCNa>
+<BarrowmanXN>0.52856</BarrowmanXN>
+<RockSimCNa>5.54523</RockSimCNa>
+<RockSimXN>0.52856</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>517.5</Station>
+<FinCount>3</FinCount>
+<RootChord>38.1</RootChord>
+<TipChord>24.9</TipChord>
+<SemiSpan>45.7</SemiSpan>
+<MidChordLen>45.7</MidChordLen>
+<SweepDistance>6.6</SweepDistance>
+<Thickness>2.39</Thickness>
+<ShapeCode>0</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>2</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.139993</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>54.2541</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>2.86063</RockSimCNaPerFin>
+<TaperRatio>0.653543</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>302.</Xb>
+<CalcMass>7.65502</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>15</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>590.9</Station>
+<OD>65.02</OD>
+<ID>25.4</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>335.5</Xb>
+<CalcMass>7.62626</CalcMass>
+<CalcCG>1.585</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-(2)0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>16</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>624.4</Station>
+<OD>65.</OD>
+<ID>25.4</ID>
+<Len>3.17</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<BodyTube>
+<PartMfg>Public Missiles Ltd.</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>958.705</Density>
+<Material>Kraft phenolic</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>587.4</Xb>
+<CalcMass>9.8818</CalcMass>
+<CalcCG>35.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>KS-1.1</PartNo>
+<PartDesc>KwikSwitch MMT 29mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>-1.58371</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>17</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>1</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>587.4</Station>
+<OD>32.26</OD>
+<ID>29.21</ID>
+<Len>70.</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>29.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>Semroc</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Engine block</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>2.69315</CalcMass>
+<CalcCG>2.39</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TB-7</PartNo>
+<PartDesc>Thrust Block</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>18</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>587.4</Station>
+<OD>29.21</OD>
+<ID>14.61</ID>
+<Len>4.78</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>2</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+</AttachedParts>
+</BodyTube>
+<LaunchLug>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Launch lug</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>265.8</Xb>
+<CalcMass>1.11942</CalcMass>
+<CalcCG>38.1</CalcCG>
+<WettedSurface>0.00374518</WettedSurface>
+<PaintedSurface>0.00199411</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>13056</PartNo>
+<PartDesc><![CDATA[1/4" X 3]]></PartDesc>
+<RadialLoc>37.185</RadialLoc>
+<RadialAngle>1.22</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>27</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>554.7</Station>
+<OD>8.33</OD>
+<ID>7.26</ID>
+<Len>76.2</Len>
+<FinishCode>0</FinishCode>
+<AttachedParts>
+</AttachedParts>
+</LaunchLug>
+</AttachedParts>
+</BodyTube>
+</Stage2Parts>
+<Stage1Parts>
+<Transition>
+<PartMfg>BalsaMachining.com</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Transition</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>8.61936</CalcMass>
+<CalcCG>25.1551</CalcCG>
+<WettedSurface>0.0098623</WettedSurface>
+<PaintedSurface>0.0098623</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TA6080</PartNo>
+<PartDesc>Transition T60 to T80 2.25 in long</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>19</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>-1.213</BarrowmanCNa>
+<BarrowmanXN>0.675973</BarrowmanXN>
+<RockSimCNa>-1.213</RockSimCNa>
+<RockSimXN>0.675973</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>649.58</Station>
+<FrontDia>66.</FrontDia>
+<RearDia>41.4</RearDia>
+<Len>57.15</Len>
+<FinishCode>0</FinishCode>
+<FrontShoulderLen>20.</FrontShoulderLen>
+<RearShoulderLen>38.1</RearShoulderLen>
+<ConstructionType>1</ConstructionType>
+<WallThickness>3.</WallThickness>
+<FrontShoulderDia>64.77</FrontShoulderDia>
+<RearShoulderDia>41.38</RearShoulderDia>
+<CoreDia>0.</CoreDia>
+<ShapeCode>0</ShapeCode>
+<ShapeParameter>0.</ShapeParameter>
+<EquivNoseLen>153.339</EquivNoseLen>
+<EquivNoseOffset>96.1895</EquivNoseOffset>
+<AttachedParts>
+</AttachedParts>
+</Transition>
+<BodyTube>
+<PartMfg>LOC/Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>nan.</CalcCG>
+<WettedSurface>0.0544179</WettedSurface>
+<PaintedSurface>0.0544179</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC BT-2.14</PartNo>
+<PartDesc>Airframe tube</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>20</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>706.73</Station>
+<OD>41.4</OD>
+<ID>41.</ID>
+<Len>418.4</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<FinSet>
+<PartMfg>Quest</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Elliptical Fins</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>69.7</Xb>
+<CalcMass>36.2048</CalcMass>
+<CalcCG>46.</CalcCG>
+<WettedSurface>0.00676907</WettedSurface>
+<PaintedSurface>0.0203072</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>-0.519061</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>21</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>3.61024</BarrowmanCNa>
+<BarrowmanXN>0.802926</BarrowmanXN>
+<RockSimCNa>6.03948</RockSimCNa>
+<RockSimXN>0.802926</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>776.43</Station>
+<FinCount>3</FinCount>
+<RootChord>92.</RootChord>
+<TipChord>46.</TipChord>
+<SemiSpan>46.9</SemiSpan>
+<MidChordLen>46.9</MidChordLen>
+<SweepDistance>33.49</SweepDistance>
+<Thickness>3.18</Thickness>
+<ShapeCode>1</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>0</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.349066</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>41.5444</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>3.21868</RockSimCNaPerFin>
+<TaperRatio>0.5</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+<CustomFinSet>
+<PartMfg>Public Missiles</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1905.24</Density>
+<Material>G10 fiberglass</Material>
+<Name>Custom Fins</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>241.7</Xb>
+<CalcMass>256.292</CalcMass>
+<CalcCG>78.9922</CalcCG>
+<WettedSurface>0.0355266</WettedSurface>
+<PaintedSurface>0.10658</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>FIN-C-02</PartNo>
+<PartDesc>Fins</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.357967</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>22</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>25.7037</BarrowmanCNa>
+<BarrowmanXN>0.996526</BarrowmanXN>
+<RockSimCNa>34.1865</RockSimCNa>
+<RockSimXN>0.996822</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>948.43</Station>
+<FinCount>3</FinCount>
+<RootChord>152.4</RootChord>
+<TipChord>84.53</TipChord>
+<SemiSpan>146.72</SemiSpan>
+<MidChordLen>146.81</MidChordLen>
+<SweepDistance>39.07</SweepDistance>
+<Thickness>2.38</Thickness>
+<ShapeCode>2</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>2</TipShapeCode>
+<TabLength>101.6</TabLength>
+<TabDepth>10.6</TabDepth>
+<TabOffset>35.6</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>87.0529</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>19.7376</RockSimCNaPerFin>
+<TaperRatio>0.554659</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AverageChord>121.39</AverageChord>
+<EffectiveTipChord>84.5261</EffectiveTipChord>
+<PointList>152.4,0|126.202,146.715|36.455,146.715|0,0|</PointList>
+<AutoCalcGridStepX>0,0,0,0,0,0,0</AutoCalcGridStepX>
+<GridStepCountX>10,10,10,10,10,10,10</GridStepCountX>
+<UseAbsoluteGridStepsX>0,0,0,0,0,0,0</UseAbsoluteGridStepsX>
+<GridStepSizeX>0.5,10,0.5,0.5,0.00018939,0.001,1</GridStepSizeX>
+<SnapToSizeX>0.25,5,0.1,0.1,0.00018939,0.001,1</SnapToSizeX>
+<AutoCalcGridStepY>0,0,0,0,0,0,0</AutoCalcGridStepY>
+<GridStepCountY>10,10,10,10,10,10,10</GridStepCountY>
+<UseAbsoluteGridStepsY>0,0,0,0,0,0,0</UseAbsoluteGridStepsY>
+<GridStepSizeY>0.5,10,0.5,0.5,0.00018939,0.001,1</GridStepSizeY>
+<SnapToSizeY>0.25,5,0.1,0.1,0.00018939,0.001,1</SnapToSizeY>
+<AttachedParts>
+</AttachedParts>
+</CustomFinSet>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>379.5</Xb>
+<CalcMass>1.99074</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC FCR-1.52-1.14</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>23</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>1086.23</Station>
+<OD>41.4</OD>
+<ID>24.79</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>272.</Xb>
+<CalcMass>1.99074</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC FCR-1.52-1.14</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>24</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>978.73</Station>
+<OD>41.4</OD>
+<ID>24.79</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>259.7</Xb>
+<CalcMass>5.22902</CalcMass>
+<CalcCG>91.95</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3086</PartNo>
+<PartDesc>BT-50</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>25</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>966.43</Station>
+<OD>24.79</OD>
+<ID>24.13</ID>
+<Len>183.9</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>24.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+<TubeFinSet>
+<PartMfg>Custom</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Tube fins</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>12.6878</CalcMass>
+<CalcCG>24.79</CalcCG>
+<WettedSurface>0.0688063</WettedSurface>
+<PaintedSurface>0.0688063</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>35.395</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>28</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>10.866</BarrowmanCNa>
+<BarrowmanXN>0.707815</BarrowmanXN>
+<RockSimCNa>10.866</RockSimCNa>
+<RockSimXN>0.707815</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>706.73</Station>
+<OD>24.79</OD>
+<ID>24.13</ID>
+<Len>49.58</Len>
+<FinishCode>0</FinishCode>
+<TubeCount>9</TubeCount>
+<MinTubeAngle>0.715549</MinTubeAngle>
+<MaxTubesAllowed>9</MaxTubesAllowed>
+<AttachedParts>
+</AttachedParts>
+</TubeFinSet>
+<RingTail>
+<PartMfg>Custom</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>688.794</Density>
+<Material>Cardboard</Material>
+<Name>Ringtail</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>2.93707</CalcMass>
+<CalcCG>10.</CalcCG>
+<WettedSurface>0.00474229</WettedSurface>
+<PaintedSurface>0.00444249</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>31</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>2</LocationMode>
+<Color>rgb(255,9,18)</Color>
+<BarrowmanCNa>39.6386</BarrowmanCNa>
+<BarrowmanXN>1.10463</BarrowmanXN>
+<RockSimCNa>39.6386</RockSimCNa>
+<RockSimXN>1.10463</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>1105.13</Station>
+<FinCount>3</FinCount>
+<RootChord>20.</RootChord>
+<TipChord>20.</TipChord>
+<SemiSpan>7.495</SemiSpan>
+<MidChordLen>7.495</MidChordLen>
+<SweepDistance>0.</SweepDistance>
+<Thickness>3.</Thickness>
+<ShapeCode>0</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>0</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>0.</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>0.</RockSimCNaPerFin>
+<TaperRatio>0.</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<OD>56.39</OD>
+<ID>55.37</ID>
+<Len>20.</Len>
+<TubeDensity>1121.29</TubeDensity>
+<TubeDensityType>0</TubeDensityType>
+<TubeMaterial>Paper</TubeMaterial>
+<AttachedParts>
+</AttachedParts>
+</RingTail>
+<Streamer>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1309.</Density>
+<Material>Mylar</Material>
+<Name>Streamer</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>149.4</Xb>
+<CalcMass>5.67514</CalcMass>
+<CalcCG>50.8</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>29006</PartNo>
+<PartDesc><![CDATA[4" Wide Mylar]]></PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>32</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>856.13</Station>
+<Len>1422.4</Len>
+<Width>101.6</Width>
+<Thickness>0.03</Thickness>
+<StreamerCount>1</StreamerCount>
+<DragCoefficient>0.127</DragCoefficient>
+<IsFolded>0</IsFolded>
+<AutoCalcCd>1</AutoCalcCd>
+<AttachedParts>
+</AttachedParts>
+</Streamer>
+</AttachedParts>
+</BodyTube>
+</Stage1Parts>
+<SideViewDims>
+</SideViewDims>
+<BaseViewDims>
+</BaseViewDims>
+<VertViewDims>
+</VertViewDims>
+</RocketDesign>
+</DesignInformation>
+<SimulationResultsList>
+</SimulationResultsList>
+</RockSimDocument>
diff --git a/test/net/sf/openrocket/file/rocksim/rocksimTestRocket1.rkt b/test/net/sf/openrocket/file/rocksim/rocksimTestRocket1.rkt
deleted file mode 100644 (file)
index 79f7b00..0000000
+++ /dev/null
@@ -1,743 +0,0 @@
-<RockSimDocument>
-<FileVersion>3</FileVersion>
-<DesignInformation>
-<RocketDesign>
-    <Name>FooBar Test</Name>
-<CalculateCD>1</CalculateCD>
-<ProCalculateCD>1</ProCalculateCD>
-<ProCalculateCN>1</ProCalculateCN>
-<FixedCd>0.75</FixedCd>
-<FixedCd2>0.8</FixedCd2>
-<FixedCd3>0.81</FixedCd3>
-<FixedCd2Alone>0.95</FixedCd2Alone>
-<FixedCd3Alone>0.95</FixedCd3Alone>
-<StageCount>1</StageCount>
-<Stage3Mass>0.</Stage3Mass>
-<Stage2Mass>0.</Stage2Mass>
-<Stage1Mass>0.</Stage1Mass>
-<Stage321CG>0.</Stage321CG>
-<Stage32CG>0.</Stage32CG>
-<Stage3CG>0.</Stage3CG>
-<Stage2CGAlone>0.</Stage2CGAlone>
-<Stage1CGAlone>0.</Stage1CGAlone>
-<CPCalcFlags>1</CPCalcFlags>
-<LaunchGuideLength>914.4</LaunchGuideLength>
-<UseKnownMass>0</UseKnownMass>
-<DefaultFinish>0</DefaultFinish>
-<FinishMedium>0</FinishMedium>
-<FinishCoatCount>1</FinishCoatCount>
-<GlueType>0</GlueType>
-<CPSimFlags>1</CPSimFlags>
-<LastSerialNumber>11</LastSerialNumber>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<BarromanXN>0,1215.49,0,0</BarromanXN>
-<BarrowmanCNa>0,35.9506,0,0</BarrowmanCNa>
-<RockSimXN>0,1226.38,0,0</RockSimXN>
-<RockSimCNa>0,47.5027,0,0</RockSimCNa>
-<RockSimCNa90>0,0,0,0</RockSimCNa90>
-<RockSimXN90>0,0,0,0</RockSimXN90>
-<ViewType>0</ViewType>
-<ViewStageCount>1</ViewStageCount>
-<ViewTypeEdit>0</ViewTypeEdit>
-<ViewStageCountEdit>1</ViewStageCountEdit>
-<ZoomFactor>0.</ZoomFactor>
-<ZoomFactorEdit>0.</ZoomFactorEdit>
-<ScrollPosX>0</ScrollPosX>
-<ScrollPosY>0</ScrollPosY>
-<ScrollPosXEdit>0</ScrollPosXEdit>
-<ScrollPosYEdit>0</ScrollPosYEdit>
-<ThreeDFlags>0</ThreeDFlags>
-<ThreeDFlagsEdit>0</ThreeDFlagsEdit>
-<UseModelSprite>0</UseModelSprite>
-<StaticMarginRef>0</StaticMarginRef>
-<UserRefDiameter>0.</UserRefDiameter>
-<SideMarkerHeight>10.</SideMarkerHeight>
-<SideDimensionHeight>10.</SideDimensionHeight>
-<BaseMarkerHeight>10.</BaseMarkerHeight>
-<BaseDimensionHeight>10.</BaseDimensionHeight>
-<ShowGlideCP>0</ShowGlideCP>
-<ShowGridTypeSide>0</ShowGridTypeSide>
-<ShowGridTypeBase>0</ShowGridTypeBase>
-<GridSpacing>10.</GridSpacing>
-<GridOpacity>0.15</GridOpacity>
-<GridColor>black</GridColor>
-<MaxDiaWithFins>424.688</MaxDiaWithFins>
-<MaxDiaWithoutFins>66.04</MaxDiaWithoutFins>
-<MaxLenWithFins>1417.95</MaxLenWithFins>
-<MaxLenWithoutFins>1332.23</MaxLenWithoutFins>
-<MinXExtent>0.</MinXExtent>
-<MaxXExtent>1417.95</MaxXExtent>
-<CalculatedMaxStageDia>0,66.04,0,0</CalculatedMaxStageDia>
-<CalculatedStageLen>0,1332.23,0,0</CalculatedStageLen>
-<Cd3>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cd3>
-<Cd32>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cd32>
-<Cd321>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cd321>
-<Cb3>
-<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cb3>
-<Cb32>
-<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cb32>
-<Cb321>
-<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cb321>
-<CNa3>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CNa3>
-<CNa32>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CNa32>
-<CNa321>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CNa321>
-<CP3>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CP3>
-<CP32>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CP32>
-<CP321>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CP321>
-<SimulationEventList>
-</SimulationEventList>
-<Stage3Parts>
-<NoseCone>
-<PartMfg>Apogee</PartMfg>
-<KnownMass>24.1</KnownMass>
-<Density>1049.21</Density>
-<Material>Polystyrene PS</Material>
-<Name>Nose cone</Name>
-<KnownCG>65.3999</KnownCG>
-<UseKnownCG>1</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>126.438</CalcMass>
-<CalcCG>348.443</CalcCG>
-<WettedSurface>0.0356487</WettedSurface>
-<PaintedSurface>0.0356487</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>19470</PartNo>
-<PartDesc>PNC-70A</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>2</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>2.</BarrowmanCNa>
-<BarrowmanXN>0.264319</BarrowmanXN>
-<RockSimCNa>2.</RockSimCNa>
-<RockSimXN>0.264319</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>0.</Station>
-<Len>396.875</Len>
-<BaseDia>57.15</BaseDia>
-<FinishCode>0</FinishCode>
-<ShapeCode>0</ShapeCode>
-<ConstructionType>1</ConstructionType>
-<ShoulderLen>58.3997</ShoulderLen>
-<WallThickness>2.159</WallThickness>
-<ShapeParameter>0.</ShapeParameter>
-<ShoulderOD>53.1012</ShoulderOD>
-<BaseExtensionLen>66.675</BaseExtensionLen>
-<CoreDia>0.</CoreDia>
-<CoreLen>0.</CoreLen>
-<AttachedParts>
-</AttachedParts>
-</NoseCone>
-<BodyTube>
-<PartMfg>Estes</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>10.636</CalcMass>
-<CalcCG>180.34</CalcCG>
-<WettedSurface>0.0748306</WettedSurface>
-<PaintedSurface>0.0748306</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>EST 3090</PartNo>
-<PartDesc>BT-80</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>3</SerialNo>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>463.55</Station>
-<OD>66.04</OD>
-<ID>65.786</ID>
-<Len>360.68</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>0.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>0</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-</AttachedParts>
-</BodyTube>
-<Transition>
-<PartMfg>BalsaMachining.com</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>128.148</Density>
-<Material>Balsa</Material>
-<Name>Transition</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>39.355</CalcMass>
-<CalcCG>37.0332</CalcCG>
-<WettedSurface>0.0096001</WettedSurface>
-<PaintedSurface>0.0096001</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>TA7080</PartNo>
-<PartDesc>Transition T70 to T80 2 in long</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>7</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>-0.92852</BarrowmanCNa>
-<BarrowmanXN>0.848729</BarrowmanXN>
-<RockSimCNa>-0.92852</RockSimCNa>
-<RockSimXN>0.848729</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>824.23</Station>
-<FrontDia>66.04</FrontDia>
-<RearDia>53.34</RearDia>
-<Len>50.8</Len>
-<FinishCode>0</FinishCode>
-<FrontShoulderLen>35.56</FrontShoulderLen>
-<RearShoulderLen>35.56</RearShoulderLen>
-<ConstructionType>0</ConstructionType>
-<WallThickness>0.</WallThickness>
-<FrontShoulderDia>55.118</FrontShoulderDia>
-<RearShoulderDia>53.34</RearShoulderDia>
-<CoreDia>0.</CoreDia>
-<ShapeCode>0</ShapeCode>
-<ShapeParameter>0.</ShapeParameter>
-<EquivNoseLen>264.12</EquivNoseLen>
-<EquivNoseOffset>213.32</EquivNoseOffset>
-<AttachedParts>
-</AttachedParts>
-</Transition>
-<BodyTube>
-<PartMfg>Estes</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>44.449</CalcMass>
-<CalcCG>222.25</CalcCG>
-<WettedSurface>0.0787423</WettedSurface>
-<PaintedSurface>0.0787423</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>Estes</PartNo>
-<PartDesc>BT-70</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>8</SerialNo>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>875.03</Station>
-<OD>56.388</OD>
-<ID>55.372</ID>
-<Len>444.5</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>0.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>0</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<FinSet>
-<PartMfg>Public Missiles</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1905.24</Density>
-<Material>G10 fiberglass</Material>
-<Name>Fin set</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>260.35</Xb>
-<CalcMass>153.85</CalcMass>
-<CalcCG>155.575</CalcCG>
-<WettedSurface>0.0339112</WettedSurface>
-<PaintedSurface>0.101734</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>FIN-A-01</PartNo>
-<PartDesc>Fins</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>9</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>34.8792</BarrowmanCNa>
-<BarrowmanXN>1.26026</BarrowmanXN>
-<RockSimCNa>46.4312</RockSimCNa>
-<RockSimXN>1.26026</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>1135.38</Station>
-<FinCount>3</FinCount>
-<RootChord>184.15</RootChord>
-<TipChord>0.</TipChord>
-<SemiSpan>184.15</SemiSpan>
-<MidChordLen>264.956</MidChordLen>
-<SweepDistance>282.575</SweepDistance>
-<Thickness>1.5875</Thickness>
-<ShapeCode>0</ShapeCode>
-<FinishCode>0</FinishCode>
-<TipShapeCode>0</TipShapeCode>
-<TabLength>0.</TabLength>
-<TabDepth>0.</TabDepth>
-<TabOffset>0.</TabOffset>
-<SweepMode>1</SweepMode>
-<SweepAngle>0.990003</SweepAngle>
-<RockSimXNPerFin>0.</RockSimXNPerFin>
-<RockSimRadialXNPerFin>89.5773</RockSimRadialXNPerFin>
-<RockSimCNaPerFin>26.8071</RockSimCNaPerFin>
-<TaperRatio>0.</TaperRatio>
-<CantAngle>0.</CantAngle>
-<CantPivotPoint>0.</CantPivotPoint>
-<AttachedParts>
-</AttachedParts>
-</FinSet>
-<BodyTube>
-<PartMfg>Estes</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>13.008</CalcMass>
-<CalcCG>228.6</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>EST 3086</PartNo>
-<PartDesc>BT-50</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>11</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>875.03</Station>
-<OD>24.7904</OD>
-<ID>24.13</ID>
-<Len>457.2</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>1</IsMotorMount>
-<MotorDia>24.</MotorDia>
-<EngineOverhang>12.7</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>1</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-</AttachedParts>
-</BodyTube>
-</AttachedParts>
-</BodyTube>
-</Stage3Parts>
-<Stage2Parts>
-</Stage2Parts>
-<Stage1Parts>
-</Stage1Parts>
-<SideViewDims>
-</SideViewDims>
-<BaseViewDims>
-</BaseViewDims>
-<VertViewDims>
-</VertViewDims>
-</RocketDesign>
-</DesignInformation>
-<SimulationResultsList>
-<SimulationResults>
-<MaxAltitude>445.129</MaxAltitude>
-<MaxVelocity>68.7587</MaxVelocity>
-<MaxAcceleration>76.6476</MaxAcceleration>
-<TimeToApogee>10.8263</TimeToApogee>
-<OptimalDelay>4.765</OptimalDelay>
-<MultiDelayCount>1</MultiDelayCount>
-<VelocityAtDeplyment>33.4284</VelocityAtDeplyment>
-<AltitudeAtDeployment>405.535</AltitudeAtDeployment>
-<DelayTime>2</DelayTime>
-<EjectTime>8.06125</EjectTime>
-<FinalState>4</FinalState>
-<TimeToBurnout>6.06125</TimeToBurnout>
-<TimeToLanding>22.4787</TimeToLanding>
-<TimeToEject>8.06125</TimeToEject>
-<MinLaunchGuideLen>1.35915</MinLaunchGuideLen>
-<MaxVertVelocity>65.9349</MaxVertVelocity>
-<MaxHorzVelocity>1.0686</MaxHorzVelocity>
-<MaxVertAcceleration>76.5426</MaxVertAcceleration>
-<MaxHorzAcceleration>4.01173</MaxHorzAcceleration>
-<MaxRange>172.076</MaxRange>
-<LaunchStartVelocity>0.</LaunchStartVelocity>
-<LaunchStartRollRate>0.</LaunchStartRollRate>
-<LaunchGuideType>0</LaunchGuideType>
-<LaunchGuideLen>1828.8</LaunchGuideLen>
-<LaunchWindDirection>0</LaunchWindDirection>
-<LaunchWindSpeed>0.</LaunchWindSpeed>
-<LaunchDirection>0</LaunchDirection>
-<LaunchAngle>0.0523599</LaunchAngle>
-<LaunchGuideAzimuth>0.</LaunchGuideAzimuth>
-<LaunchGuideElevation>0.</LaunchGuideElevation>
-<LaunchBarometer>770.314</LaunchBarometer>
-<LaunchLatitude>43.</LaunchLatitude>
-<LaunchLongitude>0.</LaunchLongitude>
-<LaunchHumidity>70.</LaunchHumidity>
-<LaunchTemperature>7.22222</LaunchTemperature>
-<LaunchAltitude>304.8</LaunchAltitude>
-<LaunchLandingAltitude>0.</LaunchLandingAltitude>
-<CompStateMask>0</CompStateMask>
-<LaunchWindPreset>3</LaunchWindPreset>
-<LaunchWindLowSpeed>1.34112</LaunchWindLowSpeed>
-<LaunchWindHighSpeed>3.53162</LaunchWindHighSpeed>
-<LaunchWindTurbulencePreset>2</LaunchWindTurbulencePreset>
-<LaunchWindFrequency>0.01</LaunchWindFrequency>
-<LaunchWindDeltaFrequency>0.02</LaunchWindDeltaFrequency>
-<LaunchUseRandomConditions>0</LaunchUseRandomConditions>
-<LaunchCloudCoverPreset>5</LaunchCloudCoverPreset>
-<LaunchCCLow>0.</LaunchCCLow>
-<LaunchCCHigh>0.1</LaunchCCHigh>
-<LaunchThermalPosPreset>1</LaunchThermalPosPreset>
-<LaunchThermalPos>0.</LaunchThermalPos>
-<LaunchMultipleThermals>0</LaunchMultipleThermals>
-<LaunchMaxThermals>3</LaunchMaxThermals>
-<LaunchThermalDia>300.</LaunchThermalDia>
-<LaunchThermalHeight>2000.</LaunchThermalHeight>
-<LaunchThermalSpeedPreset>1</LaunchThermalSpeedPreset>
-<LaunchThermalSpeed>5.99999</LaunchThermalSpeed>
-<LaunchWindTableSize>0</LaunchWindTableSize>
-<LaunchWindAltTable>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</LaunchWindAltTable>
-<LaunchWindSpeedTable>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</LaunchWindSpeedTable>
-<LaunchWindDirectionTable>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</LaunchWindDirectionTable>
-<LaunchLossPreset>2</LaunchLossPreset>
-<LaunchLossPercent>0.99</LaunchLossPercent>
-<LaunchSiteDia>2000.</LaunchSiteDia>
-<LaunchDriftRangeToLoss>1500.</LaunchDriftRangeToLoss>
-<LaunchPayloadDamagePreset>2</LaunchPayloadDamagePreset>
-<LaunchPayloadDamagePercent>0.98</LaunchPayloadDamagePercent>
-<LaunchEngineMisfirePreset>1</LaunchEngineMisfirePreset>
-<LaunchEngineMisfirePercent>0.</LaunchEngineMisfirePercent>
-<LaunchVariableIgnitionDelay>0</LaunchVariableIgnitionDelay>
-<LaunchVariableIgnitionDelaySec>0.08</LaunchVariableIgnitionDelaySec>
-<LaunchRecDeviceFailurePreset>1</LaunchRecDeviceFailurePreset>
-<LaunchRecDeviceFailurePercent>0.</LaunchRecDeviceFailurePercent>
-<LaunchAriframeFailurePreset>1</LaunchAriframeFailurePreset>
-<LaunchAirframeFailurePercent>0.</LaunchAirframeFailurePercent>
-<LaunchTrackLossPreset>1</LaunchTrackLossPreset>
-<LaunchTeckLossPercent>0.</LaunchTeckLossPercent>
-<CNaMultiplier>1.</CNaMultiplier>
-<CdMultiplier>1.</CdMultiplier>
-<CPOffset>0.</CPOffset>
-<SaveSimAsText>0</SaveSimAsText>
-<OutputAtMaxRes>0</OutputAtMaxRes>
-<MaxSimTim>3600.</MaxSimTim>
-<MassUncertainty>0.</MassUncertainty>
-<MOIUncertainty>0.</MOIUncertainty>
-<CGUncertainty>0.</CGUncertainty>
-<CdUncertainty>0.</CdUncertainty>
-<CnaUncertainty>0.</CnaUncertainty>
-<CPUncertainty>0.</CPUncertainty>
-<FinCantUncertainty>0.</FinCantUncertainty>
-<TotImpulseUncertainty>0.</TotImpulseUncertainty>
-<PropellantUncertainty>0.</PropellantUncertainty>
-<ThrustAxisUncertainty>0.</ThrustAxisUncertainty>
-<WindDirectionUncertainty>0.</WindDirectionUncertainty>
-<WindVelocityUncertainty>0.</WindVelocityUncertainty>
-<LaunchGuideAzimuthUncertainty>0.</LaunchGuideAzimuthUncertainty>
-<LaunchGuideElevationUncertainty>0.</LaunchGuideElevationUncertainty>
-<IgnitionUncertainty>0.</IgnitionUncertainty>
-<CATOUncertainty>0.</CATOUncertainty>
-<DeploymentUncertainty>0.</DeploymentUncertainty>
-<RecoveryDeviceUncertainty>0.</RecoveryDeviceUncertainty>
-<SimulationName>[E6-2] </SimulationName>
-<VelocityAtLaunchGuideEnd>15.4098</VelocityAtLaunchGuideEnd>
-<WindStartAltitude>0.</WindStartAltitude>
-<TimeToWindShear>0.</TimeToWindShear>
-<TimeToFreeFlight>0.25875</TimeToFreeFlight>
-<TimeToMaxVelocity>5.69125</TimeToMaxVelocity>
-<TimeToMaxAcceleration>0.11125</TimeToMaxAcceleration>
-<Nsims>10</Nsims>
-<CalcResolution>1</CalcResolution>
-<SamplesPerSecond>800.</SamplesPerSecond>
-<SimulationType>0</SimulationType>
-<LocationDataServerName>Earth</LocationDataServerName>
-<LocationDataServerDisplayName>Standard earth condistions.</LocationDataServerDisplayName>
-<ExecutionTime>4.078</ExecutionTime>
-<RangeAtLanding>-172.076</RangeAtLanding>
-<DirectionAtLanding>0.</DirectionAtLanding>
-<VelocityAtLanding>56.537</VelocityAtLanding>
-<XVelcoityAtLanding>-3.38254</XVelcoityAtLanding>
-<YVelocityAtLanding>-56.4357</YVelocityAtLanding>
-<ZVelocityAtLanding>0.</ZVelocityAtLanding>
-<StageSeparationTime>0,0,8.06125,0,0</StageSeparationTime>
-<StageEjectTime>-1,-1,-1,-1,-1</StageEjectTime>
-<TimeToDeployment>0,0,0,0,0</TimeToDeployment>
-<DeploymentType>32,32,32,32,32</DeploymentType>
-<SamplesPerSecondDescent>1.</SamplesPerSecondDescent>
-<CalculationFlags>1</CalculationFlags>
-<Mass0>0.233111</Mass0>
-<CG0>0.739954</CG0>
-<LaterialMOI0>0.0208295</LaterialMOI0>
-<RadialMOI0>0.000194272</RadialMOI0>
-<GUID>{b33e529e-1ada-4524-9885-7382d7cf4d64}</GUID>
-<Booster1Staging>
-<SimulationEvent>
-<PartSerialNo>0</PartSerialNo>
-<Type>0</Type>
-<DeployAltitude>0.</DeployAltitude>
-<DeplyTime>0.</DeplyTime>
-<HasDeployed>0</HasDeployed>
-<DeployedAt_Altitude>0.</DeployedAt_Altitude>
-<DeployedAt_Velocity>0.</DeployedAt_Velocity>
-<DeployedAt_Range>0.</DeployedAt_Range>
-<DeployedAt_Time>0.</DeployedAt_Time>
-<DeviceID>-1</DeviceID>
-<TestType>0,0,0</TestType>
-<TestCondition>0,0,0</TestCondition>
-<TestValueAltitude>0,0,0</TestValueAltitude>
-<TestValueDegrees>0,0,0</TestValueDegrees>
-<TestValuePressure>0,0,0</TestValuePressure>
-<TestValueMach>0,0,0</TestValueMach>
-<TestValueTime>0,0,0</TestValueTime>
-<TestValueQ>0,0,0</TestValueQ>
-</SimulationEvent>
-</Booster1Staging>
-<Booster2Staging>
-<SimulationEvent>
-<PartSerialNo>0</PartSerialNo>
-<Type>0</Type>
-<DeployAltitude>0.</DeployAltitude>
-<DeplyTime>0.</DeplyTime>
-<HasDeployed>0</HasDeployed>
-<DeployedAt_Altitude>0.</DeployedAt_Altitude>
-<DeployedAt_Velocity>0.</DeployedAt_Velocity>
-<DeployedAt_Range>0.</DeployedAt_Range>
-<DeployedAt_Time>0.</DeployedAt_Time>
-<DeviceID>-1</DeviceID>
-<TestType>0,0,0</TestType>
-<TestCondition>0,0,0</TestCondition>
-<TestValueAltitude>0,0,0</TestValueAltitude>
-<TestValueDegrees>0,0,0</TestValueDegrees>
-<TestValuePressure>0,0,0</TestValuePressure>
-<TestValueMach>0,0,0</TestValueMach>
-<TestValueTime>0,0,0</TestValueTime>
-<TestValueQ>0,0,0</TestValueQ>
-</SimulationEvent>
-</Booster2Staging>
-<SimulationEvents>
-</SimulationEvents>
-<Stage1Engines>
-</Stage1Engines>
-<Stage2Engines>
-</Stage2Engines>
-<Stage3Engines>
-<EngineSet>
-<EngineCount>1</EngineCount>
-<EngineCode>E6</EngineCode>
-<IgnitionDelay>0.</IgnitionDelay>
-<EngineMfg>Apogee</EngineMfg>
-<EngineOverhang>0.50038</EngineOverhang>
-<CasingCG>0.</CasingCG>
-<MountSerialNo>5</MountSerialNo>
-<EjectionDelay>2.</EjectionDelay>
-<RotateXaboutY>0.</RotateXaboutY>
-<RotateEngineAxisAboutX>0.</RotateEngineAxisAboutX>
-</EngineSet>
-</Stage3Engines>
-<DropItems>
-</DropItems>
-</SimulationResults>
-</SimulationResultsList>
-</RockSimDocument>
diff --git a/test/net/sf/openrocket/file/rocksim/rocksimTestRocket2.rkt b/test/net/sf/openrocket/file/rocksim/rocksimTestRocket2.rkt
deleted file mode 100644 (file)
index 39b3411..0000000
+++ /dev/null
@@ -1,1583 +0,0 @@
-<RockSimDocument>
-<FileVersion>3</FileVersion>
-<DesignInformation>
-<RocketDesign>
-<Name>Three Stage Everything Included Rocket</Name>
-<CalculateCD>1</CalculateCD>
-<ProCalculateCD>1</ProCalculateCD>
-<ProCalculateCN>1</ProCalculateCN>
-<FixedCd>0.75</FixedCd>
-<FixedCd2>0.8</FixedCd2>
-<FixedCd3>0.81</FixedCd3>
-<FixedCd2Alone>0.95</FixedCd2Alone>
-<FixedCd3Alone>0.95</FixedCd3Alone>
-<StageCount>3</StageCount>
-<Stage3Mass>0.</Stage3Mass>
-<Stage2Mass>0.</Stage2Mass>
-<Stage1Mass>0.</Stage1Mass>
-<Stage321CG>0.</Stage321CG>
-<Stage32CG>0.</Stage32CG>
-<Stage3CG>0.</Stage3CG>
-<Stage2CGAlone>0.</Stage2CGAlone>
-<Stage1CGAlone>0.</Stage1CGAlone>
-<CPCalcFlags>1</CPCalcFlags>
-<LaunchGuideLength>914.4</LaunchGuideLength>
-<UseKnownMass>0</UseKnownMass>
-<DefaultFinish>0</DefaultFinish>
-<FinishMedium>0</FinishMedium>
-<FinishCoatCount>1</FinishCoatCount>
-<GlueType>0</GlueType>
-<CPSimFlags>1</CPSimFlags>
-<LastSerialNumber>25</LastSerialNumber>
-<DisplayFlags>7</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<BarromanXN>0,29.6333,326.159,887.03</BarromanXN>
-<BarrowmanCNa>0,2,4.93008,33.0782</BarrowmanCNa>
-<RockSimXN>0,29.6333,384.174,883.929</RockSimXN>
-<RockSimCNa>0,2,6.91103,47.1184</RockSimCNa>
-<RockSimCNa90>0,0,0,0</RockSimCNa90>
-<RockSimXN90>0,0,0,0</RockSimXN90>
-<ViewType>0</ViewType>
-<ViewStageCount>3</ViewStageCount>
-<ViewTypeEdit>0</ViewTypeEdit>
-<ViewStageCountEdit>3</ViewStageCountEdit>
-<ZoomFactor>0.</ZoomFactor>
-<ZoomFactorEdit>0.</ZoomFactorEdit>
-<ScrollPosX>0</ScrollPosX>
-<ScrollPosY>0</ScrollPosY>
-<ScrollPosXEdit>0</ScrollPosXEdit>
-<ScrollPosYEdit>0</ScrollPosYEdit>
-<ThreeDFlags>0</ThreeDFlags>
-<ThreeDFlagsEdit>0</ThreeDFlagsEdit>
-<UseModelSprite>0</UseModelSprite>
-<StaticMarginRef>0</StaticMarginRef>
-<UserRefDiameter>0.</UserRefDiameter>
-<SideMarkerHeight>10.</SideMarkerHeight>
-<SideDimensionHeight>10.</SideDimensionHeight>
-<BaseMarkerHeight>10.</BaseMarkerHeight>
-<BaseDimensionHeight>10.</BaseDimensionHeight>
-<ShowGlideCP>0</ShowGlideCP>
-<ShowGridTypeSide>0</ShowGridTypeSide>
-<ShowGridTypeBase>0</ShowGridTypeBase>
-<GridSpacing>10.</GridSpacing>
-<GridOpacity>0.15</GridOpacity>
-<GridColor>black</GridColor>
-<MaxDiaWithFins>339.43</MaxDiaWithFins>
-<MaxDiaWithoutFins>66.3</MaxDiaWithoutFins>
-<MaxLenWithFins>2104.53</MaxLenWithFins>
-<MaxLenWithoutFins>2104.53</MaxLenWithoutFins>
-<MinXExtent>0.</MinXExtent>
-<MaxXExtent>1150.33</MaxXExtent>
-<CalculatedMaxStageDia>0,66.3,66.3,66.3</CalculatedMaxStageDia>
-<CalculatedStageLen>0,296.8,954.2,2104.53</CalculatedStageLen>
-<Cd3>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cd3>
-<Cd32>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cd32>
-<Cd321>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cd321>
-<Cb3>
-<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cb3>
-<Cb32>
-<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cb32>
-<Cb321>
-<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cb321>
-<CNa3>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CNa3>
-<CNa32>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CNa32>
-<CNa321>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CNa321>
-<CP3>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CP3>
-<CP32>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CP32>
-<CP321>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CP321>
-<SimulationEventList>
-</SimulationEventList>
-<Stage3Parts>
-<NoseCone>
-<PartMfg>Aerospace Speciality Products</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>128.148</Density>
-<Material>Balsa</Material>
-<Name>Nose cone</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>42.0747</CalcMass>
-<CalcCG>75.3029</CalcCG>
-<WettedSurface>0.0152945</WettedSurface>
-<PaintedSurface>0.0152945</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>BNC80S</PartNo>
-<PartDesc><![CDATA[T-80H Balsa Nose Cone "S"]]></PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>1</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>2.</BarrowmanCNa>
-<BarrowmanXN>0.0296333</BarrowmanXN>
-<RockSimCNa>2.</RockSimCNa>
-<RockSimXN>0.0296333</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>0.</Station>
-<Len>88.9</Len>
-<BaseDia>66.3</BaseDia>
-<FinishCode>0</FinishCode>
-<ShapeCode>3</ShapeCode>
-<ConstructionType>0</ConstructionType>
-<ShoulderLen>38.1</ShoulderLen>
-<WallThickness>0.</WallThickness>
-<ShapeParameter>0.</ShapeParameter>
-<ShoulderOD>64.3</ShoulderOD>
-<BaseExtensionLen>0.</BaseExtensionLen>
-<CoreDia>0.</CoreDia>
-<CoreLen>0.</CoreLen>
-<AttachedParts>
-<MassObject>
-<PartMfg>Custom</PartMfg>
-<KnownMass>20.</KnownMass>
-<Density>0.</Density>
-<Material>Custom</Material>
-<Name>Clay</Name>
-<KnownCG>17.8</KnownCG>
-<UseKnownCG>1</UseKnownCG>
-<Xb>17.8</Xb>
-<CalcMass>0.</CalcMass>
-<CalcCG>0.</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>2</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>17.8</Station>
-<TypeCode>0</TypeCode>
-<Len>0.</Len>
-<AttachedParts>
-</AttachedParts>
-</MassObject>
-<BodyTube>
-<PartMfg>Apogee</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Attachment Rod</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>6.1</Xb>
-<CalcMass>2.47301</CalcMass>
-<CalcCG>78.85</CalcCG>
-<WettedSurface>0.00684683</WettedSurface>
-<PaintedSurface>0.00684683</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>10062</PartNo>
-<PartDesc>13 mm</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>3</SerialNo>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>6.1</Station>
-<OD>13.82</OD>
-<ID>13.16</ID>
-<Len>157.7</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>0.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>1</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Plate</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>78.9</Xb>
-<CalcMass>7.86272</CalcMass>
-<CalcCG>1.585</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC CR-2.56-(2)0.95</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>4</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>85.</Station>
-<OD>66.</OD>
-<ID>13.82</ID>
-<Len>3.17</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>0</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<Ring>
-<PartMfg>Custom</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1400.</Density>
-<Material>Carbon Fiber</Material>
-<Name>Sleeve </Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>17.5527</CalcMass>
-<CalcCG>13.85</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>5</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>2</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>136.1</Station>
-<OD>27.7</OD>
-<ID>13.82</ID>
-<Len>27.7</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>3</UsageCode>
-<AutoSize>0</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<Parachute>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>170.</KnownMass>
-<Density>0.006685</Density>
-<Material>Rip stop nylon</Material>
-<Name>Nose Cone Parachute</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>1</UseKnownCG>
-<Xb>142.6</Xb>
-<CalcMass>15.8812</CalcMass>
-<CalcCG>34.5417</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>1</DensityType>
-<PartNo>LP-50</PartNo>
-<PartDesc>50 In. 16 lines</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>6</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>148.7</Station>
-<Dia>414.5</Dia>
-<SpillHoleDia>0.</SpillHoleDia>
-<SideCount>15</SideCount>
-<ShroudLineCount>16</ShroudLineCount>
-<Thickness>0.05</Thickness>
-<ShroudLineLen>1350.</ShroudLineLen>
-<ChuteCount>1</ChuteCount>
-<ShroudLineMassPerMM>0.00032972</ShroudLineMassPerMM>
-<ShroudLineMaterial>Carpet String (Apogee 29500)</ShroudLineMaterial>
-<DragCoefficient>0.95</DragCoefficient>
-<AttachedParts>
-</AttachedParts>
-</Parachute>
-</AttachedParts>
-</BodyTube>
-</AttachedParts>
-</NoseCone>
-<BodyTube>
-<PartMfg>Estes</PartMfg>
-<KnownMass>15.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Body tube</Name>
-<KnownCG>100.</KnownCG>
-<UseKnownCG>1</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>5.80486</CalcMass>
-<CalcCG>100.</CalcCG>
-<WettedSurface>0.0414942</WettedSurface>
-<PaintedSurface>0.0414942</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>EST 3090</PartNo>
-<PartDesc>BT-80</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>7</SerialNo>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(54,250,21)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>88.9</Station>
-<OD>66.04</OD>
-<ID>65.79</ID>
-<Len>200.</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>0.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>0</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Centering ring</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>190.2</Xb>
-<CalcMass>7.65502</CalcMass>
-<CalcCG>1.59</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC CR-2.56-0.95</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>8</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>279.1</Station>
-<OD>65.02</OD>
-<ID>25.4</ID>
-<Len>3.18</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>0</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Centering ring</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>165.</Xb>
-<CalcMass>7.62626</CalcMass>
-<CalcCG>1.585</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC CR-2.56-(2)0.95</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>9</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>253.9</Station>
-<OD>65.</OD>
-<ID>25.4</ID>
-<Len>3.17</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>0</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<BodyTube>
-<PartMfg>Public Missiles Ltd.</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>958.705</Density>
-<Material>Kraft phenolic</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>137.9</Xb>
-<CalcMass>9.8818</CalcMass>
-<CalcCG>35.</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>KS-1.1</PartNo>
-<PartDesc>KwikSwitch MMT 29mm</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>-1.58371</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>10</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>226.8</Station>
-<OD>32.26</OD>
-<ID>29.21</ID>
-<Len>70.</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>1</IsMotorMount>
-<MotorDia>29.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>1</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-</AttachedParts>
-</BodyTube>
-</AttachedParts>
-</BodyTube>
-</Stage3Parts>
-<Stage2Parts>
-<BodyTube>
-<PartMfg>Estes</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>2nd Stage Tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>10.4685</CalcMass>
-<CalcCG>180.34</CalcCG>
-<WettedSurface>0.0748306</WettedSurface>
-<PaintedSurface>0.0748306</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>EST 3090</PartNo>
-<PartDesc>BT-80</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>11</SerialNo>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(54,250,21)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>288.9</Station>
-<OD>66.04</OD>
-<ID>65.79</ID>
-<Len>360.68</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>0.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>0</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>15.025</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Tube coupler</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>1</UseKnownCG>
-<Xb>-10.</Xb>
-<CalcMass>20.465</CalcMass>
-<CalcCG>35.45</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>TC-2.56</PartNo>
-<PartDesc>Tube Coupler</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>12</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>278.9</Station>
-<OD>65.79</OD>
-<ID>63.25</ID>
-<Len>70.9</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>4</UsageCode>
-<AutoSize>1</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<MassObject>
-<PartMfg>Custom</PartMfg>
-<KnownMass>40.</KnownMass>
-<Density>0.</Density>
-<Material>Custom</Material>
-<Name>Electronics</Name>
-<KnownCG>138.3</KnownCG>
-<UseKnownCG>1</UseKnownCG>
-<Xb>138.3</Xb>
-<CalcMass>0.</CalcMass>
-<CalcCG>0.</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>13</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>427.2</Station>
-<TypeCode>0</TypeCode>
-<Len>0.</Len>
-<AttachedParts>
-</AttachedParts>
-</MassObject>
-<FinSet>
-<PartMfg>Quest</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>128.148</Density>
-<Material>Balsa</Material>
-<Name>Fin set</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>228.6</Xb>
-<CalcMass>1.32269</CalcMass>
-<CalcCG>19.05</CalcCG>
-<WettedSurface>0.0028791</WettedSurface>
-<PaintedSurface>0.0086373</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>Payloader One</PartNo>
-<PartDesc>Fin</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.0830777</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>14</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>2.93008</BarrowmanCNa>
-<BarrowmanXN>0.52856</BarrowmanXN>
-<RockSimCNa>5.49629</RockSimCNa>
-<RockSimXN>0.52856</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>517.5</Station>
-<FinCount>3</FinCount>
-<RootChord>38.1</RootChord>
-<TipChord>24.9</TipChord>
-<SemiSpan>45.7</SemiSpan>
-<MidChordLen>45.7</MidChordLen>
-<SweepDistance>6.6</SweepDistance>
-<Thickness>2.39</Thickness>
-<ShapeCode>0</ShapeCode>
-<FinishCode>0</FinishCode>
-<TipShapeCode>2</TipShapeCode>
-<TabLength>0.</TabLength>
-<TabDepth>0.</TabDepth>
-<TabOffset>0.</TabOffset>
-<SweepMode>1</SweepMode>
-<SweepAngle>0.139993</SweepAngle>
-<RockSimXNPerFin>0.</RockSimXNPerFin>
-<RockSimRadialXNPerFin>54.2741</RockSimRadialXNPerFin>
-<RockSimCNaPerFin>2.83538</RockSimCNaPerFin>
-<TaperRatio>0.653543</TaperRatio>
-<CantAngle>0.</CantAngle>
-<CantPivotPoint>0.</CantPivotPoint>
-<AttachedParts>
-</AttachedParts>
-</FinSet>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Centering ring</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>302.</Xb>
-<CalcMass>7.65502</CalcMass>
-<CalcCG>1.59</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC CR-2.56-0.95</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>15</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>590.9</Station>
-<OD>65.02</OD>
-<ID>25.4</ID>
-<Len>3.18</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>0</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Centering ring</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>335.5</Xb>
-<CalcMass>7.62626</CalcMass>
-<CalcCG>1.585</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC CR-2.56-(2)0.95</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>16</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>624.4</Station>
-<OD>65.</OD>
-<ID>25.4</ID>
-<Len>3.17</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>0</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<BodyTube>
-<PartMfg>Public Missiles Ltd.</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>958.705</Density>
-<Material>Kraft phenolic</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>587.4</Xb>
-<CalcMass>9.8818</CalcMass>
-<CalcCG>35.</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>KS-1.1</PartNo>
-<PartDesc>KwikSwitch MMT 29mm</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>-1.58371</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>17</SerialNo>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>1</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>587.4</Station>
-<OD>32.26</OD>
-<ID>29.21</ID>
-<Len>70.</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>1</IsMotorMount>
-<MotorDia>29.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>1</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<Ring>
-<PartMfg>Semroc</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Engine block</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>2.69315</CalcMass>
-<CalcCG>2.39</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>TB-7</PartNo>
-<PartDesc>Thrust Block</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>18</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>587.4</Station>
-<OD>29.21</OD>
-<ID>14.61</ID>
-<Len>4.78</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>2</UsageCode>
-<AutoSize>1</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-</AttachedParts>
-</BodyTube>
-</AttachedParts>
-</BodyTube>
-</Stage2Parts>
-<Stage1Parts>
-<Transition>
-<PartMfg>BalsaMachining.com</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>128.148</Density>
-<Material>Balsa</Material>
-<Name>Transition</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>8.62096</CalcMass>
-<CalcCG>25.1578</CalcCG>
-<WettedSurface>0.00986655</WettedSurface>
-<PaintedSurface>0.00986655</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>TA6080</PartNo>
-<PartDesc>Transition T60 to T80 2.25 in long</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>19</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>-1.20451</BarrowmanCNa>
-<BarrowmanXN>0.675971</BarrowmanXN>
-<RockSimCNa>-1.20451</RockSimCNa>
-<RockSimXN>0.675971</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>649.58</Station>
-<FrontDia>66.04</FrontDia>
-<RearDia>41.4</RearDia>
-<Len>57.15</Len>
-<FinishCode>0</FinishCode>
-<FrontShoulderLen>20.</FrontShoulderLen>
-<RearShoulderLen>38.1</RearShoulderLen>
-<ConstructionType>1</ConstructionType>
-<WallThickness>3.</WallThickness>
-<FrontShoulderDia>64.77</FrontShoulderDia>
-<RearShoulderDia>41.38</RearShoulderDia>
-<CoreDia>0.</CoreDia>
-<ShapeCode>0</ShapeCode>
-<ShapeParameter>0.</ShapeParameter>
-<EquivNoseLen>153.172</EquivNoseLen>
-<EquivNoseOffset>96.022</EquivNoseOffset>
-<AttachedParts>
-</AttachedParts>
-</Transition>
-<BodyTube>
-<PartMfg>LOC/Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>33.5306</CalcMass>
-<CalcCG>209.2</CalcCG>
-<WettedSurface>0.0604643</WettedSurface>
-<PaintedSurface>0.0604643</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC BT-2.14</PartNo>
-<PartDesc>Airframe tube</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>20</SerialNo>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(54,250,21)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>706.73</Station>
-<OD>46.</OD>
-<ID>45.</ID>
-<Len>418.4</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>0.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>0</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<FinSet>
-<PartMfg>Quest</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Elliptical Fins</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>69.7</Xb>
-<CalcMass>36.2048</CalcMass>
-<CalcCG>46.</CalcCG>
-<WettedSurface>0.00676907</WettedSurface>
-<PaintedSurface>0.0203072</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>-0.519061</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>21</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>3.64017</BarrowmanCNa>
-<BarrowmanXN>0.802926</BarrowmanXN>
-<RockSimCNa>6.19583</RockSimCNa>
-<RockSimXN>0.802926</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>776.43</Station>
-<FinCount>3</FinCount>
-<RootChord>92.</RootChord>
-<TipChord>46.</TipChord>
-<SemiSpan>46.9</SemiSpan>
-<MidChordLen>46.9</MidChordLen>
-<SweepDistance>33.49</SweepDistance>
-<Thickness>3.18</Thickness>
-<ShapeCode>1</ShapeCode>
-<FinishCode>0</FinishCode>
-<TipShapeCode>0</TipShapeCode>
-<TabLength>0.</TabLength>
-<TabDepth>0.</TabDepth>
-<TabOffset>0.</TabOffset>
-<SweepMode>1</SweepMode>
-<SweepAngle>0.349066</SweepAngle>
-<RockSimXNPerFin>0.</RockSimXNPerFin>
-<RockSimRadialXNPerFin>43.8444</RockSimRadialXNPerFin>
-<RockSimCNaPerFin>3.30201</RockSimCNaPerFin>
-<TaperRatio>0.5</TaperRatio>
-<CantAngle>0.</CantAngle>
-<CantPivotPoint>0.</CantPivotPoint>
-<AttachedParts>
-</AttachedParts>
-</FinSet>
-<CustomFinSet>
-<PartMfg>Public Missiles</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1905.24</Density>
-<Material>G10 fiberglass</Material>
-<Name>Custom Fins</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>241.7</Xb>
-<CalcMass>256.292</CalcMass>
-<CalcCG>78.9922</CalcCG>
-<WettedSurface>0.0355266</WettedSurface>
-<PaintedSurface>0.10658</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>FIN-C-02</PartNo>
-<PartDesc>Fins</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.357967</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>22</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>25.7124</BarrowmanCNa>
-<BarrowmanXN>0.996591</BarrowmanXN>
-<RockSimCNa>34.6308</RockSimCNa>
-<RockSimXN>0.996926</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>948.43</Station>
-<FinCount>3</FinCount>
-<RootChord>152.4</RootChord>
-<TipChord>83.83</TipChord>
-<SemiSpan>146.72</SemiSpan>
-<MidChordLen>146.81</MidChordLen>
-<SweepDistance>39.42</SweepDistance>
-<Thickness>2.38</Thickness>
-<ShapeCode>2</ShapeCode>
-<FinishCode>0</FinishCode>
-<TipShapeCode>2</TipShapeCode>
-<TabLength>101.6</TabLength>
-<TabDepth>10.6</TabDepth>
-<TabOffset>35.6</TabOffset>
-<SweepMode>1</SweepMode>
-<SweepAngle>0.</SweepAngle>
-<RockSimXNPerFin>0.</RockSimXNPerFin>
-<RockSimRadialXNPerFin>89.2598</RockSimRadialXNPerFin>
-<RockSimCNaPerFin>19.9941</RockSimCNaPerFin>
-<TaperRatio>0.550066</TaperRatio>
-<CantAngle>0.</CantAngle>
-<CantPivotPoint>0.</CantPivotPoint>
-<AverageChord>121.07</AverageChord>
-<EffectiveTipChord>83.8257</EffectiveTipChord>
-<PointList>152.4,0|126.202,146.715|36.455,146.715|0,0|</PointList>
-<AutoCalcGridStepX>0,0,0,0,0,0,0</AutoCalcGridStepX>
-<GridStepCountX>10,10,10,10,10,10,10</GridStepCountX>
-<UseAbsoluteGridStepsX>0,0,0,0,0,0,0</UseAbsoluteGridStepsX>
-<GridStepSizeX>0.5,10,0.5,0.5,0.00018939,0.001,1</GridStepSizeX>
-<SnapToSizeX>0.25,5,0.1,0.1,0.00018939,0.001,1</SnapToSizeX>
-<AutoCalcGridStepY>0,0,0,0,0,0,0</AutoCalcGridStepY>
-<GridStepCountY>10,10,10,10,10,10,10</GridStepCountY>
-<UseAbsoluteGridStepsY>0,0,0,0,0,0,0</UseAbsoluteGridStepsY>
-<GridStepSizeY>0.5,10,0.5,0.5,0.00018939,0.001,1</GridStepSizeY>
-<SnapToSizeY>0.25,5,0.1,0.1,0.00018939,0.001,1</SnapToSizeY>
-<AttachedParts>
-</AttachedParts>
-</CustomFinSet>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Centering ring</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>379.5</Xb>
-<CalcMass>2.55395</CalcMass>
-<CalcCG>1.59</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC FCR-1.52-1.14</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>23</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>1086.23</Station>
-<OD>45.</OD>
-<ID>24.79</ID>
-<Len>3.18</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>1</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Centering ring</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>272.</Xb>
-<CalcMass>2.55395</CalcMass>
-<CalcCG>1.59</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC FCR-1.52-1.14</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>24</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>978.73</Station>
-<OD>45.</OD>
-<ID>24.79</ID>
-<Len>3.18</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>1</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<BodyTube>
-<PartMfg>Estes</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>259.7</Xb>
-<CalcMass>5.22902</CalcMass>
-<CalcCG>91.95</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>EST 3086</PartNo>
-<PartDesc>BT-50</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>25</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>966.43</Station>
-<OD>24.79</OD>
-<ID>24.13</ID>
-<Len>183.9</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>1</IsMotorMount>
-<MotorDia>24.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>1</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-</AttachedParts>
-</BodyTube>
-</AttachedParts>
-</BodyTube>
-</Stage1Parts>
-<SideViewDims>
-</SideViewDims>
-<BaseViewDims>
-</BaseViewDims>
-<VertViewDims>
-</VertViewDims>
-</RocketDesign>
-</DesignInformation>
-<SimulationResultsList>
-</SimulationResultsList>
-</RockSimDocument>
diff --git a/test/net/sf/openrocket/file/rocksim/rocksimTestRocket3.rkt b/test/net/sf/openrocket/file/rocksim/rocksimTestRocket3.rkt
deleted file mode 100644 (file)
index df1788c..0000000
+++ /dev/null
@@ -1,1961 +0,0 @@
-<RockSimDocument>
-<FileVersion>3</FileVersion>
-<DesignInformation>
-<RocketDesign>
-<Name>Three Stage Everything Included Rocket - Override Total Mass/CG</Name>
-<CalculateCD>1</CalculateCD>
-<ProCalculateCD>1</ProCalculateCD>
-<ProCalculateCN>1</ProCalculateCN>
-<FixedCd>0.75</FixedCd>
-<FixedCd2>0.8</FixedCd2>
-<FixedCd3>0.81</FixedCd3>
-<FixedCd2Alone>0.95</FixedCd2Alone>
-<FixedCd3Alone>0.95</FixedCd3Alone>
-<StageCount>3</StageCount>
-<Stage3Mass>185.</Stage3Mass>
-<Stage2Mass>210.</Stage2Mass>
-<Stage1Mass>330.</Stage1Mass>
-<Stage321CG>0.</Stage321CG>
-<Stage32CG>0.</Stage32CG>
-<Stage3CG>300.</Stage3CG>
-<Stage2CGAlone>400.</Stage2CGAlone>
-<Stage1CGAlone>500.</Stage1CGAlone>
-<CPCalcFlags>1</CPCalcFlags>
-<LaunchGuideLength>914.4</LaunchGuideLength>
-<UseKnownMass>0</UseKnownMass>
-<DefaultFinish>0</DefaultFinish>
-<FinishMedium>0</FinishMedium>
-<FinishCoatCount>1</FinishCoatCount>
-<GlueType>0</GlueType>
-<CPSimFlags>1</CPSimFlags>
-<LastSerialNumber>32</LastSerialNumber>
-<DisplayFlags>7</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<BarromanXN>0,29.6333,327.236,966.855</BarromanXN>
-<BarrowmanCNa>0,2,4.95647,83.562</BarrowmanCNa>
-<RockSimXN>0,29.6333,385.082,953.76</RockSimXN>
-<RockSimCNa>0,2,6.95476,97.0629</RockSimCNa>
-<RockSimCNa90>0,0,0,0</RockSimCNa90>
-<RockSimXN90>0,0,0,0</RockSimXN90>
-<ViewType>0</ViewType>
-<ViewStageCount>3</ViewStageCount>
-<ViewTypeEdit>0</ViewTypeEdit>
-<ViewStageCountEdit>3</ViewStageCountEdit>
-<ZoomFactor>0.</ZoomFactor>
-<ZoomFactorEdit>0.</ZoomFactorEdit>
-<ScrollPosX>0</ScrollPosX>
-<ScrollPosY>0</ScrollPosY>
-<ScrollPosXEdit>0</ScrollPosXEdit>
-<ScrollPosYEdit>0</ScrollPosYEdit>
-<ThreeDFlags>0</ThreeDFlags>
-<ThreeDFlagsEdit>0</ThreeDFlagsEdit>
-<UseModelSprite>0</UseModelSprite>
-<StaticMarginRef>0</StaticMarginRef>
-<UserRefDiameter>0.</UserRefDiameter>
-<SideMarkerHeight>10.</SideMarkerHeight>
-<SideDimensionHeight>10.</SideDimensionHeight>
-<BaseMarkerHeight>10.</BaseMarkerHeight>
-<BaseDimensionHeight>10.</BaseDimensionHeight>
-<ShowGlideCP>0</ShowGlideCP>
-<ShowGridTypeSide>0</ShowGridTypeSide>
-<ShowGridTypeBase>0</ShowGridTypeBase>
-<GridSpacing>10.</GridSpacing>
-<GridOpacity>0.15</GridOpacity>
-<GridColor>black</GridColor>
-<MaxDiaWithFins>334.83</MaxDiaWithFins>
-<MaxDiaWithoutFins>66.</MaxDiaWithoutFins>
-<MaxLenWithFins>2155.23</MaxLenWithFins>
-<MaxLenWithoutFins>2155.23</MaxLenWithoutFins>
-<MinXExtent>0.</MinXExtent>
-<MaxXExtent>1150.33</MaxXExtent>
-<CalculatedMaxStageDia>0,66,66,66</CalculatedMaxStageDia>
-<CalculatedStageLen>0,347.5,1004.9,2155.23</CalculatedStageLen>
-<Cd3>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cd3>
-<Cd32>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cd32>
-<Cd321>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cd321>
-<Cb3>
-<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cb3>
-<Cb32>
-<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cb32>
-<Cb321>
-<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</Cb321>
-<CNa3>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CNa3>
-<CNa32>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CNa32>
-<CNa321>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CNa321>
-<CP3>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CP3>
-<CP32>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CP32>
-<CP321>
-<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
-<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
-<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
-<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
-<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
-</PolyData>
-</CP321>
-<SimulationEventList>
-</SimulationEventList>
-<Stage3Parts>
-<NoseCone>
-<PartMfg>Aerospace Speciality Products</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>128.148</Density>
-<Material>Balsa</Material>
-<Name>Nose cone</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>42.6368</CalcMass>
-<CalcCG>76.0242</CalcCG>
-<WettedSurface>0.0152192</WettedSurface>
-<PaintedSurface>0.0152192</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>BNC80S</PartNo>
-<PartDesc><![CDATA[T-80H Balsa Nose Cone "S"]]></PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>1</SerialNo>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>2.</BarrowmanCNa>
-<BarrowmanXN>0.0296333</BarrowmanXN>
-<RockSimCNa>2.</RockSimCNa>
-<RockSimXN>0.0296333</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>0.</Station>
-<Len>88.9</Len>
-<BaseDia>66.</BaseDia>
-<FinishCode>0</FinishCode>
-<ShapeCode>3</ShapeCode>
-<ConstructionType>0</ConstructionType>
-<ShoulderLen>38.1</ShoulderLen>
-<WallThickness>0.</WallThickness>
-<ShapeParameter>0.</ShapeParameter>
-<ShoulderOD>65.9</ShoulderOD>
-<BaseExtensionLen>0.</BaseExtensionLen>
-<CoreDia>0.</CoreDia>
-<CoreLen>0.</CoreLen>
-<AttachedParts>
-<MassObject>
-<PartMfg>Custom</PartMfg>
-<KnownMass>20.</KnownMass>
-<Density>0.</Density>
-<Material>Custom</Material>
-<Name>Clay</Name>
-<KnownCG>17.8</KnownCG>
-<UseKnownCG>1</UseKnownCG>
-<Xb>17.8</Xb>
-<CalcMass>0.</CalcMass>
-<CalcCG>0.</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>2</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>17.8</Station>
-<TypeCode>0</TypeCode>
-<Len>0.</Len>
-<AttachedParts>
-</AttachedParts>
-</MassObject>
-<BodyTube>
-<PartMfg>Apogee</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Attachment Rod</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>6.1</Xb>
-<CalcMass>2.47301</CalcMass>
-<CalcCG>78.85</CalcCG>
-<WettedSurface>0.00684683</WettedSurface>
-<PaintedSurface>0.00684683</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>10062</PartNo>
-<PartDesc>13 mm</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>3</SerialNo>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>6.1</Station>
-<OD>13.82</OD>
-<ID>13.16</ID>
-<Len>157.7</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>0.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>1</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Plate</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>78.9</Xb>
-<CalcMass>7.86272</CalcMass>
-<CalcCG>1.585</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC CR-2.56-(2)0.95</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>4</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>85.</Station>
-<OD>66.</OD>
-<ID>13.82</ID>
-<Len>3.17</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>0</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<Ring>
-<PartMfg>Custom</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1400.</Density>
-<Material>Carbon Fiber</Material>
-<Name>Sleeve </Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>17.5527</CalcMass>
-<CalcCG>13.85</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>5</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>2</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>136.1</Station>
-<OD>27.7</OD>
-<ID>13.82</ID>
-<Len>27.7</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>3</UsageCode>
-<AutoSize>0</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<Parachute>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>170.</KnownMass>
-<Density>0.006685</Density>
-<Material>Rip stop nylon</Material>
-<Name>Nose Cone Parachute</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>1</UseKnownCG>
-<Xb>142.6</Xb>
-<CalcMass>15.8812</CalcMass>
-<CalcCG>34.5417</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>1</DensityType>
-<PartNo>LP-50</PartNo>
-<PartDesc>50 In. 16 lines</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>6</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>148.7</Station>
-<Dia>414.5</Dia>
-<SpillHoleDia>0.</SpillHoleDia>
-<SideCount>15</SideCount>
-<ShroudLineCount>16</ShroudLineCount>
-<Thickness>0.05</Thickness>
-<ShroudLineLen>1350.</ShroudLineLen>
-<ChuteCount>1</ChuteCount>
-<ShroudLineMassPerMM>0.00032972</ShroudLineMassPerMM>
-<ShroudLineMaterial>Carpet String (Apogee 29500)</ShroudLineMaterial>
-<DragCoefficient>0.95</DragCoefficient>
-<AttachedParts>
-</AttachedParts>
-</Parachute>
-</AttachedParts>
-</BodyTube>
-</AttachedParts>
-</NoseCone>
-<BodyTube>
-<PartMfg>Estes</PartMfg>
-<KnownMass>15.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Body tube</Name>
-<KnownCG>100.</KnownCG>
-<UseKnownCG>1</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>5.805</CalcMass>
-<CalcCG>100.</CalcCG>
-<WettedSurface>0.0414942</WettedSurface>
-<PaintedSurface>0.0414942</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>EST 3090</PartNo>
-<PartDesc>BT-80</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>7</SerialNo>
-<DisplayFlags>1</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(54,250,21)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>88.9</Station>
-<OD>66.</OD>
-<ID>65.79</ID>
-<Len>200.</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>0.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>0</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Centering ring</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>190.2</Xb>
-<CalcMass>7.65502</CalcMass>
-<CalcCG>1.59</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC CR-2.56-0.95</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>8</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>279.1</Station>
-<OD>65.02</OD>
-<ID>25.4</ID>
-<Len>3.18</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>0</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Centering ring</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>165.</Xb>
-<CalcMass>7.62626</CalcMass>
-<CalcCG>1.585</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC CR-2.56-(2)0.95</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>9</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>253.9</Station>
-<OD>65.</OD>
-<ID>25.4</ID>
-<Len>3.17</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>0</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<BodyTube>
-<PartMfg>Public Missiles Ltd.</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>958.705</Density>
-<Material>Kraft phenolic</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>137.9</Xb>
-<CalcMass>9.8818</CalcMass>
-<CalcCG>35.</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>KS-1.1</PartNo>
-<PartDesc>KwikSwitch MMT 29mm</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>-1.58371</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>10</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>226.8</Station>
-<OD>32.26</OD>
-<ID>29.21</ID>
-<Len>70.</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>1</IsMotorMount>
-<MotorDia>29.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>1</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-</AttachedParts>
-</BodyTube>
-<LaunchLug>
-<PartMfg>Apogee</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Launch lug</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>77.2</Xb>
-<CalcMass>1.11942</CalcMass>
-<CalcCG>38.1</CalcCG>
-<WettedSurface>0.00374518</WettedSurface>
-<PaintedSurface>0.00199411</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>13056</PartNo>
-<PartDesc><![CDATA[1/4" X 3]]></PartDesc>
-<RadialLoc>37.185</RadialLoc>
-<RadialAngle>3.14</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>26</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>166.1</Station>
-<OD>8.33</OD>
-<ID>7.26</ID>
-<Len>76.2</Len>
-<FinishCode>0</FinishCode>
-<AttachedParts>
-</AttachedParts>
-</LaunchLug>
-<ExternalPod>
-<PartMfg>Custom</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>0.</Density>
-<Name>Pod</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>200.</Xb>
-<CalcMass>0.</CalcMass>
-<CalcCG>0.</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<RadialLoc>36.175</RadialLoc>
-<RadialAngle>-1.50735</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>29</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>288.9</Station>
-<Detachable>1</Detachable>
-<AutoCalcRadialDistance>1</AutoCalcRadialDistance>
-<AutoCalcRadialAngle>1</AutoCalcRadialAngle>
-<AttachedParts>
-<BodyTube>
-<PartMfg>Apogee</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>958.705</Density>
-<Material>Kraft phenolic</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>0.400397</CalcMass>
-<CalcCG>29.3</CalcCG>
-<WettedSurface>0.00116902</WettedSurface>
-<PaintedSurface>0.00116902</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>9601</PartNo>
-<PartDesc>6 mm</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>30</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(54,250,21)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>288.9</Station>
-<OD>6.35</OD>
-<ID>5.59</ID>
-<Len>58.6</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>0.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>0</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-</AttachedParts>
-</BodyTube>
-</AttachedParts>
-</ExternalPod>
-</AttachedParts>
-</BodyTube>
-</Stage3Parts>
-<Stage2Parts>
-<BodyTube>
-<PartMfg>Estes</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>2nd Stage Tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>10.468</CalcMass>
-<CalcCG>180.34</CalcCG>
-<WettedSurface>0.0748306</WettedSurface>
-<PaintedSurface>0.0748306</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>EST 3090</PartNo>
-<PartDesc>BT-80</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>11</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(54,250,21)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>288.9</Station>
-<OD>66.</OD>
-<ID>65.79</ID>
-<Len>360.68</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>0.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>0</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>15.025</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Tube coupler</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>1</UseKnownCG>
-<Xb>-10.</Xb>
-<CalcMass>20.465</CalcMass>
-<CalcCG>35.45</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>TC-2.56</PartNo>
-<PartDesc>Tube Coupler</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>12</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>278.9</Station>
-<OD>65.79</OD>
-<ID>63.25</ID>
-<Len>70.9</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>4</UsageCode>
-<AutoSize>1</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<MassObject>
-<PartMfg>Custom</PartMfg>
-<KnownMass>40.</KnownMass>
-<Density>0.</Density>
-<Material>Custom</Material>
-<Name>Electronics</Name>
-<KnownCG>138.3</KnownCG>
-<UseKnownCG>1</UseKnownCG>
-<Xb>138.3</Xb>
-<CalcMass>0.</CalcMass>
-<CalcCG>0.</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>13</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>427.2</Station>
-<TypeCode>0</TypeCode>
-<Len>0.</Len>
-<AttachedParts>
-</AttachedParts>
-</MassObject>
-<FinSet>
-<PartMfg>Quest</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>128.148</Density>
-<Material>Balsa</Material>
-<Name>Fin set</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>228.6</Xb>
-<CalcMass>1.32269</CalcMass>
-<CalcCG>19.05</CalcCG>
-<WettedSurface>0.0028791</WettedSurface>
-<PaintedSurface>0.0086373</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>Payloader One</PartNo>
-<PartDesc>Fin</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.0830777</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>14</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>2.95647</BarrowmanCNa>
-<BarrowmanXN>0.52856</BarrowmanXN>
-<RockSimCNa>5.54523</RockSimCNa>
-<RockSimXN>0.52856</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>517.5</Station>
-<FinCount>3</FinCount>
-<RootChord>38.1</RootChord>
-<TipChord>24.9</TipChord>
-<SemiSpan>45.7</SemiSpan>
-<MidChordLen>45.7</MidChordLen>
-<SweepDistance>6.6</SweepDistance>
-<Thickness>2.39</Thickness>
-<ShapeCode>0</ShapeCode>
-<FinishCode>0</FinishCode>
-<TipShapeCode>2</TipShapeCode>
-<TabLength>0.</TabLength>
-<TabDepth>0.</TabDepth>
-<TabOffset>0.</TabOffset>
-<SweepMode>1</SweepMode>
-<SweepAngle>0.139993</SweepAngle>
-<RockSimXNPerFin>0.</RockSimXNPerFin>
-<RockSimRadialXNPerFin>54.2541</RockSimRadialXNPerFin>
-<RockSimCNaPerFin>2.86063</RockSimCNaPerFin>
-<TaperRatio>0.653543</TaperRatio>
-<CantAngle>0.</CantAngle>
-<CantPivotPoint>0.</CantPivotPoint>
-<AttachedParts>
-</AttachedParts>
-</FinSet>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Centering ring</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>302.</Xb>
-<CalcMass>7.65502</CalcMass>
-<CalcCG>1.59</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC CR-2.56-0.95</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>15</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>590.9</Station>
-<OD>65.02</OD>
-<ID>25.4</ID>
-<Len>3.18</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>0</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Centering ring</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>335.5</Xb>
-<CalcMass>7.62626</CalcMass>
-<CalcCG>1.585</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC CR-2.56-(2)0.95</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>16</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>624.4</Station>
-<OD>65.</OD>
-<ID>25.4</ID>
-<Len>3.17</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>0</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<BodyTube>
-<PartMfg>Public Missiles Ltd.</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>958.705</Density>
-<Material>Kraft phenolic</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>587.4</Xb>
-<CalcMass>9.8818</CalcMass>
-<CalcCG>35.</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>KS-1.1</PartNo>
-<PartDesc>KwikSwitch MMT 29mm</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>-1.58371</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>17</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>1</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>587.4</Station>
-<OD>32.26</OD>
-<ID>29.21</ID>
-<Len>70.</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>1</IsMotorMount>
-<MotorDia>29.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>1</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<Ring>
-<PartMfg>Semroc</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Engine block</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>2.69315</CalcMass>
-<CalcCG>2.39</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>TB-7</PartNo>
-<PartDesc>Thrust Block</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>18</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>587.4</Station>
-<OD>29.21</OD>
-<ID>14.61</ID>
-<Len>4.78</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>2</UsageCode>
-<AutoSize>1</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-</AttachedParts>
-</BodyTube>
-<LaunchLug>
-<PartMfg>Apogee</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Launch lug</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>265.8</Xb>
-<CalcMass>1.11942</CalcMass>
-<CalcCG>38.1</CalcCG>
-<WettedSurface>0.00374518</WettedSurface>
-<PaintedSurface>0.00199411</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>13056</PartNo>
-<PartDesc><![CDATA[1/4" X 3]]></PartDesc>
-<RadialLoc>37.185</RadialLoc>
-<RadialAngle>1.22</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>27</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>554.7</Station>
-<OD>8.33</OD>
-<ID>7.26</ID>
-<Len>76.2</Len>
-<FinishCode>0</FinishCode>
-<AttachedParts>
-</AttachedParts>
-</LaunchLug>
-</AttachedParts>
-</BodyTube>
-</Stage2Parts>
-<Stage1Parts>
-<Transition>
-<PartMfg>BalsaMachining.com</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>128.148</Density>
-<Material>Balsa</Material>
-<Name>Transition</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>8.61936</CalcMass>
-<CalcCG>25.1551</CalcCG>
-<WettedSurface>0.0098623</WettedSurface>
-<PaintedSurface>0.0098623</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>TA6080</PartNo>
-<PartDesc>Transition T60 to T80 2.25 in long</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>19</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>-1.213</BarrowmanCNa>
-<BarrowmanXN>0.675973</BarrowmanXN>
-<RockSimCNa>-1.213</RockSimCNa>
-<RockSimXN>0.675973</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>649.58</Station>
-<FrontDia>66.</FrontDia>
-<RearDia>41.4</RearDia>
-<Len>57.15</Len>
-<FinishCode>0</FinishCode>
-<FrontShoulderLen>20.</FrontShoulderLen>
-<RearShoulderLen>38.1</RearShoulderLen>
-<ConstructionType>1</ConstructionType>
-<WallThickness>3.</WallThickness>
-<FrontShoulderDia>64.77</FrontShoulderDia>
-<RearShoulderDia>41.38</RearShoulderDia>
-<CoreDia>0.</CoreDia>
-<ShapeCode>0</ShapeCode>
-<ShapeParameter>0.</ShapeParameter>
-<EquivNoseLen>153.339</EquivNoseLen>
-<EquivNoseOffset>96.1895</EquivNoseOffset>
-<AttachedParts>
-</AttachedParts>
-</Transition>
-<BodyTube>
-<PartMfg>LOC/Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>0.</CalcMass>
-<CalcCG>nan.</CalcCG>
-<WettedSurface>0.0544179</WettedSurface>
-<PaintedSurface>0.0544179</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC BT-2.14</PartNo>
-<PartDesc>Airframe tube</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>20</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(54,250,21)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>706.73</Station>
-<OD>41.4</OD>
-<ID>41.</ID>
-<Len>418.4</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>0</IsMotorMount>
-<MotorDia>0.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>0</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-<FinSet>
-<PartMfg>Quest</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Elliptical Fins</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>69.7</Xb>
-<CalcMass>36.2048</CalcMass>
-<CalcCG>46.</CalcCG>
-<WettedSurface>0.00676907</WettedSurface>
-<PaintedSurface>0.0203072</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>-0.519061</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>21</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>3.61024</BarrowmanCNa>
-<BarrowmanXN>0.802926</BarrowmanXN>
-<RockSimCNa>6.03948</RockSimCNa>
-<RockSimXN>0.802926</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>776.43</Station>
-<FinCount>3</FinCount>
-<RootChord>92.</RootChord>
-<TipChord>46.</TipChord>
-<SemiSpan>46.9</SemiSpan>
-<MidChordLen>46.9</MidChordLen>
-<SweepDistance>33.49</SweepDistance>
-<Thickness>3.18</Thickness>
-<ShapeCode>1</ShapeCode>
-<FinishCode>0</FinishCode>
-<TipShapeCode>0</TipShapeCode>
-<TabLength>0.</TabLength>
-<TabDepth>0.</TabDepth>
-<TabOffset>0.</TabOffset>
-<SweepMode>1</SweepMode>
-<SweepAngle>0.349066</SweepAngle>
-<RockSimXNPerFin>0.</RockSimXNPerFin>
-<RockSimRadialXNPerFin>41.5444</RockSimRadialXNPerFin>
-<RockSimCNaPerFin>3.21868</RockSimCNaPerFin>
-<TaperRatio>0.5</TaperRatio>
-<CantAngle>0.</CantAngle>
-<CantPivotPoint>0.</CantPivotPoint>
-<AttachedParts>
-</AttachedParts>
-</FinSet>
-<CustomFinSet>
-<PartMfg>Public Missiles</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1905.24</Density>
-<Material>G10 fiberglass</Material>
-<Name>Custom Fins</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>241.7</Xb>
-<CalcMass>256.292</CalcMass>
-<CalcCG>78.9922</CalcCG>
-<WettedSurface>0.0355266</WettedSurface>
-<PaintedSurface>0.10658</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>FIN-C-02</PartNo>
-<PartDesc>Fins</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.357967</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>22</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>25.7037</BarrowmanCNa>
-<BarrowmanXN>0.996526</BarrowmanXN>
-<RockSimCNa>34.1865</RockSimCNa>
-<RockSimXN>0.996822</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>948.43</Station>
-<FinCount>3</FinCount>
-<RootChord>152.4</RootChord>
-<TipChord>84.53</TipChord>
-<SemiSpan>146.72</SemiSpan>
-<MidChordLen>146.81</MidChordLen>
-<SweepDistance>39.07</SweepDistance>
-<Thickness>2.38</Thickness>
-<ShapeCode>2</ShapeCode>
-<FinishCode>0</FinishCode>
-<TipShapeCode>2</TipShapeCode>
-<TabLength>101.6</TabLength>
-<TabDepth>10.6</TabDepth>
-<TabOffset>35.6</TabOffset>
-<SweepMode>1</SweepMode>
-<SweepAngle>0.</SweepAngle>
-<RockSimXNPerFin>0.</RockSimXNPerFin>
-<RockSimRadialXNPerFin>87.0529</RockSimRadialXNPerFin>
-<RockSimCNaPerFin>19.7376</RockSimCNaPerFin>
-<TaperRatio>0.554659</TaperRatio>
-<CantAngle>0.</CantAngle>
-<CantPivotPoint>0.</CantPivotPoint>
-<AverageChord>121.39</AverageChord>
-<EffectiveTipChord>84.5261</EffectiveTipChord>
-<PointList>152.4,0|126.202,146.715|36.455,146.715|0,0|</PointList>
-<AutoCalcGridStepX>0,0,0,0,0,0,0</AutoCalcGridStepX>
-<GridStepCountX>10,10,10,10,10,10,10</GridStepCountX>
-<UseAbsoluteGridStepsX>0,0,0,0,0,0,0</UseAbsoluteGridStepsX>
-<GridStepSizeX>0.5,10,0.5,0.5,0.00018939,0.001,1</GridStepSizeX>
-<SnapToSizeX>0.25,5,0.1,0.1,0.00018939,0.001,1</SnapToSizeX>
-<AutoCalcGridStepY>0,0,0,0,0,0,0</AutoCalcGridStepY>
-<GridStepCountY>10,10,10,10,10,10,10</GridStepCountY>
-<UseAbsoluteGridStepsY>0,0,0,0,0,0,0</UseAbsoluteGridStepsY>
-<GridStepSizeY>0.5,10,0.5,0.5,0.00018939,0.001,1</GridStepSizeY>
-<SnapToSizeY>0.25,5,0.1,0.1,0.00018939,0.001,1</SnapToSizeY>
-<AttachedParts>
-</AttachedParts>
-</CustomFinSet>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Centering ring</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>379.5</Xb>
-<CalcMass>1.99074</CalcMass>
-<CalcCG>1.59</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC FCR-1.52-1.14</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>23</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>1086.23</Station>
-<OD>41.4</OD>
-<ID>24.79</ID>
-<Len>3.18</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>1</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<Ring>
-<PartMfg>LOC Precision</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>724.996</Density>
-<Material>Aircraft plywood (LOC)</Material>
-<Name>Centering ring</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>272.</Xb>
-<CalcMass>1.99074</CalcMass>
-<CalcCG>1.59</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>LOC FCR-1.52-1.14</PartNo>
-<PartDesc>Centering Ring</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>24</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>978.73</Station>
-<OD>41.4</OD>
-<ID>24.79</ID>
-<Len>3.18</Len>
-<FinishCode>0</FinishCode>
-<UsageCode>0</UsageCode>
-<AutoSize>1</AutoSize>
-<AttachedParts>
-</AttachedParts>
-</Ring>
-<BodyTube>
-<PartMfg>Estes</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Body tube</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>259.7</Xb>
-<CalcMass>5.22902</CalcMass>
-<CalcCG>91.95</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>EST 3086</PartNo>
-<PartDesc>BT-50</PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>rgb(0,0,250)</AbientColor>
-<DiffuseColor>rgb(0,0,250)</DiffuseColor>
-<SpecularColor>rgb(255,255,255)</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>25</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>rgb(0,0,250)</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>966.43</Station>
-<OD>24.79</OD>
-<ID>24.13</ID>
-<Len>183.9</Len>
-<FinishCode>0</FinishCode>
-<IsMotorMount>1</IsMotorMount>
-<MotorDia>24.</MotorDia>
-<EngineOverhang>0.5</EngineOverhang>
-<FrontExtension>0.</FrontExtension>
-<RearExtension>0.</RearExtension>
-<IsInsideTube>1</IsInsideTube>
-<isStrapOnTube>0</isStrapOnTube>
-<AttachedParts>
-</AttachedParts>
-</BodyTube>
-<TubeFinSet>
-<PartMfg>Custom</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1121.29</Density>
-<Material>Paper</Material>
-<Name>Tube fins</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>12.6878</CalcMass>
-<CalcCG>24.79</CalcCG>
-<WettedSurface>0.0688063</WettedSurface>
-<PaintedSurface>0.0688063</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<RadialLoc>35.395</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>28</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>10.866</BarrowmanCNa>
-<BarrowmanXN>0.707815</BarrowmanXN>
-<RockSimCNa>10.866</RockSimCNa>
-<RockSimXN>0.707815</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>706.73</Station>
-<OD>24.79</OD>
-<ID>24.13</ID>
-<Len>49.58</Len>
-<FinishCode>0</FinishCode>
-<TubeCount>9</TubeCount>
-<MinTubeAngle>0.715549</MinTubeAngle>
-<MaxTubesAllowed>9</MaxTubesAllowed>
-<AttachedParts>
-</AttachedParts>
-</TubeFinSet>
-<RingTail>
-<PartMfg>Custom</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>688.794</Density>
-<Material>Cardboard</Material>
-<Name>Ringtail</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>0.</Xb>
-<CalcMass>2.93707</CalcMass>
-<CalcCG>10.</CalcCG>
-<WettedSurface>0.00474229</WettedSurface>
-<PaintedSurface>0.00444249</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>31</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>2</LocationMode>
-<Color>rgb(255,9,18)</Color>
-<BarrowmanCNa>39.6386</BarrowmanCNa>
-<BarrowmanXN>1.10463</BarrowmanXN>
-<RockSimCNa>39.6386</RockSimCNa>
-<RockSimXN>1.10463</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>1105.13</Station>
-<FinCount>3</FinCount>
-<RootChord>20.</RootChord>
-<TipChord>20.</TipChord>
-<SemiSpan>7.495</SemiSpan>
-<MidChordLen>7.495</MidChordLen>
-<SweepDistance>0.</SweepDistance>
-<Thickness>3.</Thickness>
-<ShapeCode>0</ShapeCode>
-<FinishCode>0</FinishCode>
-<TipShapeCode>0</TipShapeCode>
-<TabLength>0.</TabLength>
-<TabDepth>0.</TabDepth>
-<TabOffset>0.</TabOffset>
-<SweepMode>1</SweepMode>
-<SweepAngle>0.</SweepAngle>
-<RockSimXNPerFin>0.</RockSimXNPerFin>
-<RockSimRadialXNPerFin>0.</RockSimRadialXNPerFin>
-<RockSimCNaPerFin>0.</RockSimCNaPerFin>
-<TaperRatio>0.</TaperRatio>
-<CantAngle>0.</CantAngle>
-<CantPivotPoint>0.</CantPivotPoint>
-<OD>56.39</OD>
-<ID>55.37</ID>
-<Len>20.</Len>
-<TubeDensity>1121.29</TubeDensity>
-<TubeDensityType>0</TubeDensityType>
-<TubeMaterial>Paper</TubeMaterial>
-<AttachedParts>
-</AttachedParts>
-</RingTail>
-<Streamer>
-<PartMfg>Apogee</PartMfg>
-<KnownMass>0.</KnownMass>
-<Density>1309.</Density>
-<Material>Mylar</Material>
-<Name>Streamer</Name>
-<KnownCG>0.</KnownCG>
-<UseKnownCG>0</UseKnownCG>
-<Xb>149.4</Xb>
-<CalcMass>5.67514</CalcMass>
-<CalcCG>50.8</CalcCG>
-<WettedSurface>0.</WettedSurface>
-<PaintedSurface>0.</PaintedSurface>
-<GlueJointLength>0.</GlueJointLength>
-<DensityType>0</DensityType>
-<PartNo>29006</PartNo>
-<PartDesc><![CDATA[4" Wide Mylar]]></PartDesc>
-<RadialLoc>0.</RadialLoc>
-<RadialAngle>0.</RadialAngle>
-<Texture>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)</Texture>
-<Opacity>1.</Opacity>
-<Specular>0.</Specular>
-<SpecularPower>1.</SpecularPower>
-<Ambient>0.</Ambient>
-<Diffuse>1.</Diffuse>
-<AbientColor>blue</AbientColor>
-<DiffuseColor>blue</DiffuseColor>
-<SpecularColor>white</SpecularColor>
-<UseSingleColor>1</UseSingleColor>
-<SerialNo>32</SerialNo>
-<DisplayFlags>0</DisplayFlags>
-<MetricsFlags>0</MetricsFlags>
-<LocationMode>0</LocationMode>
-<Color>blue</Color>
-<BarrowmanCNa>0.</BarrowmanCNa>
-<BarrowmanXN>0.</BarrowmanXN>
-<RockSimCNa>0.</RockSimCNa>
-<RockSimXN>0.</RockSimXN>
-<SimpleColorModel>1</SimpleColorModel>
-<ProduceTemplate>0</ProduceTemplate>
-<TemplateUnits>8</TemplateUnits>
-<Removed>0</Removed>
-<Station>856.13</Station>
-<Len>1422.4</Len>
-<Width>101.6</Width>
-<Thickness>0.03</Thickness>
-<StreamerCount>1</StreamerCount>
-<DragCoefficient>0.127</DragCoefficient>
-<IsFolded>0</IsFolded>
-<AutoCalcCd>1</AutoCalcCd>
-<AttachedParts>
-</AttachedParts>
-</Streamer>
-</AttachedParts>
-</BodyTube>
-</Stage1Parts>
-<SideViewDims>
-</SideViewDims>
-<BaseViewDims>
-</BaseViewDims>
-<VertViewDims>
-</VertViewDims>
-</RocketDesign>
-</DesignInformation>
-<SimulationResultsList>
-</SimulationResultsList>
-</RockSimDocument>