Added inference of Rocksim shock cords to try to be a little more predictive when...
authorrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Wed, 11 Jul 2012 22:06:23 +0000 (22:06 +0000)
committerrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Wed, 11 Jul 2012 22:06:23 +0000 (22:06 +0000)
cord from their component database.

git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@886 180e2498-e6e9-4542-8430-84ac67f01cd8

core/src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java
core/src/net/sf/openrocket/file/rocksim/importt/MassObjectHandler.java

index 6302c62a3e19baa9a3ea917764c8f3ef9b37ba32..a9d0bd944f939f1647f2e5c0436c0a5aa6a28f1d 100644 (file)
@@ -18,7 +18,7 @@ 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
+ * @param <C> the specific RocketComponent subtype for which the concrete handler can create
  */
 public abstract class BaseHandler<C extends RocketComponent> extends AbstractElementHandler {
 
@@ -51,10 +51,11 @@ public abstract class BaseHandler<C extends RocketComponent> extends AbstractEle
     /**
      * 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.
+     * @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
      */
 
@@ -70,7 +71,7 @@ public abstract class BaseHandler<C extends RocketComponent> extends AbstractEle
                 mass = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
             }
             if (RocksimCommonConstants.DENSITY.equals(element)) {
-                density = Math.max(0d, Double.parseDouble(content) );
+                density = Math.max(0d, Double.parseDouble(content));
             }
             if (RocksimCommonConstants.KNOWN_CG.equals(element)) {
                 cg = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
@@ -105,13 +106,14 @@ public abstract class BaseHandler<C extends RocketComponent> extends AbstractEle
     /**
      * 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.
-     *
+     * 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.
+     * <p/>
      * 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) {
@@ -119,14 +121,14 @@ public abstract class BaseHandler<C extends RocketComponent> extends AbstractEle
     }
 
     /**
-     * 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.
+     * 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
+     * @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) {
@@ -139,10 +141,10 @@ public abstract class BaseHandler<C extends RocketComponent> extends AbstractEle
     /**
      * 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
+     * @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) {
@@ -171,7 +173,7 @@ public abstract class BaseHandler<C extends RocketComponent> extends AbstractEle
     /**
      * 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
+     * @param theCG the CG value to really use when overriding CG on the OpenRocket component
      */
     protected void setCG(double theCG) {
         cg = theCG;
@@ -180,35 +182,62 @@ public abstract class BaseHandler<C extends RocketComponent> extends AbstractEle
     /**
      * Set the material name as specified in the Rocksim design file.
      *
-     * @param content  the material name
+     * @param content the material name
      */
     protected void setMaterialName(String content) {
         materialName = content;
     }
 
+    /**
+     * Get the Rocksim enum of the component's density type.
+     *
+     * @return a Rocksim density type
+     */
+    protected RocksimDensityType getDensityType() {
+        return densityType;
+    }
+
     /**
      * 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 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) {
+        return isCompatible(parent, child, warnings, false);
+    }
+
+    /**
+     * 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
+     * @param suppressWarnings suppress warnings, just return the boolean
+     *
+     * @return true if the child is compatible with parent
+     */
+    protected static boolean isCompatible(RocketComponent parent, Class<? extends RocketComponent> child,
+                                          WarningSet warnings,
+                                          boolean suppressWarnings) {
         if (!parent.isCompatible(child)) {
-            warnings.add(child.getName() + " can not be attached to "
-                         + parent.getComponentName() + ", ignoring component.");
+            if (!suppressWarnings) {
+                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.
+     * 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
@@ -224,8 +253,8 @@ public abstract class BaseHandler<C extends RocketComponent> extends AbstractEle
      * 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())
+     * @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 {
@@ -243,9 +272,9 @@ public abstract class BaseHandler<C extends RocketComponent> extends AbstractEle
     /**
      * 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
+     * @param component the component who's material is to be set
+     * @param name      the method name
+     * @param args      the class types of the parameters
      *
      * @return the Method instance, or null
      */
index ee8cd22db4aeb7977234aa6632c1c9cbd12b6a0f..2d918af9a4c49bc5d7951c51967228b364e25014 100644 (file)
@@ -5,9 +5,11 @@ package net.sf.openrocket.file.rocksim.importt;
 
 import net.sf.openrocket.aerodynamics.WarningSet;
 import net.sf.openrocket.file.rocksim.RocksimCommonConstants;
+import net.sf.openrocket.file.rocksim.RocksimDensityType;
 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.Coaxial;
 import net.sf.openrocket.rocketcomponent.MassComponent;
 import net.sf.openrocket.rocketcomponent.MassObject;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
@@ -21,12 +23,12 @@ import java.util.HashMap;
  */
 class MassObjectHandler extends PositionDependentHandler<MassObject> {
 
-    /** 
+    /**
      * 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.
+     * 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;
 
@@ -51,12 +53,12 @@ class MassObjectHandler extends PositionDependentHandler<MassObject> {
     private int typeCode = 0;
 
     /**
-     * Constructor.
-     *l
-     * @param c the parent component
-     * @param warnings  the warning set
-     * 
-     * @throws IllegalArgumentException  thrown if <code>c</code> is null
+     * 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) {
@@ -89,7 +91,7 @@ class MassObjectHandler extends PositionDependentHandler<MassObject> {
                 //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); 
+                super.setCG(0);
             }
             if (RocksimCommonConstants.TYPE_CODE.equals(element)) {
                 typeCode = Integer.parseInt(content);
@@ -104,32 +106,68 @@ class MassObjectHandler extends PositionDependentHandler<MassObject> {
     }
 
     @Override
-    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
-        if (typeCode == 0) { //General Mass Object
+    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws
+                                                                                                                    SAXException {
+        if (inferAsShockCord(typeCode, warnings)) { //Shock Cord
+            mapMassObjectAsShockCord(element, attributes, content, warnings);
+        }
+        else { // typeCode == 0   General Mass Object
             if (isCompatible(parent, MassComponent.class, warnings)) {
                 parent.addChild(mass);
             }
             super.endHandler(element, attributes, content, warnings);
         }
-        else if (typeCode == 1) { //Shock Cord
-            ShockCord cord = new ShockCord();
-            current = cord;
-            if (isCompatible(parent, ShockCord.class, warnings)) {
-                parent.addChild(cord);
-            }
-            super.endHandler(element, attributes, content, warnings);
-            cord.setName(mass.getName());
-
-            setOverride(cord, mass.isMassOverridden(), mass.getOverrideMass(), mass.getOverrideCGX());
+    }
 
-            cord.setRadialDirection(mass.getRadialDirection());
-            cord.setRadialPosition(mass.getRadialPosition());
-            cord.setRadius(mass.getRadius());
+    /**
+     * Rocksim does not have a separate entity for Shock Cords.  It has to be inferred.  Sometimes the typeCode
+     * indicates it's a shock cord, but most times it does not.  This is due to bugs in the Rocksim Component and
+     * Material databases.  Try to infer a shock cord based on it's length and it's material type.  It's somewhat
+     * arbitrary, but if the mass object's length is more than twice the length of it's parent component and it's a LINE
+     * material, then assume a shock cord.
+     *
+     * @param theTypeCode the code from the RKT XML file
+     *
+     * @return true if we think it's a shock cord
+     */
+    private boolean inferAsShockCord(int theTypeCode, WarningSet warnings) {
+        return (theTypeCode == 1 || (mass.getLength() >= 2 * parent.getLength() && RocksimDensityType.ROCKSIM_LINE
+                .equals(getDensityType()))) && isCompatible(parent, ShockCord.class, warnings, true);
+    }
 
-            //Rocksim does not distinguish between total length of the cord and the packed length.  Fudge the
-            //packed length and set the real length.
-            cord.setCordLength(mass.getLength());
-            cord.setLength(cord.getCordLength()/MASS_LEN_FUDGE_FACTOR);
+    /**
+     * If it appears that the mass object is a shock cord, then create an OR shock cord instance.
+     *
+     * @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
+     */
+    private void mapMassObjectAsShockCord(final String element, final HashMap<String, String> attributes,
+                                          final String content, final WarningSet warnings) throws SAXException {
+        ShockCord cord = new ShockCord();
+        current = cord;
+        if (isCompatible(parent, ShockCord.class, warnings)) {
+            parent.addChild(cord);
+        }
+        super.endHandler(element, attributes, content, warnings);
+        cord.setName(mass.getName());
+
+        setOverride(cord, mass.isMassOverridden(), mass.getOverrideMass(), mass.getOverrideCGX());
+
+        cord.setRadialDirection(mass.getRadialDirection());
+        cord.setRadialPosition(mass.getRadialPosition());
+        cord.setRadius(mass.getRadius());
+
+        //Rocksim does not distinguish between total length of the cord and the packed length.  Fudge the
+        //packed length and set the real length.
+        cord.setCordLength(mass.getLength());
+        cord.setLength(cord.getCordLength() / MASS_LEN_FUDGE_FACTOR);
+        if (parent instanceof Coaxial) {
+            Coaxial parentCoaxial = (Coaxial) parent;
+            cord.setRadius(parentCoaxial.getInnerRadius());
         }
     }
 
@@ -154,7 +192,8 @@ class MassObjectHandler extends PositionDependentHandler<MassObject> {
     }
 
     /**
-     * Get the required type of material for this component.  Does not apply to MassComponents, but does apply to Shock Cords.
+     * Get the required type of material for this component.  Does not apply to MassComponents, but does apply to Shock
+     * Cords.
      *
      * @return LINE
      */