bug fixes and rocket optimization
[debian/openrocket] / src / net / sf / openrocket / rocketcomponent / RocketComponent.java
index e109f6b389abdb4f0a57248e72a847d4938df140..f9b28ea381d048f5dbbda7d516ca6f6955dad81b 100644 (file)
@@ -1,66 +1,85 @@
 package net.sf.openrocket.rocketcomponent;
 
+import java.awt.Color;
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.swing.event.ChangeListener;
+
+import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.ArrayList;
-import net.sf.openrocket.util.*;
-
-import javax.swing.event.ChangeListener;
-import java.awt.*;
-import java.util.*;
-import java.util.List;
+import net.sf.openrocket.util.BugException;
+import net.sf.openrocket.util.ChangeSource;
+import net.sf.openrocket.util.Coordinate;
+import net.sf.openrocket.util.Invalidator;
+import net.sf.openrocket.util.LineStyle;
+import net.sf.openrocket.util.MathUtil;
+import net.sf.openrocket.util.SafetyMutex;
+import net.sf.openrocket.util.UniqueID;
 
 
 public abstract class RocketComponent implements ChangeSource, Cloneable, Iterable<RocketComponent> {
        private static final LogHelper log = Application.getLogger();
-
+       private static final Translator trans = Application.getTranslator();
+       
        /*
         * Text is suitable to the form
         *    Position relative to:  <title>
         */
        public enum Position {
                /** Position relative to the top of the parent component. */
-               TOP("Top of the parent component"),
+               //// Top of the parent component
+               TOP(trans.get("RocketComponent.Position.TOP")),
                /** Position relative to the middle of the parent component. */
-               MIDDLE("Middle of the parent component"),
+               //// Middle of the parent component
+               MIDDLE(trans.get("RocketComponent.Position.MIDDLE")),
                /** Position relative to the bottom of the parent component. */
-               BOTTOM("Bottom of the parent component"),
+               //// Bottom of the parent component
+               BOTTOM(trans.get("RocketComponent.Position.BOTTOM")),
                /** Position after the parent component (for body components). */
-               AFTER("After the parent component"),
+               //// After the parent component
+               AFTER(trans.get("RocketComponent.Position.AFTER")),
                /** Specify an absolute X-coordinate position. */
-               ABSOLUTE("Tip of the nose cone");
-
+               //// Tip of the nose cone
+               ABSOLUTE(trans.get("RocketComponent.Position.ABSOLUTE"));
+               
                private String title;
-
+               
                Position(String title) {
                        this.title = title;
                }
-
+               
                @Override
                public String toString() {
                        return title;
                }
        }
-
+       
        /**
         * A safety mutex that can be used to prevent concurrent access to this component.
         */
        protected SafetyMutex mutex = SafetyMutex.newInstance();
-
+       
        ////////  Parent/child trees
        /**
         * Parent component of the current component, or null if none exists.
         */
        private RocketComponent parent = null;
-
+       
        /**
         * List of child components of this component.
         */
        private ArrayList<RocketComponent> children = new ArrayList<RocketComponent>();
-
+       
 
        ////////  Parameters common to all components:
-
+       
        /**
         * Characteristic length of the component.  This is used in calculating the coordinate
         * transformations and positions of other components in reference to this component.
@@ -68,50 +87,50 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * By default it is zero, i.e. no translation.
         */
        protected double length = 0;
-
+       
        /**
         * Positioning of this component relative to the parent component.
         */
        protected Position relativePosition;
-
+       
        /**
         * Offset of the position of this component relative to the normal position given by
         * relativePosition.  By default zero, i.e. no position change.
         */
        protected double position = 0;
-
+       
 
        // Color of the component, null means to use the default color
        private Color color = null;
        private LineStyle lineStyle = null;
-
+       
 
        // Override mass/CG
        private double overrideMass = 0;
        private boolean massOverriden = false;
        private double overrideCGX = 0;
        private boolean cgOverriden = false;
-
+       
        private boolean overrideSubcomponents = false;
-
+       
 
        // User-given name of the component
        private String name = null;
-
+       
        // User-specified comment
        private String comment = "";
-
+       
        // Unique ID of the component
        private String id = null;
-
+       
        /**
         * Used to invalidate the component after calling {@link #copyFrom(RocketComponent)}.
         */
        private Invalidator invalidator = new Invalidator(this);
-
-
+       
+       
        ////  NOTE !!!  All fields must be copied in the method copyFrom()!  ////
-
+       
 
 
        /**
@@ -124,25 +143,25 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                this.relativePosition = relativePosition;
                newID();
        }
-
+       
        ////////////  Methods that must be implemented  ////////////
-
+       
 
        /**
         * Static component name.  The name may not vary of the parameters, it must be static.
         */
        public abstract String getComponentName(); // Static component type name
-
+       
        /**
         * Return the component mass (regardless of mass overriding).
         */
        public abstract double getComponentMass(); // Mass of non-overridden component
-
+       
        /**
         * Return the component CG and mass (regardless of CG or mass overriding).
         */
        public abstract Coordinate getComponentCG(); // CG of non-overridden component
-
+       
 
        /**
         * Return the longitudinal (around the y- or z-axis) unitary moment of inertia.
@@ -153,8 +172,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * @return   the longitudinal unitary moment of inertia of this component.
         */
        public abstract double getLongitudinalUnitInertia();
-
-
+       
+       
        /**
         * Return the rotational (around the x-axis) unitary moment of inertia.
         * The unitary moment of inertia is the moment of inertia with the assumption that
@@ -164,8 +183,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * @return   the rotational unitary moment of inertia of this component.
         */
        public abstract double getRotationalUnitInertia();
-
-
+       
+       
        /**
         * Test whether this component allows any children components.  This method must
         * return true if and only if {@link #isCompatible(Class)} returns true for any
@@ -174,7 +193,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * @return      <code>true</code> if children can be attached to this component, <code>false</code> otherwise.
         */
        public abstract boolean allowsChildren();
-
+       
        /**
         * Test whether the given component type can be added to this component.  This type safety
         * is enforced by the <code>addChild()</code> methods.  The return value of this method
@@ -185,8 +204,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * @return      Whether such a component can be added.
         */
        public abstract boolean isCompatible(Class<? extends RocketComponent> type);
-
-
+       
+       
        /* Non-abstract helper method */
        /**
         * Test whether the given component can be added to this component.  This is equivalent
@@ -200,8 +219,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return isCompatible(c.getClass());
        }
-
-
+       
+       
 
        /**
         * Return a collection of bounding coordinates.  The coordinates must be such that
@@ -210,23 +229,23 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * @return      a collection of coordinates that bound the component.
         */
        public abstract Collection<Coordinate> getComponentBounds();
-
+       
        /**
         * Return true if the component may have an aerodynamic effect on the rocket.
         */
        public abstract boolean isAerodynamic();
-
+       
        /**
         * Return true if the component may have an effect on the rocket's mass.
         */
        public abstract boolean isMassive();
-
-
+       
+       
 
 
 
        ////////////  Methods that may be overridden  ////////////
-
+       
 
        /**
         * Shift the coordinates in the array corresponding to radial movement.  A component
@@ -244,8 +263,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return c;
        }
-
-
+       
+       
        /**
         * Called when any component in the tree fires a ComponentChangeEvent.  This is by
         * default a no-op, but subclasses may override this method to e.g. invalidate
@@ -258,8 +277,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                // No-op
                checkState();
        }
-
-
+       
+       
 
 
        /**
@@ -276,8 +295,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                else
                        return name;
        }
-
-
+       
+       
        /**
         * Create a string describing the basic component structure from this component downwards.
         * @return      a string containing the rocket structure
@@ -292,7 +311,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        mutex.unlock("toDebugString");
                }
        }
-
+       
        private void toDebugString(StringBuilder sb) {
                sb.append(this.getClass().getSimpleName()).append('@').append(System.identityHashCode(this));
                sb.append("[\"").append(this.getName()).append('"');
@@ -302,8 +321,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                sb.append(']');
        }
-
-
+       
+       
        /**
         * Make a deep copy of the rocket component tree structure from this component
         * downwards for copying purposes.  Each component in the copy will be assigned
@@ -313,15 +332,15 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         */
        public final RocketComponent copy() {
                RocketComponent clone = copyWithOriginalID();
-
+               
                Iterator<RocketComponent> iterator = clone.iterator(true);
                while (iterator.hasNext()) {
                        iterator.next().newID();
                }
                return clone;
        }
-
-
+       
+       
 
        /**
         * Make a deep copy of the rocket component tree structure from this component
@@ -349,14 +368,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        } catch (CloneNotSupportedException e) {
                                throw new BugException("CloneNotSupportedException encountered, report a bug!", e);
                        }
-
+                       
                        // Reset the mutex
                        clone.mutex = SafetyMutex.newInstance();
-
+                       
                        // Reset all parent/child information
                        clone.parent = null;
                        clone.children = new ArrayList<RocketComponent>();
-
+                       
                        // Add copied children to the structure without firing events.
                        for (RocketComponent child : this.children) {
                                RocketComponent childCopy = child.copyWithOriginalID();
@@ -364,23 +383,23 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                clone.children.add(childCopy);
                                childCopy.parent = clone;
                        }
-
+                       
                        this.checkComponentStructure();
                        clone.checkComponentStructure();
-
+                       
                        return clone;
                } finally {
                        mutex.unlock("copyWithOriginalID");
                }
        }
-
-
+       
+       
        //////////////  Methods that may not be overridden  ////////////
-
+       
 
 
        ////////// Common parameter setting/getting //////////
-
+       
        /**
         * Return the color of the object to use in 2D figures, or <code>null</code>
         * to use the default color.
@@ -389,7 +408,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return color;
        }
-
+       
        /**
         * Set the color of the object to use in 2D figures.
         */
@@ -397,18 +416,18 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                if ((color == null && c == null) ||
                                (color != null && color.equals(c)))
                        return;
-
+               
                checkState();
                this.color = c;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-
-
+       
+       
        public final LineStyle getLineStyle() {
                mutex.verify();
                return lineStyle;
        }
-
+       
        public final void setLineStyle(LineStyle style) {
                if (this.lineStyle == style)
                        return;
@@ -416,8 +435,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                this.lineStyle = style;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-
-
+       
+       
 
 
        /**
@@ -430,7 +449,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return overrideMass;
        }
-
+       
        /**
         * Set the current override mass.  The mass is not set to use by this
         * method.
@@ -445,7 +464,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                if (massOverriden)
                        fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-
+       
        /**
         * Return whether mass override is active for this component.  This does NOT
         * take into account whether a parent component is overriding the mass.
@@ -456,7 +475,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return massOverriden;
        }
-
+       
        /**
         * Set whether the mass is currently overridden.
         *
@@ -470,8 +489,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                massOverriden = o;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-
-
+       
+       
 
 
 
@@ -484,7 +503,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return getComponentCG().setX(overrideCGX);
        }
-
+       
        /**
         * Return the x-coordinate of the current override CG.
         *
@@ -494,7 +513,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return overrideCGX;
        }
-
+       
        /**
         * Set the current override CG to (x,0,0).
         *
@@ -510,7 +529,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                else
                        fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-
+       
        /**
         * Return whether the CG is currently overridden.
         *
@@ -520,7 +539,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return cgOverriden;
        }
-
+       
        /**
         * Set whether the CG is currently overridden.
         *
@@ -534,8 +553,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                cgOverriden = o;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-
-
+       
+       
 
        /**
         * Return whether the mass and/or CG override overrides all subcomponent values
@@ -551,8 +570,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return overrideSubcomponents;
        }
-
-
+       
+       
        /**
         * Set whether the mass and/or CG override overrides all subcomponent values
         * as well.  See {@link #getOverrideSubcomponents()} for details.
@@ -567,7 +586,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                overrideSubcomponents = override;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-
+       
        /**
         * Return whether the option to override all subcomponents is enabled or not.
         * The default implementation returns <code>false</code> if neither mass nor
@@ -582,8 +601,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return isCGOverridden() || isMassOverridden();
        }
-
-
+       
+       
 
 
        /**
@@ -593,7 +612,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return name;
        }
-
+       
        /**
         * Set the user-defined name of the component.  If name==null, sets the name to
         * the default name, currently the component name.
@@ -609,8 +628,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        this.name = name;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-
-
+       
+       
        /**
         * Return the comment of the component.  The component may contain multiple lines
         * using \n as a newline separator.
@@ -621,7 +640,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return comment;
        }
-
+       
        /**
         * Set the comment of the component.
         *
@@ -637,8 +656,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        this.comment = comment;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-
-
+       
+       
 
        /**
         * Returns the unique ID of the component.
@@ -648,7 +667,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        public final String getID() {
                return id;
        }
-
+       
        /**
         * Generate a new ID for this component.
         */
@@ -656,8 +675,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                this.id = UniqueID.uuid();
        }
-
-
+       
+       
 
 
        /**
@@ -672,7 +691,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return length;
        }
-
+       
        /**
         * Get the positioning of the component relative to its parent component.
         * This is one of the enums of {@link Position}.  A setter method is not provided,
@@ -682,8 +701,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return relativePosition;
        }
-
-
+       
+       
        /**
         * Set the positioning of the component relative to its parent component.
         * The actual position of the component is maintained to the best ability.
@@ -699,38 +718,38 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                if (this.relativePosition == position)
                        return;
                checkState();
-
+               
                // Update position so as not to move the component
                if (this.parent != null) {
                        double thisPos = this.toRelative(Coordinate.NUL, this.parent)[0].x;
-
+                       
                        switch (position) {
                        case ABSOLUTE:
                                this.position = this.toAbsolute(Coordinate.NUL)[0].x;
                                break;
-
+                       
                        case TOP:
                                this.position = thisPos;
                                break;
-
+                       
                        case MIDDLE:
                                this.position = thisPos - (this.parent.length - this.length) / 2;
                                break;
-
+                       
                        case BOTTOM:
                                this.position = thisPos - (this.parent.length - this.length);
                                break;
-
+                       
                        default:
                                throw new BugException("Unknown position type: " + position);
                        }
                }
-
+               
                this.relativePosition = position;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-
-
+       
+       
 
 
        /**
@@ -743,8 +762,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return position;
        }
-
-
+       
+       
        /**
         * Set the position value of the component.  The exact meaning of the value
         * depends on the current relative positioning.
@@ -762,11 +781,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                this.position = value;
        }
-
-
+       
+       
 
        ///////////  Coordinate changes  ///////////
-
+       
        /**
         * Returns coordinate c in absolute coordinates.  Equivalent to toComponent(c,null).
         */
@@ -774,8 +793,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return toRelative(c, null);
        }
-
-
+       
+       
        /**
         * Return coordinate <code>c</code> described in the coordinate system of
         * <code>dest</code>.  If <code>dest</code> is <code>null</code> returns
@@ -800,33 +819,33 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        RocketComponent search = dest;
                        Coordinate[] array = new Coordinate[1];
                        array[0] = c;
-
+                       
                        RocketComponent component = this;
                        while ((component != search) && (component.parent != null)) {
-
+                               
                                array = component.shiftCoordinates(array);
-
+                               
                                switch (component.relativePosition) {
                                case TOP:
                                        for (int i = 0; i < array.length; i++) {
                                                array[i] = array[i].add(component.position, 0, 0);
                                        }
                                        break;
-
+                               
                                case MIDDLE:
                                        for (int i = 0; i < array.length; i++) {
                                                array[i] = array[i].add(component.position +
                                                                (component.parent.length - component.length) / 2, 0, 0);
                                        }
                                        break;
-
+                               
                                case BOTTOM:
                                        for (int i = 0; i < array.length; i++) {
                                                array[i] = array[i].add(component.position +
                                                                (component.parent.length - component.length), 0, 0);
                                        }
                                        break;
-
+                               
                                case AFTER:
                                        // Add length of all previous brother-components with POSITION_RELATIVE_AFTER
                                        int index = component.parent.children.indexOf(component);
@@ -842,28 +861,28 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                                array[i] = array[i].add(component.position + component.parent.length, 0, 0);
                                        }
                                        break;
-
+                               
                                case ABSOLUTE:
                                        search = null; // Requires back-search if dest!=null
                                        if (Double.isNaN(absoluteX)) {
                                                absoluteX = component.position;
                                        }
                                        break;
-
+                               
                                default:
                                        throw new BugException("Unknown relative positioning type of component" +
                                                        component + ": " + component.relativePosition);
                                }
-
+                               
                                component = component.parent; // parent != null
                        }
-
+                       
                        if (!Double.isNaN(absoluteX)) {
                                for (int i = 0; i < array.length; i++) {
                                        array[i] = array[i].setX(absoluteX + c.x);
                                }
                        }
-
+                       
                        // Check whether destination has been found or whether to backtrack
                        // TODO: LOW: Backtracking into clustered components uses only one component
                        if ((dest != null) && (component != dest)) {
@@ -872,14 +891,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                        array[i] = array[i].sub(origin[0]);
                                }
                        }
-
+                       
                        return array;
                } finally {
                        mutex.unlock("toRelative");
                }
        }
-
-
+       
+       
        /**
         * Recursively sum the lengths of all subcomponents that have position
         * Position.AFTER.
@@ -901,11 +920,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        mutex.unlock("getTotalLength");
                }
        }
-
-
+       
+       
 
        /////////// Total mass and CG calculation ////////////
-
+       
        /**
         * Return the (possibly overridden) mass of component.
         *
@@ -917,7 +936,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        return overrideMass;
                return getComponentMass();
        }
-
+       
        /**
         * Return the (possibly overridden) center of gravity and mass.
         *
@@ -930,14 +949,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                if (cgOverriden)
                        return getOverrideCG().setWeight(getMass());
-
+               
                if (massOverriden)
                        return getComponentCG().setWeight(getMass());
-
+               
                return getComponentCG();
        }
-
-
+       
+       
        /**
         * Return the longitudinal (around the y- or z-axis) moment of inertia of this component.
         * The moment of inertia is scaled in reference to the (possibly overridden) mass
@@ -949,7 +968,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return getLongitudinalUnitInertia() * getMass();
        }
-
+       
        /**
         * Return the rotational (around the y- or z-axis) moment of inertia of this component.
         * The moment of inertia is scaled in reference to the (possibly overridden) mass
@@ -961,11 +980,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return getRotationalUnitInertia() * getMass();
        }
-
-
+       
+       
 
        ///////////  Children handling  ///////////
-
+       
 
        /**
         * Adds a child to the rocket component tree.  The component is added to the end
@@ -981,8 +1000,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                addChild(component, children.size());
        }
-
-
+       
+       
        /**
         * Adds a child to the rocket component tree.  The component is added to
         * the given position of the component's child list.
@@ -1005,17 +1024,17 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        throw new IllegalStateException("Component " + component.getComponentName() +
                                        " not currently compatible with component " + getComponentName());
                }
-
+               
                children.add(index, component);
                component.parent = this;
-
+               
                this.checkComponentStructure();
                component.checkComponentStructure();
-
+               
                fireAddRemoveEvent(component);
        }
-
-
+       
+       
        /**
         * Removes a child from the rocket component tree.
         *
@@ -1026,13 +1045,13 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                RocketComponent component = children.remove(n);
                component.parent = null;
-
+               
                this.checkComponentStructure();
                component.checkComponentStructure();
-
+               
                fireAddRemoveEvent(component);
        }
-
+       
        /**
         * Removes a child from the rocket component tree.  Does nothing if the component
         * is not present as a child.
@@ -1042,22 +1061,22 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         */
        public final boolean removeChild(RocketComponent component) {
                checkState();
-
+               
                component.checkComponentStructure();
-
+               
                if (children.remove(component)) {
                        component.parent = null;
-
+                       
                        this.checkComponentStructure();
                        component.checkComponentStructure();
-
+                       
                        fireAddRemoveEvent(component);
                        return true;
                }
                return false;
        }
-
-
+       
+       
 
 
        /**
@@ -1071,15 +1090,15 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                if (children.remove(component)) {
                        children.add(index, component);
-
+                       
                        this.checkComponentStructure();
                        component.checkComponentStructure();
-
+                       
                        fireAddRemoveEvent(component);
                }
        }
-
-
+       
+       
        /**
         * Fires an AERODYNAMIC_CHANGE, MASS_CHANGE or OTHER_CHANGE event depending on the
         * type of component removed.
@@ -1094,30 +1113,30 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        if (c.isMassive())
                                type |= ComponentChangeEvent.MASS_CHANGE;
                }
-
+               
                fireComponentChangeEvent(type);
        }
-
-
+       
+       
        public final int getChildCount() {
                checkState();
                this.checkComponentStructure();
                return children.size();
        }
-
+       
        public final RocketComponent getChild(int n) {
                checkState();
                this.checkComponentStructure();
                return children.get(n);
        }
-
+       
        public final List<RocketComponent> getChildren() {
                checkState();
                this.checkComponentStructure();
                return children.clone();
        }
-
-
+       
+       
        /**
         * Returns the position of the child in this components child list, or -1 if the
         * component is not a child of this component.
@@ -1130,7 +1149,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                this.checkComponentStructure();
                return children.indexOf(child);
        }
-
+       
        /**
         * Get the parent component of this component.  Returns <code>null</code> if the component
         * has no parent.
@@ -1141,7 +1160,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return parent;
        }
-
+       
        /**
         * Get the root component of the component tree.
         *
@@ -1154,7 +1173,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        gp = gp.parent;
                return gp;
        }
-
+       
        /**
         * Returns the root Rocket component of this component tree.  Throws an
         * IllegalStateException if the root component is not a Rocket.
@@ -1170,8 +1189,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                throw new IllegalStateException("getRocket() called with root component "
                                + r.getComponentName());
        }
-
-
+       
+       
        /**
         * Return the Stage component that this component belongs to.  Throws an
         * IllegalStateException if a Stage is not in the parentage of this component.
@@ -1189,7 +1208,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                throw new IllegalStateException("getStage() called without Stage as a parent.");
        }
-
+       
        /**
         * Return the stage number of the stage this component belongs to.  The stages
         * are numbered from zero upwards.
@@ -1201,7 +1220,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                if (parent == null) {
                        throw new IllegalArgumentException("getStageNumber() called for root component");
                }
-
+               
                RocketComponent stage = this;
                while (!(stage instanceof Stage)) {
                        stage = stage.parent;
@@ -1212,8 +1231,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                return stage.parent.getChildPosition(stage);
        }
-
-
+       
+       
        /**
         * Find a component with the given ID.  The component tree is searched from this component
         * down (including this component) for the ID and the corresponding component is returned,
@@ -1232,8 +1251,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                return null;
        }
-
-
+       
+       
        // TODO: Move these methods elsewhere (used only in SymmetricComponent)
        public final RocketComponent getPreviousComponent() {
                checkState();
@@ -1264,34 +1283,34 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        c = c.getChild(c.getChildCount() - 1);
                return c;
        }
-
+       
        // TODO: Move these methods elsewhere (used only in SymmetricComponent)
        public final RocketComponent getNextComponent() {
                checkState();
                if (getChildCount() > 0)
                        return getChild(0);
-
+               
                RocketComponent current = this;
                RocketComponent nextParent = this.parent;
-
+               
                while (nextParent != null) {
                        int pos = nextParent.getChildPosition(current);
                        if (pos < nextParent.getChildCount() - 1)
                                return nextParent.getChild(pos + 1);
-
+                       
                        current = nextParent;
                        nextParent = current.parent;
                }
                return null;
        }
-
-
+       
+       
        ///////////  Event handling  //////////
        //
        // Listener lists are provided by the root Rocket component,
        // a single listener list for the whole rocket.
        //
-
+       
        /**
         * Adds a ComponentChangeListener to the rocket tree.  The listener is added to the root
         * component, which must be of type Rocket (which overrides this method).  Events of all
@@ -1303,7 +1322,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                getRocket().addComponentChangeListener(l);
        }
-
+       
        /**
         * Removes a ComponentChangeListener from the rocket tree.  The listener is removed from
         * the root component, which must be of type Rocket (which overrides this method).
@@ -1317,8 +1336,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        getRoot().removeComponentChangeListener(l);
                }
        }
-
-
+       
+       
        /**
         * Adds a <code>ChangeListener</code> to the rocket tree.  This is identical to
         * <code>addComponentChangeListener()</code> except that it uses a
@@ -1333,7 +1352,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                getRocket().addChangeListener(l);
        }
-
+       
        /**
         * Removes a ChangeListener from the rocket tree.  This is identical to
         * removeComponentChangeListener() except it uses a ChangeListener.
@@ -1348,8 +1367,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        getRoot().removeChangeListener(l);
                }
        }
-
-
+       
+       
        /**
         * Fires a ComponentChangeEvent on the rocket structure.  The call is passed to the
         * root component, which must be of type Rocket (which overrides this method).
@@ -1370,8 +1389,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                getRoot().fireComponentChangeEvent(e);
        }
-
-
+       
+       
        /**
         * Fires a ComponentChangeEvent of the given type.  The source of the event is set to
         * this component.
@@ -1382,8 +1401,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        protected void fireComponentChangeEvent(int type) {
                fireComponentChangeEvent(new ComponentChangeEvent(this, type));
        }
-
-
+       
+       
        /**
         * Checks whether this component has been invalidated and should no longer be used.
         * This is a safety check that in-place replaced components are no longer used.
@@ -1396,8 +1415,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                invalidator.check(true);
                mutex.verify();
        }
-
-
+       
+       
        /**
         * Check that the local component structure is correct.  This can be called after changing
         * the component structure in order to verify the integrity.
@@ -1420,7 +1439,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        }
                }
        }
-
+       
        // Check whether the list contains exactly the searched-for component (with == operator)
        private boolean containsExact(List<RocketComponent> haystack, RocketComponent needle) {
                for (RocketComponent c : haystack) {
@@ -1430,10 +1449,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                return false;
        }
-
-
+       
+       
        ///////////  Iterators  //////////
-
+       
        /**
         * Returns an iterator that iterates over all children and sub-children.
         * <p>
@@ -1455,8 +1474,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        public final Iterator<RocketComponent> deepIterator(boolean returnSelf) {
                return iterator(returnSelf);
        }
-
-
+       
+       
        /**
         * Returns an iterator that iterates over all children and sub-children, including itself.
         * <p>
@@ -1471,8 +1490,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        public final Iterator<RocketComponent> deepIterator() {
                return iterator();
        }
-
-
+       
+       
 
        /**
         * Returns an iterator that iterates over all children and sub-children.
@@ -1492,10 +1511,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return new RocketComponentIterator(this, returnSelf);
        }
-
-
+       
+       
        /**
-        * Returns an iterator that iterates over this components, its children and sub-children.
+        * Returns an iterator that iterates over this component, its children and sub-children.
         * <p>
         * This method is equivalent to <code>iterator(true)</code>.
         *
@@ -1505,8 +1524,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        public final Iterator<RocketComponent> iterator() {
                return iterator(true);
        }
-
-
+       
+       
 
 
 
@@ -1525,18 +1544,18 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                RocketComponent other = (RocketComponent) obj;
                return this.id.equals(other.id);
        }
-
-
+       
+       
 
        @Override
        public int hashCode() {
                return id.hashCode();
        }
-
-
+       
+       
 
        ////////////  Helper methods for subclasses
-
+       
 
 
 
@@ -1551,36 +1570,36 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                bounds.add(new Coordinate(x, r, r));
                bounds.add(new Coordinate(x, -r, r));
        }
-
-
+       
+       
        protected static final Coordinate ringCG(double outerRadius, double innerRadius,
                        double x1, double x2, double density) {
                return new Coordinate((x1 + x2) / 2, 0, 0,
                                ringMass(outerRadius, innerRadius, x2 - x1, density));
        }
-
+       
        protected static final double ringMass(double outerRadius, double innerRadius,
                        double length, double density) {
                return Math.PI * (MathUtil.pow2(outerRadius) - MathUtil.pow2(innerRadius)) *
                                        length * density;
        }
-
+       
        protected static final double ringLongitudinalUnitInertia(double outerRadius,
                        double innerRadius, double length) {
                // 1/12 * (3 * (r1^2 + r2^2) + h^2)
                return (3 * (MathUtil.pow2(innerRadius) + MathUtil.pow2(outerRadius)) + MathUtil.pow2(length)) / 12;
        }
-
+       
        protected static final double ringRotationalUnitInertia(double outerRadius,
                        double innerRadius) {
                // 1/2 * (r1^2 + r2^2)
                return (MathUtil.pow2(innerRadius) + MathUtil.pow2(outerRadius)) / 2;
        }
-
-
+       
+       
 
        ////////////  OTHER
-
+       
 
        /**
         * Loads the RocketComponent fields from the given component.  This method is meant
@@ -1602,34 +1621,34 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        protected List<RocketComponent> copyFrom(RocketComponent src) {
                checkState();
                List<RocketComponent> toInvalidate = new ArrayList<RocketComponent>();
-
+               
                if (this.parent != null) {
                        throw new UnsupportedOperationException("copyFrom called for non-root component, parent=" +
                                        this.parent.toDebugString() + ", this=" + this.toDebugString());
                }
-
+               
                // Add current structure to be invalidated
                Iterator<RocketComponent> iterator = this.iterator(false);
                while (iterator.hasNext()) {
                        toInvalidate.add(iterator.next());
                }
-
+               
                // Remove previous components
                for (RocketComponent child : this.children) {
                        child.parent = null;
                }
                this.children.clear();
-
+               
                // Copy new children to this component
                for (RocketComponent c : src.children) {
                        RocketComponent copy = c.copyWithOriginalID();
                        this.children.add(copy);
                        copy.parent = this;
                }
-
+               
                this.checkComponentStructure();
                src.checkComponentStructure();
-
+               
                // Set all parameters
                this.length = src.length;
                this.relativePosition = src.relativePosition;
@@ -1644,22 +1663,22 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                this.name = src.name;
                this.comment = src.comment;
                this.id = src.id;
-
+               
                // Add source components to invalidation tree
                for (RocketComponent c : src) {
                        toInvalidate.add(c);
                }
-
+               
                return toInvalidate;
        }
-
+       
        protected void invalidate() {
                invalidator.invalidate();
        }
-
-
+       
+       
        //////////  Iterator implementation  ///////////
-
+       
        /**
         * Private inner class to implement the Iterator.
         *
@@ -1668,16 +1687,16 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        private static class RocketComponentIterator implements Iterator<RocketComponent> {
                // Stack holds iterators which still have some components left.
                private final Deque<Iterator<RocketComponent>> iteratorStack = new ArrayDeque<Iterator<RocketComponent>>();
-
+               
                private final Rocket root;
                private final int treeModID;
-
+               
                private final RocketComponent original;
                private boolean returnSelf = false;
-
+               
                // Construct iterator with component's child's iterator, if it has elements
                public RocketComponentIterator(RocketComponent c, boolean returnSelf) {
-
+                       
                        RocketComponent gp = c.getRoot();
                        if (gp instanceof Rocket) {
                                root = (Rocket) gp;
@@ -1686,15 +1705,15 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                root = null;
                                treeModID = -1;
                        }
-
+                       
                        Iterator<RocketComponent> i = c.children.iterator();
                        if (i.hasNext())
                                iteratorStack.push(i);
-
+                       
                        this.original = c;
                        this.returnSelf = returnSelf;
                }
-
+               
                @Override
                public boolean hasNext() {
                        checkID();
@@ -1702,38 +1721,38 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                return true;
                        return !iteratorStack.isEmpty(); // Elements remain if stack is not empty
                }
-
+               
                @Override
                public RocketComponent next() {
                        Iterator<RocketComponent> i;
-
+                       
                        checkID();
-
+                       
                        // Return original component first
                        if (returnSelf) {
                                returnSelf = false;
                                return original;
                        }
-
+                       
                        // Peek first iterator from stack, throw exception if empty
                        i = iteratorStack.peek();
                        if (i == null) {
                                throw new NoSuchElementException("No further elements in RocketComponent iterator");
                        }
-
+                       
                        // Retrieve next component of the iterator, remove iterator from stack if empty
                        RocketComponent c = i.next();
                        if (!i.hasNext())
                                iteratorStack.pop();
-
+                       
                        // Add iterator of component children to stack if it has children
                        i = c.children.iterator();
                        if (i.hasNext())
                                iteratorStack.push(i);
-
+                       
                        return c;
                }
-
+               
                private void checkID() {
                        if (root != null) {
                                if (root.getTreeModID() != treeModID) {
@@ -1741,12 +1760,12 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                }
                        }
                }
-
+               
                @Override
                public void remove() {
                        throw new UnsupportedOperationException("remove() not supported by " +
                                        "RocketComponent iterator");
                }
        }
-
+       
 }