]> git.gag.com Git - debian/openrocket/commitdiff
DGP - minor refactorings and added JavaDoc
authorrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Sun, 22 Jan 2012 22:58:08 +0000 (22:58 +0000)
committerrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Sun, 22 Jan 2012 22:58:08 +0000 (22:58 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@364 180e2498-e6e9-4542-8430-84ac67f01cd8

22 files changed:
core/src/net/sf/openrocket/file/rocksim/RocksimCommonConstants.java
core/src/net/sf/openrocket/file/rocksim/export/AbstractTransitionDTO.java
core/src/net/sf/openrocket/file/rocksim/export/AttachableParts.java [new file with mode: 0644]
core/src/net/sf/openrocket/file/rocksim/export/AttachedParts.java [deleted file]
core/src/net/sf/openrocket/file/rocksim/export/BodyTubeDTO.java
core/src/net/sf/openrocket/file/rocksim/export/BulkheadDTO.java
core/src/net/sf/openrocket/file/rocksim/export/CenteringRingDTO.java
core/src/net/sf/openrocket/file/rocksim/export/EngineBlockDTO.java
core/src/net/sf/openrocket/file/rocksim/export/FinSetDTO.java
core/src/net/sf/openrocket/file/rocksim/export/InnerBodyTubeDTO.java
core/src/net/sf/openrocket/file/rocksim/export/LaunchLugDTO.java
core/src/net/sf/openrocket/file/rocksim/export/MassObjectDTO.java
core/src/net/sf/openrocket/file/rocksim/export/NoseConeDTO.java
core/src/net/sf/openrocket/file/rocksim/export/ParachuteDTO.java
core/src/net/sf/openrocket/file/rocksim/export/RocketDesignDTO.java
core/src/net/sf/openrocket/file/rocksim/export/StageDTO.java
core/src/net/sf/openrocket/file/rocksim/export/StreamerDTO.java
core/src/net/sf/openrocket/file/rocksim/export/TransitionDTO.java
core/src/net/sf/openrocket/file/rocksim/importt/AttachedPartsHandler.java
core/src/net/sf/openrocket/file/rocksim/importt/FinSetHandler.java
core/src/net/sf/openrocket/file/rocksim/importt/RocksimHandler.java
core/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java

index f0d9c859cd3e0b8c2d9a618a42b36b89455763e7..d44ef1a27e0990475ad8a8662096e33bd421584a 100644 (file)
@@ -102,4 +102,7 @@ public class RocksimCommonConstants {
      * Radius conversion.  Rocksim is always in diameters, OpenRocket mostly in radius.
      */
     public static final int ROCKSIM_TO_OPENROCKET_RADIUS = 2 * ROCKSIM_TO_OPENROCKET_LENGTH;
+    public static final String TUBE_FIN_SET = "TubeFinSet";
+    public static final String RING_TAIL = "RingTail";
+    public static final String EXTERNAL_POD = "ExternalPod";
 }
index d729ebdd3b566ad39f3bc829c5888fea5653ecb4..987bc203362be60ce3aed7d2b24f92eca952c487 100644 (file)
@@ -29,7 +29,7 @@ import java.util.List;
  * Transition to a Rocksim Transition.
  */
 @XmlAccessorType(XmlAccessType.FIELD)
-public class AbstractTransitionDTO extends BasePartDTO implements AttachedParts {
+public class AbstractTransitionDTO extends BasePartDTO implements AttachableParts {
 
     @XmlElement(name = RocksimCommonConstants.SHAPE_CODE)
     private int shapeCode = 1;
diff --git a/core/src/net/sf/openrocket/file/rocksim/export/AttachableParts.java b/core/src/net/sf/openrocket/file/rocksim/export/AttachableParts.java
new file mode 100644 (file)
index 0000000..61b6f4d
--- /dev/null
@@ -0,0 +1,21 @@
+package net.sf.openrocket.file.rocksim.export;
+
+/**
+ * An interface that defines methods for attaching and detaching child components.  Rocksim has a special
+ * XML element that acts as a container, called <pre><AttachedParts></AttachedParts></pre>.  Implementors of
+ * this interface are those Rocksim DTO classes that support the attached parts element.
+ */
+public interface AttachableParts {
+    /**
+     * Remove a previously attached part from this component.
+     *
+     * @param part  the instance to remove
+     */
+    void removeAttachedPart(BasePartDTO part);
+
+    /**
+     * Attach (associate) a DTO with this component.
+     * @param part
+     */
+    void addAttachedPart(BasePartDTO part);
+}
diff --git a/core/src/net/sf/openrocket/file/rocksim/export/AttachedParts.java b/core/src/net/sf/openrocket/file/rocksim/export/AttachedParts.java
deleted file mode 100644 (file)
index a7a8c30..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.sf.openrocket.file.rocksim.export;
-
-/**
- */
-public interface AttachedParts {
-    void removeAttachedPart(BasePartDTO part);
-
-    void addAttachedPart(BasePartDTO part);
-}
index 3a043a0cf22ce1ff1699e7d7ebbc624a68a0e0b8..4f9f708d941b66755f24083879d5f3cb592cbb1a 100644 (file)
@@ -27,10 +27,11 @@ import java.util.ArrayList;
 import java.util.List;
 
 /**
+ * Models the XML element for a Rocksim body tube.
  */
 @XmlRootElement(name = RocksimCommonConstants.BODY_TUBE)
 @XmlAccessorType(XmlAccessType.FIELD)
-public class BodyTubeDTO extends BasePartDTO implements AttachedParts {
+public class BodyTubeDTO extends BasePartDTO implements AttachableParts {
 
     @XmlElement(name = RocksimCommonConstants.OD)
     private double od = 0d;
@@ -57,28 +58,42 @@ public class BodyTubeDTO extends BasePartDTO implements AttachedParts {
             @XmlElementRef(name = RocksimCommonConstants.MASS_OBJECT, type = MassObjectDTO.class)})
     List<BasePartDTO> attachedParts = new ArrayList<BasePartDTO>();
 
+    /**
+     * Constructor.
+     */
     public BodyTubeDTO() {
     }
 
-    public BodyTubeDTO(InnerTube inner) {
-        super(inner);
+    /**
+     * Copy constructor.
+     *
+     * @param theORInnerTube  an OR inner tube; used by subclasses
+     */
+    protected BodyTubeDTO(InnerTube theORInnerTube) {
+        super(theORInnerTube);
     }
 
-    protected BodyTubeDTO(BodyTube bt) {
-        super(bt);
+    /**
+     * Copy constructor.
+     *
+     * @param theORBodyTube an OR body tube
+     */
+    protected BodyTubeDTO(BodyTube theORBodyTube) {
+        super(theORBodyTube);
 
-        setEngineOverhang(bt.getMotorOverhang() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
-        setID(bt.getInnerRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
-        setOD(bt.getOuterRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
-        setMotorDia((bt.getMotorMountDiameter() / 2) * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
-        setMotorMount(bt.isMotorMount());
+        setEngineOverhang(theORBodyTube.getMotorOverhang() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setID(theORBodyTube.getInnerRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setOD(theORBodyTube.getOuterRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setMotorDia((theORBodyTube.getMotorMountDiameter() / 2) * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setMotorMount(theORBodyTube.isMotorMount());
 
-        List<RocketComponent> children = bt.getChildren();
+        List<RocketComponent> children = theORBodyTube.getChildren();
         for (int i = 0; i < children.size(); i++) {
             RocketComponent rocketComponents = children.get(i);
             if (rocketComponents instanceof InnerTube) {
                 final InnerTube innerTube = (InnerTube) rocketComponents;
                 final InnerBodyTubeDTO innerBodyTubeDTO = new InnerBodyTubeDTO(innerTube, this);
+                //Only add the inner tube if it is NOT a cluster.
                 if (innerTube.getClusterCount() == 1) {
                     attachedParts.add(innerBodyTubeDTO);
                 }
index 847c7dc2390dcb8d8858db2b77d0729829130b47..e8b78e11f57c77ce3885c7c79c69769660168997 100644 (file)
@@ -17,10 +17,10 @@ public class BulkheadDTO extends CenteringRingDTO {
     /**
      * Constructor.
      *
-     * @param bh bulkhead
+     * @param theORBulkhead the OR bulkhead
      */
-    public BulkheadDTO(Bulkhead bh) {
-        super(bh);
+    public BulkheadDTO(Bulkhead theORBulkhead) {
+        super(theORBulkhead);
         setUsageCode(CenteringRingDTO.UsageCode.Bulkhead);
     }
 }
index 742999a378776daedb4a8b26da648bc33fc09bfe..e925c10f2d75ab04cb33f6c7c99a076a7c737477 100644 (file)
@@ -42,20 +42,34 @@ public class CenteringRingDTO extends BasePartDTO {
     @XmlElement(name = RocksimCommonConstants.AUTO_SIZE)
     private int autoSize = 0;
 
+    /**
+     * Default Constructor.
+     */
     public CenteringRingDTO() {
-
     }
-    public CenteringRingDTO(RadiusRingComponent cr) {
-        super(cr);
-        setId(cr.getInnerRadius()* RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
-        setOd(cr.getOuterRadius()* RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+
+    /**
+     * Copy constructor.
+     *
+     * @param theORRadiusRing
+     */
+    public CenteringRingDTO(RadiusRingComponent theORRadiusRing) {
+        super(theORRadiusRing);
+        setId(theORRadiusRing.getInnerRadius()* RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setOd(theORRadiusRing.getOuterRadius()* RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
     }
 
-    public CenteringRingDTO(ThicknessRingComponent trc) {
-        super(trc);
-        setId(trc.getInnerRadius()* RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
-        setOd(trc.getOuterRadius()* RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+    /**
+     * Copy constructor.
+     *
+     * @param theORThicknessRing
+     */
+    public CenteringRingDTO(ThicknessRingComponent theORThicknessRing) {
+        super(theORThicknessRing);
+        setId(theORThicknessRing.getInnerRadius()* RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setOd(theORThicknessRing.getOuterRadius()* RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
     }
+
     public double getOd() {
         return od;
     }
index bcb6d575147f019b810cdeeddbf653dd1e4b4097..6a742fb343cb03b8f141e2b422ae3768ac6d3542 100644 (file)
@@ -7,13 +7,20 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
 
 /**
+ * Models a Rocksim XML Element for an EngineBlock.  EngineBlocks in Rocksim are treated as rings with a special
+ * usage code.
  */
 @XmlRootElement(name = "Ring")
 @XmlAccessorType(XmlAccessType.FIELD)
 public class EngineBlockDTO extends CenteringRingDTO{
-    
-    public EngineBlockDTO(EngineBlock eb) {
-        super(eb);
+
+    /**
+     * Copy constructor.
+     *
+     * @param theOREngineBlock
+     */
+    public EngineBlockDTO(EngineBlock theOREngineBlock) {
+        super(theOREngineBlock);
         setUsageCode(UsageCode.EngineBlock);
     }
 }
index b8238dd7eb0be88d3d48311082c2c34430911317..0879c3b78abe9199851a9af6e7413f4e00bd0ba6 100644 (file)
@@ -13,6 +13,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
 /**
+ * This class models XML elements for Rocksim finsets.
  */
 @XmlRootElement(name = RocksimCommonConstants.FIN_SET)
 @XmlAccessorType(XmlAccessType.FIELD)
@@ -45,36 +46,44 @@ public class FinSetDTO extends BasePartDTO {
     @XmlElement(name = RocksimCommonConstants.CANT_ANGLE)
     private double cantAngle = 0d;
 
+    /**
+     * Constructor.
+     */
     public FinSetDTO() {
     }
 
-    public FinSetDTO(FinSet ec) {
-        super(ec);
-
-        setFinCount(ec.getFinCount());
-        setCantAngle(ec.getCantAngle());
-        setTabDepth(ec.getTabHeight() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
-        setTabLength(ec.getTabLength() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
-        setTabOffset(ec.getTabShift() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
-        setThickness(ec.getThickness() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
-
-        setRadialAngle(ec.getBaseRotation());
-        setTipShapeCode(TipShapeCode.convertTipShapeCode(ec.getCrossSection()));
-        if (ec instanceof TrapezoidFinSet) {
-            TrapezoidFinSet tfs = (TrapezoidFinSet) ec;
+    /**
+     * Full copy constructor.
+     *
+     * @param theORFinSet  the OpenRocket finset
+     */
+    public FinSetDTO(FinSet theORFinSet) {
+        super(theORFinSet);
+
+        setFinCount(theORFinSet.getFinCount());
+        setCantAngle(theORFinSet.getCantAngle());
+        setTabDepth(theORFinSet.getTabHeight() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setTabLength(theORFinSet.getTabLength() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setTabOffset(theORFinSet.getTabShift() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setThickness(theORFinSet.getThickness() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+
+        setRadialAngle(theORFinSet.getBaseRotation());
+        setTipShapeCode(TipShapeCode.convertTipShapeCode(theORFinSet.getCrossSection()));
+        if (theORFinSet instanceof TrapezoidFinSet) {
+            TrapezoidFinSet tfs = (TrapezoidFinSet) theORFinSet;
             setShapeCode(0);
-            setRootChord(ec.getLength() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+            setRootChord(theORFinSet.getLength() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
             setSemiSpan(tfs.getHeight() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
             setTipChord(tfs.getTipChord() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
             setSweepDistance(tfs.getSweep() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
         }
-        else if (ec instanceof EllipticalFinSet) {
-            EllipticalFinSet efs = (EllipticalFinSet) ec;
+        else if (theORFinSet instanceof EllipticalFinSet) {
+            EllipticalFinSet efs = (EllipticalFinSet) theORFinSet;
             setShapeCode(1);
-            setRootChord(ec.getLength() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+            setRootChord(theORFinSet.getLength() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
             setSemiSpan(efs.getHeight() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
         }
-        else if (ec instanceof FreeformFinSet) {
+        else if (theORFinSet instanceof FreeformFinSet) {
             setShapeCode(2);
         }
     }
index c52c4b80fcf87466c25ea47f36805536a5ecc06e..8b040395ed05088fe94eb4c5c1fbb991aaa01d9d 100644 (file)
@@ -1,10 +1,10 @@
 package net.sf.openrocket.file.rocksim.export;
 
 import net.sf.openrocket.file.rocksim.RocksimCommonConstants;
+import net.sf.openrocket.gui.configdialog.InnerTubeConfig;
 import net.sf.openrocket.rocketcomponent.BodyTube;
 import net.sf.openrocket.rocketcomponent.Bulkhead;
 import net.sf.openrocket.rocketcomponent.CenteringRing;
-import net.sf.openrocket.rocketcomponent.ClusterConfiguration;
 import net.sf.openrocket.rocketcomponent.EngineBlock;
 import net.sf.openrocket.rocketcomponent.InnerTube;
 import net.sf.openrocket.rocketcomponent.MassObject;
@@ -21,16 +21,29 @@ import javax.xml.bind.annotation.XmlRootElement;
 import java.util.List;
 
 /**
+ * This class models the XML element for a Rocksim inside tube.
  */
 @XmlRootElement(name = RocksimCommonConstants.BODY_TUBE)
 @XmlAccessorType(XmlAccessType.FIELD)
-public class InnerBodyTubeDTO extends BodyTubeDTO implements AttachedParts {
+public class InnerBodyTubeDTO extends BodyTubeDTO implements AttachableParts {
 
+    /**
+     * Constructor.
+     */
     public InnerBodyTubeDTO() {
         super.setInsideTube(true);
     }
 
-    public InnerBodyTubeDTO(InnerTube bt, AttachedParts parent) {
+    /**
+     * Full copy constructor.
+     *
+     * @param bt     the corresponding OR inner body tube
+     * @param parent the attached parts (subcomponents in Rocksim speak) of the InnerTube's parent.  This instance
+     *               is a member of those attached parts, as well as all sibling components.  This is passed in the
+     *               event that the inner tube is a cluster.  In that situation this instance will be removed and
+     *               individual instances for each cluster member will be added.
+     */
+    public InnerBodyTubeDTO(InnerTube bt, AttachableParts parent) {
         super(bt);
         setEngineOverhang(bt.getMotorOverhang() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
         setID(bt.getInnerRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
@@ -41,35 +54,37 @@ public class InnerBodyTubeDTO extends BodyTubeDTO implements AttachedParts {
         setRadialAngle(bt.getRadialDirection());
         setRadialLoc(bt.getRadialPosition() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
 
-            List<RocketComponent> children = bt.getChildren();
-            for (int i = 0; i < children.size(); i++) {
-                RocketComponent rocketComponents = children.get(i);
-                if (rocketComponents instanceof InnerTube) {
-                    final InnerTube innerTube = (InnerTube) rocketComponents;
-                    if (innerTube.getClusterCount() == 1) {
-                        attachedParts.add(new InnerBodyTubeDTO(innerTube, this));
-                    }
-                } 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));
+        List<RocketComponent> children = bt.getChildren();
+        for (int i = 0; i < children.size(); i++) {
+            RocketComponent rocketComponents = children.get(i);
+            if (rocketComponents instanceof InnerTube) {
+                final InnerTube innerTube = (InnerTube) rocketComponents;
+                //Only if the inner tube is NOT a cluster, then create the corresponding Rocksim DTO and add it
+                //to the list of attached parts.  If it is a cluster, then it is handled specially outside of this
+                //loop.
+                if (innerTube.getClusterCount() == 1) {
+                    attachedParts.add(new InnerBodyTubeDTO(innerTube, this));
                 }
+            } 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));
             }
-
+        }
         //Do the cluster.  For now this splits the cluster into separate tubes, which is how Rocksim represents it.
         //The import (from Rocksim to OR) could be augmented to be more intelligent and try to determine if the
         //co-located tubes are a cluster.
@@ -79,25 +94,24 @@ public class InnerBodyTubeDTO extends BodyTubeDTO implements AttachedParts {
         }
     }
 
-    private void handleCluster(InnerTube it, AttachedParts p) {
+
+    /**
+     * Handle the inner tube as a cluster.  This amounts to splitting it up so that each motor mount in the cluster
+     * is created individually to support Rocksim's view of clusters.
+     *
+     * @param it  the clustered tube
+     * @param p   the collection (parent's attached parts really) to which all cluster tubes will be added
+     */
+    private void handleCluster(InnerTube it, AttachableParts p) {
 
         Coordinate[] coords = {Coordinate.NUL};
         coords = it.shiftCoordinates(coords);
         for (int x = 0; x < coords.length; x++) {
-            InnerTube copy = (InnerTube) it.copy();
-            copy.setClusterConfiguration(ClusterConfiguration.SINGLE);
-            copy.setClusterRotation(0.0);
-            copy.setClusterScale(1.0);
-            copy.setRadialShift(coords[x].y, coords[x].z);
-            copy.setName(copy.getName() + " #" + (x + 1));
-            p.addAttachedPart(copy(copy, p));
+            InnerTube partialClone = InnerTubeConfig.makeIndividualClusterComponent(coords[x], it.getName() + " #" + (x + 1), it);
+            p.addAttachedPart(new InnerBodyTubeDTO(partialClone, p));
         }
     }
 
-    private InnerBodyTubeDTO copy(InnerTube it, AttachedParts p) {
-        return new InnerBodyTubeDTO(it, p);
-    }
-
     @Override
     public void addAttachedPart(BasePartDTO part) {
         attachedParts.add(part);
index 27408228860c6ff5771806ac284ef98939828e05..4c287202be05afe78efa4977130a5e76213bc31d 100644 (file)
@@ -9,6 +9,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
 /**
+ * This class models an XML element for a Rocksim LaunchLug.
  */
 @XmlRootElement(name = RocksimCommonConstants.LAUNCH_LUG)
 @XmlAccessorType(XmlAccessType.FIELD)
@@ -19,14 +20,22 @@ public class LaunchLugDTO extends BasePartDTO {
     @XmlElement(name = RocksimCommonConstants.ID)
     private double id = 0d;
 
+    /**
+     * Default constructor.
+     */
     public LaunchLugDTO() {
     }
 
-    public LaunchLugDTO(LaunchLug ec) {
-        super(ec);
-        setId(ec.getInnerRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
-        setOd(ec.getOuterRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
-        setRadialAngle(ec.getRadialDirection());
+    /**
+     * Copy constructor.  Fully populates this instance with values taken from the OR LaunchLug.
+     *
+     * @param theORLaunchLug
+     */
+    public LaunchLugDTO(LaunchLug theORLaunchLug) {
+        super(theORLaunchLug);
+        setId(theORLaunchLug.getInnerRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setOd(theORLaunchLug.getOuterRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setRadialAngle(theORLaunchLug.getRadialDirection());
     }
 
     public double getOd() {
index 74a0347dd507857faa3c97cc4c5fc604409ff5ac..85782b27b7d7bbcdc8256227716e71820929a22a 100644 (file)
@@ -25,7 +25,7 @@ public class MassObjectDTO extends BasePartDTO{
     }
 
     /**
-     * Typed constructor.
+     * Typed copy constructor.
      *
      * @param mo  OR MassObject
      */
index aa838e0df8643327ec08bfc05aa4a7193e884f67..79914c1326c053abd8dfd26560a4c080d88e78dd 100644 (file)
@@ -9,6 +9,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
 /**
+ * This class models a Rocksim XML Element for a nose cone.
  */
 @XmlRootElement(name = RocksimCommonConstants.NOSE_CONE)
 @XmlAccessorType(XmlAccessType.FIELD)
@@ -29,7 +30,7 @@ public class NoseConeDTO extends AbstractTransitionDTO {
     }
 
     /**
-     * Full copy constructor.
+     * Full copy constructor.  Fully populates this instance with values taken from the OR NoseCone instance.
      *
      * @param nc  the OR nose cone
      */
index 5b4dcef5ac2df940ee47046105066d2769549742..7f0f25077b5b1dd6ddf0ba69334bb93b3bef93b0 100644 (file)
@@ -31,21 +31,29 @@ public class ParachuteDTO extends BasePartDTO {
     private String shroudLineMaterial = "";
     @XmlElement(name = RocksimCommonConstants.DRAG_COEFFICIENT)
     private double dragCoefficient = 0.75d;
-    
+
+    /**
+     * Default constructor.
+     */
     public ParachuteDTO() {
     }
 
-    public ParachuteDTO(Parachute ec) {
-        super(ec);
+    /**
+     * Copy constructor.  Fully populates this instance with values taken from the corresponding OR Parachute.
+     *
+     * @param theORParachute  the OR Parachute instance
+     */
+    public ParachuteDTO(Parachute theORParachute) {
+        super(theORParachute);
         
         setChuteCount(1);
-        setDia(ec.getDiameter() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
-        setDragCoefficient(ec.getCD());
-        setShroudLineCount(ec.getLineCount());
-        setShroudLineLen(ec.getLineLength() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setDia(theORParachute.getDiameter() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setDragCoefficient(theORParachute.getCD());
+        setShroudLineCount(theORParachute.getLineCount());
+        setShroudLineLen(theORParachute.getLineLength() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
 
-        String material = ec.getLineMaterial().getName();
-        setShroudLineMassPerMM(ec.getLineMaterial().getDensity() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LINE_DENSITY);
+        String material = theORParachute.getLineMaterial().getName();
+        setShroudLineMassPerMM(theORParachute.getLineMaterial().getDensity() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LINE_DENSITY);
 
         if (material.startsWith(BaseHandler.ROCKSIM_MATERIAL_PREFIX)) {
             material = material.substring(BaseHandler.ROCKSIM_MATERIAL_PREFIX.length());
index 697b5af82338e11fa3a2615024022c0b4977787d..10ecf38c3c43d032892c3d9ce486cc924fefbfb6 100644 (file)
@@ -5,6 +5,8 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 
 /**
+ * This class models a Rocksim XML element for a rocket design container.  It's really nothing more than
+ * a bunch of boilerplate XML that does not change, coupled with the stage DTOs that are part of the rocket design.
  */
 @XmlAccessorType(XmlAccessType.FIELD)
 public class RocketDesignDTO {
@@ -67,6 +69,9 @@ public class RocketDesignDTO {
     @XmlElement(name = "Stage1Parts", required = false, nillable = false)
     private StageDTO stage1 = new StageDTO();
 
+    /**
+     * Default constructor.
+     */
     public RocketDesignDTO() {
     }
 
index 3146619c9899ee64d3f7079718ae3f6ea1711c54..e0303e7fc54b456910df55a1e113151b184ac1aa 100644 (file)
@@ -33,39 +33,46 @@ public class StageDTO {
     public StageDTO() {
     }
 
-    public StageDTO(Stage stage, RocketDesignDTO design, int stageNumber) {
+    /**
+     * Copy constructor.
+     *
+     * @param theORStage  the OR stage
+     * @param design      the encompassing container DTO
+     * @param stageNumber the stage number (3 is always at the top, even if it's the only one)
+     */
+    public StageDTO(Stage theORStage, RocketDesignDTO design, int stageNumber) {
 
         if (stageNumber == 3) {
-            if (stage.isMassOverridden()) {
-                design.setStage3Mass(stage.getMass() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
+            if (theORStage.isMassOverridden()) {
+                design.setStage3Mass(theORStage.getMass() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
                 design.setUseKnownMass(1);
             }
-            if (stage.isCGOverridden()) {
-                design.setStage3CG(stage.getOverrideCGX() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+            if (theORStage.isCGOverridden()) {
+                design.setStage3CG(theORStage.getOverrideCGX() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
             }
         }
         
         if (stageNumber == 2) {
-            if (stage.isMassOverridden()) {
-                design.setStage2Mass(stage.getMass() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
+            if (theORStage.isMassOverridden()) {
+                design.setStage2Mass(theORStage.getMass() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
                 design.setUseKnownMass(1);
             }
-            if (stage.isCGOverridden()) {
-                design.setStage2CGAlone(stage.getOverrideCGX() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+            if (theORStage.isCGOverridden()) {
+                design.setStage2CGAlone(theORStage.getOverrideCGX() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
             }
         }
 
         if (stageNumber == 1) {
-            if (stage.isMassOverridden()) {
-                design.setStage1Mass(stage.getMass() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
+            if (theORStage.isMassOverridden()) {
+                design.setStage1Mass(theORStage.getMass() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
                 design.setUseKnownMass(1);
             }
-            if (stage.isCGOverridden()) {
-                design.setStage1CGAlone(stage.getOverrideCGX() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+            if (theORStage.isCGOverridden()) {
+                design.setStage1CGAlone(theORStage.getOverrideCGX() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
             }
         }
 
-        List<RocketComponent> children = stage.getChildren();
+        List<RocketComponent> children = theORStage.getChildren();
         for (int i = 0; i < children.size(); i++) {
             RocketComponent rocketComponents = children.get(i);
             if (rocketComponents instanceof NoseCone) {
index dbcd6489551934766bbda226260f4ae00f22b82b..c959ce546c04e2dff871124cf629a6e2241b42f4 100644 (file)
@@ -9,6 +9,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
 /**
+ * This class models a Rocksim XML element for a streamer.
  */
 @XmlRootElement(name = RocksimCommonConstants.STREAMER)
 @XmlAccessorType(XmlAccessType.FIELD)
@@ -19,13 +20,21 @@ public class StreamerDTO extends BasePartDTO {
         @XmlElement(name = RocksimCommonConstants.DRAG_COEFFICIENT)
         private double dragCoefficient = 0.75d;
 
+    /**
+     * The default constructor.
+     */
     public StreamerDTO() {
     }
 
-    public StreamerDTO(Streamer ec) {
-        super(ec);
-        setWidth(ec.getStripWidth() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
-        setDragCoefficient(ec.getCD());
+    /**
+     * Copy constructor.  This constructor fully populates this instance with values taken from the OR component.
+     *
+     * @param theORStreamer  the OR streamer component
+     */
+    public StreamerDTO(Streamer theORStreamer) {
+        super(theORStreamer);
+        setWidth(theORStreamer.getStripWidth() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setDragCoefficient(theORStreamer.getCD());
     }
 
     public double getWidth() {
index bf46747669c498b0ae475358dd7b2d326082a02f..563605601b481b759be6f7618dd4a62888d43d48 100644 (file)
@@ -9,6 +9,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
 /**
+ * This class models a transition XML element in Rocksim file format.
  */
 @XmlRootElement(name = RocksimCommonConstants.TRANSITION)
 @XmlAccessorType(XmlAccessType.FIELD)
@@ -28,17 +29,26 @@ public class TransitionDTO extends AbstractTransitionDTO {
     @XmlElement(name = RocksimCommonConstants.REAR_DIA)
     private double rearDia = 0d;
 
+    /**
+     * Default constructor.
+     */
     public TransitionDTO() {
     }
 
-    public TransitionDTO(Transition tran) {
-        super(tran);
-        setFrontDia(tran.getForeRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
-        setRearDia(tran.getAftRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
-        setFrontShoulderDia(tran.getForeShoulderRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
-        setFrontShoulderLen(tran.getForeShoulderLength() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
-        setRearShoulderDia(tran.getAftShoulderRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
-        setRearShoulderLen(tran.getAftShoulderLength() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+    /**
+     * Copy constructor.  This TransitionDTO instance will be as equivalent as possible to the OR <code>tran</code>
+     * once the constructor returns.  No further modification (invoking setters) is necessary.
+     *
+     * @param theORTransition  the OR transition
+     */
+    public TransitionDTO(Transition theORTransition) {
+        super(theORTransition);
+        setFrontDia(theORTransition.getForeRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setRearDia(theORTransition.getAftRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setFrontShoulderDia(theORTransition.getForeShoulderRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setFrontShoulderLen(theORTransition.getForeShoulderLength() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+        setRearShoulderDia(theORTransition.getAftShoulderRadius() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
+        setRearShoulderLen(theORTransition.getAftShoulderLength() * RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
 
 
     }
index 155fdd8900a1ea8baff98b755adad8edbc8574e2..bfb7692ad31d2b3e1f9395d52c2536e390559278 100644 (file)
@@ -60,13 +60,13 @@ class AttachedPartsHandler extends ElementHandler {
         if (RocksimCommonConstants.TRANSITION.equals(element)) {
             return new TransitionHandler(component, warnings);
         }
-        if ("TubeFinSet".equals(element)) {
+        if (RocksimCommonConstants.TUBE_FIN_SET.equals(element)) {
             warnings.add("Tube fins are not currently supported. Ignoring.");
         }
-        if ("RingTail".equals(element)) {
+        if (RocksimCommonConstants.RING_TAIL.equals(element)) {
             warnings.add("Ring tails are not currently supported. Ignoring.");
         }
-        if ("ExternalPod".equals(element)) {
+        if (RocksimCommonConstants.EXTERNAL_POD.equals(element)) {
             warnings.add("Pods are not currently supported. Ignoring.");
         }
         return null;
index 693792a33b44ed37250810c0f887a1d82ae3b300..9b42617b0ffa2a09443aae64d3dd6d3ed01b02b4 100644 (file)
@@ -162,79 +162,79 @@ class FinSetHandler extends ElementHandler {
     public void closeElement (String element, HashMap<String, String> attributes, String content, WarningSet warnings)
             throws SAXException {
         try {
-            if ("Name".equals(element)) {
+            if (RocksimCommonConstants.NAME.equals(element)) {
                 name = content;
             }
-            if ("Material".equals(element)) {
+            if (RocksimCommonConstants.MATERIAL.equals(element)) {
                 materialName = content;
             }
-            if ("FinishCode".equals(element)) {
+            if (RocksimCommonConstants.FINISH_CODE.equals(element)) {
                 finish = RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket();
             }
-            if ("Xb".equals(element)) {
+            if (RocksimCommonConstants.XB.equals(element)) {
                 location = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
             }
-            if ("LocationMode".equals(element)) {
+            if (RocksimCommonConstants.LOCATION_MODE.equals(element)) {
                 position = RocksimLocationMode.fromCode(Integer.parseInt(content)).asOpenRocket();
             }
-            if ("FinCount".equals(element)) {
+            if (RocksimCommonConstants.FIN_COUNT.equals(element)) {
                 finCount = Integer.parseInt(content);
             }
-            if ("RootChord".equals(element)) {
+            if (RocksimCommonConstants.ROOT_CHORD.equals(element)) {
                 rootChord = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
             }
-            if ("TipChord".equals(element)) {
+            if (RocksimCommonConstants.TIP_CHORD.equals(element)) {
                 tipChord = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
             }
-            if ("SemiSpan".equals(element)) {
+            if (RocksimCommonConstants.SEMI_SPAN.equals(element)) {
                 semiSpan = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
             }
             if ("MidChordLen".equals(element)) {
                 midChordLen = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
             }
-            if ("SweepDistance".equals(element)) {
+            if (RocksimCommonConstants.SWEEP_DISTANCE.equals(element)) {
                 sweepDistance = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
             }
-            if ("Thickness".equals(element)) {
+            if (RocksimCommonConstants.THICKNESS.equals(element)) {
                 thickness = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
             }
-            if ("TipShapeCode".equals(element)) {
+            if (RocksimCommonConstants.TIP_SHAPE_CODE.equals(element)) {
                 tipShapeCode = Integer.parseInt(content);
             }
-            if ("TabLength".equals(element)) {
+            if (RocksimCommonConstants.TAB_LENGTH.equals(element)) {
                 tabLength = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
             }
-            if ("TabDepth".equals(element)) {
+            if (RocksimCommonConstants.TAB_DEPTH.equals(element)) {
                 tabDepth = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
             }
-            if ("TabOffset".equals(element)) {
+            if (RocksimCommonConstants.TAB_OFFSET.equals(element)) {
                 taboffset = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
             }
-            if ("RadialAngle".equals(element)) {
+            if (RocksimCommonConstants.RADIAL_ANGLE.equals(element)) {
                 radialAngle = Double.parseDouble(content);
             }
-            if ("ShapeCode".equals(element)) {
+            if (RocksimCommonConstants.SHAPE_CODE.equals(element)) {
                 shapeCode = Integer.parseInt(content);
             }
-            if ("PointList".equals(element)) {
+            if (RocksimCommonConstants.POINT_LIST.equals(element)) {
                 pointList = content;
             }
-            if ("KnownMass".equals(element)) {
+            if (RocksimCommonConstants.KNOWN_MASS.equals(element)) {
                 mass = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
             }
-            if ("Density".equals(element)) {
+            if (RocksimCommonConstants.DENSITY.equals(element)) {
                 density = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_BULK_DENSITY);
             }
-            if ("KnownCG".equals(element)) {
+            if (RocksimCommonConstants.KNOWN_CG.equals(element)) {
                 cg = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
             }
-            if ("UseKnownCG".equals(element)) {
+            if (RocksimCommonConstants.USE_KNOWN_CG.equals(element)) {
                 override = "1".equals(content);
             }
-            if ("CalcMass".equals(element)) {
+            if (RocksimCommonConstants.CALC_MASS.equals(element)) {
                 calcMass = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS;
             }
-            if ("CalcCg".equals(element)) {
+            if (RocksimCommonConstants.CALC_CG.equals(element)) {
                 calcCg = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
             }
         }
index 6b5765e2a10a3567275ab230c6207181b5cd981f..9228d6b102654fe7a37b9f295b8b0a0fea4ae81f 100644 (file)
@@ -103,15 +103,15 @@ class RocksimContentHandler extends ElementHandler {
     @Override
     public ElementHandler openElement(String element, HashMap<String, String> attributes,
                                       WarningSet warnings) {
-        if ("DesignInformation".equals(element)) {
+        if (RocksimCommonConstants.DESIGN_INFORMATION.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)) {
+        if (RocksimCommonConstants.FILE_VERSION.equals(element)) {
             return PlainTextHandler.INSTANCE;
         }
-        if ("RocketDesign".equals(element)) {
+        if (RocksimCommonConstants.ROCKET_DESIGN.equals(element)) {
             return new RocketDesignHandler(rocket);
         }
         return null;
@@ -124,7 +124,7 @@ class RocksimContentHandler extends ElementHandler {
          * 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)) {
+        if (RocksimCommonConstants.FILE_VERSION.equals(element)) {
             version = content;
         }
     }
@@ -243,7 +243,7 @@ class RocketDesignHandler extends ElementHandler {
                 return new StageHandler(stage);
             }
         }
-        if ("Name".equals(element)) {
+        if (RocksimCommonConstants.NAME.equals(element)) {
             return PlainTextHandler.INSTANCE;
         }
         if ("StageCount".equals(element)) {
@@ -274,7 +274,7 @@ class RocketDesignHandler extends ElementHandler {
     public void closeElement(String element, HashMap<String, String> attributes,
                              String content, WarningSet warnings) throws SAXException {
         try {
-            if ("Name".equals(element)) {
+            if (RocksimCommonConstants.NAME.equals(element)) {
                 component.setName(content);
             }
             if ("StageCount".equals(element)) {
index b7c0afeaa5bf3ac5d73901a4ba155dbf08939ef0..e679ed05df8c4bb606e8e8b2e165956e79cbbf49 100644 (file)
@@ -1,30 +1,6 @@
 package net.sf.openrocket.gui.configdialog;
 
 
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.awt.geom.Ellipse2D;
-import java.util.EventObject;
-import java.util.List;
-
-import javax.swing.BorderFactory;
-import javax.swing.JButton;
-import javax.swing.JComponent;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JSpinner;
-import javax.swing.SwingUtilities;
-import javax.swing.border.BevelBorder;
-
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.gui.Resettable;
@@ -44,6 +20,17 @@ import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.StateChangeListener;
 
+import javax.swing.*;
+import javax.swing.border.BevelBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.geom.Ellipse2D;
+import java.util.EventObject;
+import java.util.List;
+
 
 public class InnerTubeConfig extends ThicknessRingComponentConfig {
        private static final Translator trans = Application.getTranslator();
@@ -163,12 +150,7 @@ public class InnerTubeConfig extends ThicknessRingComponentConfig {
                                                coords = component.shiftCoordinates(coords);
                                                parent.removeChild(index);
                                                for (int i = 0; i < coords.length; i++) {
-                                                       InnerTube copy = (InnerTube) component.copy();
-                                                       copy.setClusterConfiguration(ClusterConfiguration.SINGLE);
-                                                       copy.setClusterRotation(0.0);
-                                                       copy.setClusterScale(1.0);
-                                                       copy.setRadialShift(coords[i].y, coords[i].z);
-                                                       copy.setName(copy.getName() + " #" + (i + 1));
+                            InnerTube copy = makeIndividualClusterComponent(coords[i], component.getName() + " #" + (i + 1), component);
                                                        
                                                        parent.addChild(copy, index + i);
                                                }
@@ -198,6 +180,27 @@ public class InnerTubeConfig extends ThicknessRingComponentConfig {
 
                return panel;
        }
+
+    /**
+     * For a given coordinate that represents one tube in a cluster, create an instance of that tube.  Must be called
+     * once for each tube in the cluster.
+     *
+     * @param coord        the coordinate of the clustered tube to create
+     * @param splitName    the name of the individual tube
+     * @param theInnerTube the 'parent' from which this tube will be created.
+     *
+     * @return an instance of an inner tube that represents ONE of the clustered tubes in the cluster represented
+     *  by <code>theInnerTube</code>
+     */
+    public static InnerTube makeIndividualClusterComponent(Coordinate coord, String splitName, RocketComponent theInnerTube) {
+        InnerTube copy = (InnerTube) theInnerTube.copy();
+        copy.setClusterConfiguration(ClusterConfiguration.SINGLE);
+        copy.setClusterRotation(0.0);
+        copy.setClusterScale(1.0);
+        copy.setRadialShift(coord.y, coord.z);
+        copy.setName(splitName);
+        return copy;
+    }
 }