Merge commit '42b2e5ca519766e37ce6941ba4faecc9691cc403' into upstream
[debian/openrocket] / core / src / net / sf / openrocket / file / rocksim / importt / MassObjectHandler.java
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
      */