bug fixes and rocket optimization
[debian/openrocket] / src / net / sf / openrocket / rocketcomponent / RocketComponent.java
index 34ae962f2ba15a4550a86a677544be9a915904dd..f9b28ea381d048f5dbbda7d516ca6f6955dad81b 100644 (file)
@@ -1,31 +1,32 @@
 package net.sf.openrocket.rocketcomponent;
 
 import java.awt.Color;
-import java.util.ArrayList;
+import java.util.ArrayDeque;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.EmptyStackException;
+import java.util.Deque;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
-import java.util.Stack;
 
 import javax.swing.event.ChangeListener;
 
+import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
-import net.sf.openrocket.logging.TraceException;
 import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.ArrayList;
 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> {
+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
@@ -33,15 +34,20 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         */
        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;
                
@@ -55,6 +61,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
                }
        }
        
+       /**
+        * 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.
@@ -64,7 +75,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        /**
         * List of child components of this component.
         */
-       private List<RocketComponent> children = new ArrayList<RocketComponent>();
+       private ArrayList<RocketComponent> children = new ArrayList<RocketComponent>();
        
 
        ////////  Parameters common to all components:
@@ -113,10 +124,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        private String id = null;
        
        /**
-        * When invalidated is non-null this component cannot be used anymore.
-        * This is a safety mechanism to prevent accidental use after calling {@link #copyFrom(RocketComponent)}.
+        * Used to invalidate the component after calling {@link #copyFrom(RocketComponent)}.
         */
-       private TraceException invalidated = null;
+       private Invalidator invalidator = new Invalidator(this);
+       
        
        ////  NOTE !!!  All fields must be copied in the method copyFrom()!  ////
        
@@ -133,10 +144,6 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
                newID();
        }
        
-       
-
-
-
        ////////////  Methods that must be implemented  ////////////
        
 
@@ -157,22 +164,22 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
 
        /**
-        * Return the longitudal (around the y- or z-axis) unitary moment of inertia.  
+        * Return the longitudinal (around the y- or z-axis) unitary moment of inertia.
         * The unitary moment of inertia is the moment of inertia with the assumption that
         * the mass of the component is one kilogram.  The inertia is measured in
         * respect to the non-overridden CG.
-        * 
-        * @return   the longitudal unitary moment of inertia of this component.
+        *
+        * @return   the longitudinal unitary moment of inertia of this component.
         */
-       public abstract double getLongitudalUnitInertia();
+       public abstract double getLongitudinalUnitInertia();
        
        
        /**
-        * Return the rotational (around the x-axis) unitary moment of inertia.  
+        * 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
         * the mass of the component is one kilogram.  The inertia is measured in
         * respect to the non-overridden CG.
-        * 
+        *
         * @return   the rotational unitary moment of inertia of this component.
         */
        public abstract double getRotationalUnitInertia();
@@ -182,7 +189,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * Test whether this component allows any children components.  This method must
         * return true if and only if {@link #isCompatible(Class)} returns true for any
         * rocket component class.
-        * 
+        *
         * @return      <code>true</code> if children can be attached to this component, <code>false</code> otherwise.
         */
        public abstract boolean allowsChildren();
@@ -192,7 +199,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * is enforced by the <code>addChild()</code> methods.  The return value of this method
         * may change to reflect the current state of this component (e.g. two components of some
         * type cannot be placed as children).
-        * 
+        *
         * @param type  The RocketComponent class type to add.
         * @return      Whether such a component can be added.
         */
@@ -203,12 +210,13 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        /**
         * Test whether the given component can be added to this component.  This is equivalent
         * to calling <code>isCompatible(c.getClass())</code>.
-        * 
+        *
         * @param c  Component to test.
         * @return   Whether the component can be added.
         * @see #isCompatible(Class)
         */
        public final boolean isCompatible(RocketComponent c) {
+               mutex.verify();
                return isCompatible(c.getClass());
        }
        
@@ -217,7 +225,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        /**
         * Return a collection of bounding coordinates.  The coordinates must be such that
         * the component is fully enclosed in their convex hull.
-        * 
+        *
         * @return      a collection of coordinates that bound the component.
         */
        public abstract Collection<Coordinate> getComponentBounds();
@@ -246,7 +254,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * coordinate for each cluster.
         * <p>
         * The default implementation simply returns the array, and thus produces no shift.
-        * 
+        *
         * @param c   an array of coordinates to shift.
         * @return    an array of shifted coordinates.  The method may modify the contents
         *                        of the passed array and return the array itself.
@@ -258,11 +266,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
        
        /**
-        * 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 
-        * cached data.  The overriding method *must* call 
+        * 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
+        * cached data.  The overriding method *must* call
         * <code>super.componentChanged(e)</code> at some point.
-        * 
+        *
         * @param e  The event fired
         */
        protected void componentChanged(ComponentChangeEvent e) {
@@ -274,39 +282,44 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
 
 
        /**
-        * Return a descriptive name of the component.
-        * 
-        * The description may include extra information about the type of component,
-        * e.g. "Conical nose cone".
-        * 
+        * Return the user-provided name of the component, or the component base
+        * name if the user-provided name is empty.  This can be used in the UI.
+        *
         * @return A string describing the component.
         */
        @Override
        public final String toString() {
-               if (name.equals(""))
+               mutex.verify();
+               if (name.length() == 0)
                        return getComponentName();
                else
                        return name;
        }
        
        
-       public final void printStructure() {
-               System.out.println("Rocket structure from '" + this.toString() + "':");
-               printStructure(0);
+       /**
+        * Create a string describing the basic component structure from this component downwards.
+        * @return      a string containing the rocket structure
+        */
+       public final String toDebugString() {
+               mutex.lock("toDebugString");
+               try {
+                       StringBuilder sb = new StringBuilder();
+                       toDebugString(sb);
+                       return sb.toString();
+               } finally {
+                       mutex.unlock("toDebugString");
+               }
        }
        
-       private void printStructure(int level) {
-               String s = "";
-               
-               for (int i = 0; i < level; i++) {
-                       s += "  ";
-               }
-               s += this.toString() + " (" + this.getComponentName() + ")";
-               System.out.println(s);
-               
-               for (RocketComponent c : children) {
-                       c.printStructure(level + 1);
+       private void toDebugString(StringBuilder sb) {
+               sb.append(this.getClass().getSimpleName()).append('@').append(System.identityHashCode(this));
+               sb.append("[\"").append(this.getName()).append('"');
+               for (RocketComponent c : this.children) {
+                       sb.append("; ");
+                       c.toDebugString(sb);
                }
+               sb.append(']');
        }
        
        
@@ -314,13 +327,13 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * 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
         * a new component ID, making it a safe copy.  This method does not fire any events.
-        * 
+        *
         * @return A deep copy of the structure.
         */
        public final RocketComponent copy() {
                RocketComponent clone = copyWithOriginalID();
                
-               Iterator<RocketComponent> iterator = clone.deepIterator(true);
+               Iterator<RocketComponent> iterator = clone.iterator(true);
                while (iterator.hasNext()) {
                        iterator.next().newID();
                }
@@ -336,38 +349,48 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * undo/redo mechanism.  This method should not be used for other purposes,
         * such as copy/paste.  This method does not fire any events.
         * <p>
-        * This method must be overridden by any component that refers to mutable objects, 
+        * This method must be overridden by any component that refers to mutable objects,
         * or if some fields should not be copied.  This should be performed by
         * <code>RocketComponent c = super.copyWithOriginalID();</code> and then cloning/modifying
         * the appropriate fields.
         * <p>
         * This is not performed as serializing/deserializing for performance reasons.
-        * 
+        *
         * @return A deep copy of the structure.
         */
        protected RocketComponent copyWithOriginalID() {
-               checkState();
-               RocketComponent clone;
+               mutex.lock("copyWithOriginalID");
                try {
-                       clone = (RocketComponent) this.clone();
-               } catch (CloneNotSupportedException e) {
-                       throw new BugException("CloneNotSupportedException encountered, " +
-                                       "report a bug!", e);
-               }
-               
-               // 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();
-                       // Don't use add method since it fires events
-                       clone.children.add(childCopy);
-                       childCopy.parent = clone;
+                       checkState();
+                       RocketComponent clone;
+                       try {
+                               clone = (RocketComponent) this.clone();
+                       } 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();
+                               // Don't use add method since it fires events
+                               clone.children.add(childCopy);
+                               childCopy.parent = clone;
+                       }
+                       
+                       this.checkComponentStructure();
+                       clone.checkComponentStructure();
+                       
+                       return clone;
+               } finally {
+                       mutex.unlock("copyWithOriginalID");
                }
-               
-               return clone;
        }
        
        
@@ -382,11 +405,12 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * to use the default color.
         */
        public final Color getColor() {
+               mutex.verify();
                return color;
        }
        
        /**
-        * Set the color of the object to use in 2D figures.  
+        * Set the color of the object to use in 2D figures.
         */
        public final void setColor(Color c) {
                if ((color == null && c == null) ||
@@ -400,6 +424,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
        
        public final LineStyle getLineStyle() {
+               mutex.verify();
                return lineStyle;
        }
        
@@ -417,17 +442,18 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        /**
         * Get the current override mass.  The mass is not necessarily in use
         * at the moment.
-        * 
+        *
         * @return  the override mass
         */
        public final double getOverrideMass() {
+               mutex.verify();
                return overrideMass;
        }
        
        /**
         * Set the current override mass.  The mass is not set to use by this
         * method.
-        * 
+        *
         * @param m  the override mass
         */
        public final void setOverrideMass(double m) {
@@ -442,16 +468,17 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        /**
         * Return whether mass override is active for this component.  This does NOT
         * take into account whether a parent component is overriding the mass.
-        * 
+        *
         * @return  whether the mass is overridden
         */
        public final boolean isMassOverridden() {
+               mutex.verify();
                return massOverriden;
        }
        
        /**
         * Set whether the mass is currently overridden.
-        * 
+        *
         * @param o  whether the mass is overridden
         */
        public final void setMassOverridden(boolean o) {
@@ -469,25 +496,27 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
 
        /**
         * Return the current override CG.  The CG is not necessarily overridden.
-        * 
+        *
         * @return  the override CG
         */
        public final Coordinate getOverrideCG() {
+               mutex.verify();
                return getComponentCG().setX(overrideCGX);
        }
        
        /**
         * Return the x-coordinate of the current override CG.
-        * 
+        *
         * @return      the x-coordinate of the override CG.
         */
        public final double getOverrideCGX() {
+               mutex.verify();
                return overrideCGX;
        }
        
        /**
         * Set the current override CG to (x,0,0).
-        * 
+        *
         * @param x  the x-coordinate of the override CG to set.
         */
        public final void setOverrideCGX(double x) {
@@ -503,16 +532,17 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
        /**
         * Return whether the CG is currently overridden.
-        * 
+        *
         * @return  whether the CG is overridden
         */
        public final boolean isCGOverridden() {
+               mutex.verify();
                return cgOverriden;
        }
        
        /**
         * Set whether the CG is currently overridden.
-        * 
+        *
         * @param o  whether the CG is overridden
         */
        public final void setCGOverridden(boolean o) {
@@ -533,10 +563,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * always or never overrides subcomponents.  In this case the subclass should
         * also override {@link #isOverrideSubcomponentsEnabled()} to return
         * <code>false</code>.
-        * 
+        *
         * @return      whether the current mass and/or CG override overrides subcomponents as well.
         */
        public boolean getOverrideSubcomponents() {
+               mutex.verify();
                return overrideSubcomponents;
        }
        
@@ -544,7 +575,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        /**
         * Set whether the mass and/or CG override overrides all subcomponent values
         * as well.  See {@link #getOverrideSubcomponents()} for details.
-        * 
+        *
         * @param override      whether the mass and/or CG override overrides all subcomponent.
         */
        public void setOverrideSubcomponents(boolean override) {
@@ -563,10 +594,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * <p>
         * This method may be overridden if the setting of overriding subcomponents
         * cannot be set.
-        * 
+        *
         * @return      whether the option to override subcomponents is currently enabled.
         */
        public boolean isOverrideSubcomponentsEnabled() {
+               mutex.verify();
                return isCGOverridden() || isMassOverridden();
        }
        
@@ -577,6 +609,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * Get the user-defined name of the component.
         */
        public final String getName() {
+               mutex.verify();
                return name;
        }
        
@@ -600,16 +633,17 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        /**
         * Return the comment of the component.  The component may contain multiple lines
         * using \n as a newline separator.
-        * 
+        *
         * @return  the comment of the component.
         */
        public final String getComment() {
+               mutex.verify();
                return comment;
        }
        
        /**
         * Set the comment of the component.
-        * 
+        *
         * @param comment  the comment of the component.
         */
        public final void setComment(String comment) {
@@ -627,7 +661,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
 
        /**
         * Returns the unique ID of the component.
-        * 
+        *
         * @return      the ID of the component.
         */
        public final String getID() {
@@ -638,6 +672,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * Generate a new ID for this component.
         */
        private final void newID() {
+               mutex.verify();
                this.id = UniqueID.uuid();
        }
        
@@ -648,11 +683,12 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * Get the characteristic length of the component, for example the length of a body tube
         * of the length of the root chord of a fin.  This is used in positioning the component
         * relative to its parent.
-        * 
+        *
         * If the length of a component is settable, the class must define the setter method
         * itself.
         */
        public final double getLength() {
+               mutex.verify();
                return length;
        }
        
@@ -662,6 +698,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * but can be provided by a subclass.
         */
        public final Position getRelativePosition() {
+               mutex.verify();
                return relativePosition;
        }
        
@@ -674,7 +711,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * do not support setting the relative position.  A component that does support
         * it should override this with a public method that simply calls this
         * supermethod AND fire a suitable ComponentChangeEvent.
-        * 
+        *
         * @param position      the relative positioning.
         */
        protected void setRelativePosition(RocketComponent.Position position) {
@@ -718,10 +755,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        /**
         * Get the position value of the component.  The exact meaning of the value is
         * dependent on the current relative positioning.
-        * 
+        *
         * @return  the positional value.
         */
        public final double getPositionValue() {
+               mutex.verify();
                return position;
        }
        
@@ -734,7 +772,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * do not support setting the relative position.  A component that does support
         * it should override this with a public method that simply calls this
         * supermethod AND fire a suitable ComponentChangeEvent.
-        * 
+        *
         * @param value         the position value of the component.
         */
        public void setPositionValue(double value) {
@@ -758,16 +796,16 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
        
        /**
-        * Return coordinate <code>c</code> described in the coordinate system of 
+        * Return coordinate <code>c</code> described in the coordinate system of
         * <code>dest</code>.  If <code>dest</code> is <code>null</code> returns
         * absolute coordinates.
         * <p>
         * This method returns an array of coordinates, each of which represents a
         * position of the coordinate in clustered cases.  The array is guaranteed
-        * to contain at least one element.  
+        * to contain at least one element.
         * <p>
         * The current implementation does not support rotating components.
-        * 
+        *
         * @param c    Coordinate in the component's coordinate system.
         * @param dest Destination component coordinate system.
         * @return     an array of coordinates describing <code>c</code> in coordinates
@@ -775,101 +813,112 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         */
        public final Coordinate[] toRelative(Coordinate c, RocketComponent dest) {
                checkState();
-               double absoluteX = Double.NaN;
-               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;
+               mutex.lock("toRelative");
+               try {
+                       double absoluteX = Double.NaN;
+                       RocketComponent search = dest;
+                       Coordinate[] array = new Coordinate[1];
+                       array[0] = c;
                        
-                       case AFTER:
-                               // Add length of all previous brother-components with POSITION_RELATIVE_AFTER
-                               int index = component.parent.children.indexOf(component);
-                               assert (index >= 0);
-                               for (index--; index >= 0; index--) {
-                                       RocketComponent comp = component.parent.children.get(index);
-                                       double length = comp.getTotalLength();
+                       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(length, 0, 0);
+                                               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);
+                                       assert (index >= 0);
+                                       for (index--; index >= 0; index--) {
+                                               RocketComponent comp = component.parent.children.get(index);
+                                               double componentLength = comp.getTotalLength();
+                                               for (int i = 0; i < array.length; i++) {
+                                                       array[i] = array[i].add(componentLength, 0, 0);
+                                               }
+                                       }
+                                       for (int i = 0; i < array.length; i++) {
+                                               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].add(component.position + component.parent.length, 0, 0);
+                                       array[i] = array[i].setX(absoluteX + c.x);
                                }
-                               break;
+                       }
                        
-                       case ABSOLUTE:
-                               search = null; // Requires back-search if dest!=null
-                               if (Double.isNaN(absoluteX)) {
-                                       absoluteX = component.position;
+                       // 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)) {
+                               Coordinate[] origin = dest.toAbsolute(Coordinate.NUL);
+                               for (int i = 0; i < array.length; i++) {
+                                       array[i] = array[i].sub(origin[0]);
                                }
-                               break;
-                       
-                       default:
-                               throw new BugException("Unknown relative positioning type of component" +
-                                               component + ": " + component.relativePosition);
                        }
                        
-                       component = component.parent; // parent != null
+                       return array;
+               } finally {
+                       mutex.unlock("toRelative");
                }
-               
-               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)) {
-                       Coordinate[] origin = dest.toAbsolute(Coordinate.NUL);
-                       for (int i = 0; i < array.length; i++) {
-                               array[i] = array[i].sub(origin[0]);
-                       }
-               }
-               
-               return array;
        }
        
        
        /**
-        * Recursively sum the lengths of all subcomponents that have position 
+        * Recursively sum the lengths of all subcomponents that have position
         * Position.AFTER.
-        * 
+        *
         * @return  Sum of the lengths.
         */
        private final double getTotalLength() {
                checkState();
-               double l = 0;
-               if (relativePosition == Position.AFTER)
-                       l = length;
-               for (int i = 0; i < children.size(); i++)
-                       l += children.get(i).getTotalLength();
-               return l;
+               this.checkComponentStructure();
+               mutex.lock("getTotalLength");
+               try {
+                       double l = 0;
+                       if (relativePosition == Position.AFTER)
+                               l = length;
+                       for (int i = 0; i < children.size(); i++)
+                               l += children.get(i).getTotalLength();
+                       return l;
+               } finally {
+                       mutex.unlock("getTotalLength");
+               }
        }
        
        
@@ -878,10 +927,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
        /**
         * Return the (possibly overridden) mass of component.
-        * 
+        *
         * @return The mass of the component or the given override mass.
         */
        public final double getMass() {
+               mutex.verify();
                if (massOverriden)
                        return overrideMass;
                return getComponentMass();
@@ -889,10 +939,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
        /**
         * Return the (possibly overridden) center of gravity and mass.
-        * 
+        *
         * Returns the CG with the weight of the coordinate set to the weight of the component.
         * Both CG and mass may be separately overridden.
-        * 
+        *
         * @return The CG of the component or the given override CG.
         */
        public final Coordinate getCG() {
@@ -908,22 +958,22 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
        
        /**
-        * Return the longitudal (around the y- or z-axis) moment of inertia of this component.
+        * 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
         * and is relative to the non-overridden CG.
-        * 
-        * @return    the longitudal moment of inertia of this component.
+        *
+        * @return    the longitudinal moment of inertia of this component.
         */
-       public final double getLongitudalInertia() {
+       public final double getLongitudinalInertia() {
                checkState();
-               return getLongitudalUnitInertia() * getMass();
+               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
         * and is relative to the non-overridden CG.
-        * 
+        *
         * @return    the rotational moment of inertia of this component.
         */
        public final double getRotationalInertia() {
@@ -938,11 +988,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
 
        /**
         * Adds a child to the rocket component tree.  The component is added to the end
-        * of the component's child list.  This is a helper method that calls 
+        * of the component's child list.  This is a helper method that calls
         * {@link #addChild(RocketComponent,int)}.
-        * 
+        *
         * @param component  The component to add.
-        * @throws IllegalArgumentException  if the component is already part of some 
+        * @throws IllegalArgumentException  if the component is already part of some
         *                                                                       component tree.
         * @see #addChild(RocketComponent,int)
         */
@@ -953,18 +1003,18 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
        
        /**
-        * Adds a child to the rocket component tree.  The component is added to 
+        * Adds a child to the rocket component tree.  The component is added to
         * the given position of the component's child list.
         * <p>
-        * This method may be overridden to enforce more strict component addition rules.  
+        * This method may be overridden to enforce more strict component addition rules.
         * The tests should be performed first and then this method called.
-        * 
-        * @param component  The component to add.
-        * @param position   Position to add component to.
-        * @throws IllegalArgumentException  If the component is already part of 
+        *
+        * @param component     The component to add.
+        * @param index         Position to add component to.
+        * @throws IllegalArgumentException  If the component is already part of
         *                                                                       some component tree.
         */
-       public void addChild(RocketComponent component, int position) {
+       public void addChild(RocketComponent component, int index) {
                checkState();
                if (component.parent != null) {
                        throw new IllegalArgumentException("component " + component.getComponentName() +
@@ -975,16 +1025,19 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
                                        " not currently compatible with component " + getComponentName());
                }
                
-               children.add(position, component);
+               children.add(index, component);
                component.parent = this;
                
+               this.checkComponentStructure();
+               component.checkComponentStructure();
+               
                fireAddRemoveEvent(component);
        }
        
        
        /**
         * Removes a child from the rocket component tree.
-        * 
+        *
         * @param n  remove the n'th child.
         * @throws IndexOutOfBoundsException  if n is out of bounds
         */
@@ -992,20 +1045,31 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
                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.
-        * 
+        *
         * @param component             the component to remove
         * @return                              whether the component was a child
         */
        public final boolean removeChild(RocketComponent component) {
                checkState();
+               
+               component.checkComponentStructure();
+               
                if (children.remove(component)) {
                        component.parent = null;
+                       
+                       this.checkComponentStructure();
+                       component.checkComponentStructure();
+                       
                        fireAddRemoveEvent(component);
                        return true;
                }
@@ -1017,15 +1081,19 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
 
        /**
         * Move a child to another position.
-        * 
+        *
         * @param component     the component to move
-        * @param position      the component's new position
+        * @param index the component's new position
         * @throws IllegalArgumentException If an illegal placement was attempted.
         */
-       public final void moveChild(RocketComponent component, int position) {
+       public final void moveChild(RocketComponent component, int index) {
                checkState();
                if (children.remove(component)) {
-                       children.add(position, component);
+                       children.add(index, component);
+                       
+                       this.checkComponentStructure();
+                       component.checkComponentStructure();
+                       
                        fireAddRemoveEvent(component);
                }
        }
@@ -1036,7 +1104,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * type of component removed.
         */
        private void fireAddRemoveEvent(RocketComponent component) {
-               Iterator<RocketComponent> iter = component.deepIterator(true);
+               Iterator<RocketComponent> iter = component.iterator(true);
                int type = ComponentChangeEvent.TREE_CHANGE;
                while (iter.hasNext()) {
                        RocketComponent c = iter.next();
@@ -1052,36 +1120,40 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
        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 RocketComponent[] getChildren() {
+       public final List<RocketComponent> getChildren() {
                checkState();
-               return children.toArray(new RocketComponent[0]);
+               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.
-        * 
+        *
         * @param child  The child to search for.
         * @return  Position in the list or -1 if not found.
         */
        public final int getChildPosition(RocketComponent child) {
                checkState();
+               this.checkComponentStructure();
                return children.indexOf(child);
        }
        
        /**
         * Get the parent component of this component.  Returns <code>null</code> if the component
         * has no parent.
-        * 
+        *
         * @return  The parent of this component or <code>null</code>.
         */
        public final RocketComponent getParent() {
@@ -1091,7 +1163,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
        /**
         * Get the root component of the component tree.
-        * 
+        *
         * @return  The root component of the component tree.
         */
        public final RocketComponent getRoot() {
@@ -1103,9 +1175,9 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        }
        
        /**
-        * Returns the root Rocket component of this component tree.  Throws an 
+        * Returns the root Rocket component of this component tree.  Throws an
         * IllegalStateException if the root component is not a Rocket.
-        * 
+        *
         * @return  The root Rocket component of the component tree.
         * @throws  IllegalStateException  If the root component is not a Rocket.
         */
@@ -1122,7 +1194,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        /**
         * Return the Stage component that this component belongs to.  Throws an
         * IllegalStateException if a Stage is not in the parentage of this component.
-        * 
+        *
         * @return      The Stage component this component belongs to.
         * @throws      IllegalStateException   if a Stage component is not in the parentage.
         */
@@ -1140,7 +1212,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        /**
         * Return the stage number of the stage this component belongs to.  The stages
         * are numbered from zero upwards.
-        * 
+        *
         * @return   the stage number this component belongs to.
         */
        public final int getStageNumber() {
@@ -1165,13 +1237,13 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * 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,
         * or null if not found.
-        * 
+        *
         * @param idToFind  ID to search for.
         * @return    The component with the ID, or null if not found.
         */
        public final RocketComponent findComponent(String idToFind) {
                checkState();
-               Iterator<RocketComponent> iter = this.deepIterator(true);
+               Iterator<RocketComponent> iter = this.iterator(true);
                while (iter.hasNext()) {
                        RocketComponent c = iter.next();
                        if (c.getID().equals(idToFind))
@@ -1181,8 +1253,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        }
        
        
+       // TODO: Move these methods elsewhere (used only in SymmetricComponent)
        public final RocketComponent getPreviousComponent() {
                checkState();
+               this.checkComponentStructure();
                if (parent == null)
                        return null;
                int pos = parent.getChildPosition(this);
@@ -1210,21 +1284,22 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
                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 parent = this.parent;
+               RocketComponent nextParent = this.parent;
                
-               while (parent != null) {
-                       int pos = parent.getChildPosition(current);
-                       if (pos < parent.getChildCount() - 1)
-                               return parent.getChild(pos + 1);
+               while (nextParent != null) {
+                       int pos = nextParent.getChildPosition(current);
+                       if (pos < nextParent.getChildCount() - 1)
+                               return nextParent.getChild(pos + 1);
                        
-                       current = parent;
-                       parent = current.parent;
+                       current = nextParent;
+                       nextParent = current.parent;
                }
                return null;
        }
@@ -1240,7 +1315,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * 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
         * subcomponents are sent to all listeners.
-        * 
+        *
         * @throws IllegalStateException - if the root component is not a Rocket
         */
        public void addComponentChangeListener(ComponentChangeListener l) {
@@ -1253,7 +1328,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * the root component, which must be of type Rocket (which overrides this method).
         * Does nothing if the root component is not a Rocket.  (The asymmetry is so
         * that listeners can always be removed just in case.)
-        * 
+        *
         * @param l  Listener to remove
         */
        public void removeComponentChangeListener(ComponentChangeListener l) {
@@ -1264,14 +1339,15 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
        
        /**
-        * Adds a <code>ChangeListener</code> to the rocket tree.  This is identical to 
-        * <code>addComponentChangeListener()</code> except that it uses a 
+        * Adds a <code>ChangeListener</code> to the rocket tree.  This is identical to
+        * <code>addComponentChangeListener()</code> except that it uses a
         * <code>ChangeListener</code>.  The same events are dispatched to the
-        * <code>ChangeListener</code>, as <code>ComponentChangeEvent</code> is a subclass 
+        * <code>ChangeListener</code>, as <code>ComponentChangeEvent</code> is a subclass
         * of <code>ChangeEvent</code>.
-        * 
+        *
         * @throws IllegalStateException - if the root component is not a <code>Rocket</code>
         */
+       @Override
        public void addChangeListener(ChangeListener l) {
                checkState();
                getRocket().addChangeListener(l);
@@ -1282,9 +1358,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * removeComponentChangeListener() except it uses a ChangeListener.
         * Does nothing if the root component is not a Rocket.  (The asymmetry is so
         * that listeners can always be removed just in case.)
-        * 
+        *
         * @param l  Listener to remove
         */
+       @Override
        public void removeChangeListener(ChangeListener l) {
                if (this.parent != null) {
                        getRoot().removeChangeListener(l);
@@ -1293,14 +1370,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        
        
        /**
-        * Fires a ComponentChangeEvent on the rocket structure.  The call is passed to the 
+        * 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).
         * Events of all subcomponents are sent to all listeners.
-        * 
-        * If the component tree root is not a Rocket, the event is ignored.  This is the 
-        * case when constructing components not in any Rocket tree.  In this case it 
+        *
+        * If the component tree root is not a Rocket, the event is ignored.  This is the
+        * case when constructing components not in any Rocket tree.  In this case it
         * would be impossible for the component to have listeners in any case.
-        *  
+        *
         * @param e  Event to send
         */
        protected void fireComponentChangeEvent(ComponentChangeEvent e) {
@@ -1317,7 +1394,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        /**
         * Fires a ComponentChangeEvent of the given type.  The source of the event is set to
         * this component.
-        * 
+        *
         * @param type  Type of event
         * @see #fireComponentChangeEvent(ComponentChangeEvent)
         */
@@ -1331,158 +1408,127 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * This is a safety check that in-place replaced components are no longer used.
         * All non-trivial methods (with the exception of methods simply getting a property)
         * should call this method before changing or computing anything.
-        * 
+        *
         * @throws      BugException    if this component has been invalidated by {@link #copyFrom(RocketComponent)}.
         */
        protected void checkState() {
-               if (invalidated != null) {
-                       throw new BugException("This component has been invalidated.  Cause is the point of invalidation.",
-                                       invalidated);
-               }
+               invalidator.check(true);
+               mutex.verify();
        }
        
        
-       ///////////  Iterator implementation  //////////
-       
        /**
-        * Private inner class to implement the Iterator.
-        * 
-        * This iterator is fail-fast if the root of the structure is a Rocket.
+        * Check that the local component structure is correct.  This can be called after changing
+        * the component structure in order to verify the integrity.
+        * <p>
+        * TODO: Remove this after the "inconsistent internal state" bug has been corrected
         */
-       private class RocketComponentIterator implements Iterator<RocketComponent> {
-               // Stack holds iterators which still have some components left.
-               private final Stack<Iterator<RocketComponent>> iteratorstack =
-                                       new Stack<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;
-                               treeModID = root.getTreeModID();
-                       } else {
-                               root = null;
-                               treeModID = -1;
+       public void checkComponentStructure() {
+               if (this.parent != null) {
+                       // Test that this component is found in parent's children with == operator
+                       if (!containsExact(this.parent.children, this)) {
+                               throw new BugException("Inconsistent component structure detected, parent does not contain this " +
+                                               "component as a child, parent=" + parent.toDebugString() + " this=" + this.toDebugString());
                        }
-                       
-                       Iterator<RocketComponent> i = c.children.iterator();
-                       if (i.hasNext())
-                               iteratorstack.push(i);
-                       
-                       this.original = c;
-                       this.returnSelf = returnSelf;
                }
-               
-               public boolean hasNext() {
-                       checkState();
-                       checkID();
-                       if (returnSelf)
-                               return true;
-                       return !iteratorstack.empty(); // Elements remain if stack is not empty
-               }
-               
-               public RocketComponent next() {
-                       Iterator<RocketComponent> i;
-                       
-                       checkState();
-                       checkID();
-                       
-                       // Return original component first
-                       if (returnSelf) {
-                               returnSelf = false;
-                               return original;
-                       }
-                       
-                       // Peek first iterator from stack, throw exception if empty
-                       try {
-                               i = iteratorstack.peek();
-                       } catch (EmptyStackException e) {
-                               throw new NoSuchElementException("No further elements in " +
-                                               "RocketComponent iterator");
+               for (RocketComponent child : this.children) {
+                       if (child.parent != this) {
+                               throw new BugException("Inconsistent component structure detected, child does not have this component " +
+                                               "as the parent, this=" + this.toDebugString() + " child=" + child.toDebugString() +
+                                               " child.parent=" + (child.parent == null ? "null" : child.parent.toDebugString()));
                        }
-                       
-                       // 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) {
-                                       throw new IllegalStateException("Rocket modified while being iterated");
-                               }
+       }
+       
+       // Check whether the list contains exactly the searched-for component (with == operator)
+       private boolean containsExact(List<RocketComponent> haystack, RocketComponent needle) {
+               for (RocketComponent c : haystack) {
+                       if (needle == c) {
+                               return true;
                        }
                }
-               
-               public void remove() {
-                       throw new UnsupportedOperationException("remove() not supported by " +
-                                       "RocketComponent iterator");
-               }
+               return false;
        }
        
+       
+       ///////////  Iterators  //////////
+       
        /**
         * Returns an iterator that iterates over all children and sub-children.
-        * 
+        * <p>
         * The iterator iterates through all children below this object, including itself if
-        * returnSelf is true.  The order of the iteration is not specified
+        * <code>returnSelf</code> is true.  The order of the iteration is not specified
         * (it may be specified in the future).
-        * 
+        * <p>
         * If an iterator iterating over only the direct children of the component is required,
-        * use  component.getChildren().iterator()
-        * 
-        * @param returnSelf boolean value specifying whether the component itself should be 
+        * use <code>component.getChildren().iterator()</code>.
+        *
+        * TODO: HIGH: Remove this after merges have been done
+        *
+        * @param returnSelf boolean value specifying whether the component itself should be
         *                                       returned
         * @return An iterator for the children and sub-children.
+        * @deprecated Use {@link #iterator(boolean)} instead
         */
+       @Deprecated
        public final Iterator<RocketComponent> deepIterator(boolean returnSelf) {
-               checkState();
-               return new RocketComponentIterator(this, returnSelf);
+               return iterator(returnSelf);
        }
        
+       
+       /**
+        * Returns an iterator that iterates over all children and sub-children, including itself.
+        * <p>
+        * This method is equivalent to <code>deepIterator(true)</code>.
+        *
+        * TODO: HIGH: Remove this after merges have been done
+        *
+        * @return An iterator for this component, its children and sub-children.
+        * @deprecated Use {@link #iterator()} instead
+        */
+       @Deprecated
+       public final Iterator<RocketComponent> deepIterator() {
+               return iterator();
+       }
+       
+       
+
        /**
         * Returns an iterator that iterates over all children and sub-children.
-        * 
-        * The iterator does NOT return the component itself.  It is thus equivalent to
-        * deepIterator(false).
-        * 
-        * @see #iterator()
+        * <p>
+        * The iterator iterates through all children below this object, including itself if
+        * <code>returnSelf</code> is true.  The order of the iteration is not specified
+        * (it may be specified in the future).
+        * <p>
+        * If an iterator iterating over only the direct children of the component is required,
+        * use <code>component.getChildren().iterator()</code>.
+        *
+        * @param returnSelf boolean value specifying whether the component itself should be
+        *                                       returned
         * @return An iterator for the children and sub-children.
         */
-       public final Iterator<RocketComponent> deepIterator() {
+       public final Iterator<RocketComponent> iterator(boolean returnSelf) {
                checkState();
-               return new RocketComponentIterator(this, false);
+               return new RocketComponentIterator(this, returnSelf);
        }
        
        
        /**
-        * Return an iterator that iterates of the children of the component.  The iterator
-        * does NOT recurse to sub-children nor return itself.
-        * 
-        * @return An iterator for the children.
+        * Returns an iterator that iterates over this component, its children and sub-children.
+        * <p>
+        * This method is equivalent to <code>iterator(true)</code>.
+        *
+        * @return An iterator for this component, its children and sub-children.
         */
+       @Override
        public final Iterator<RocketComponent> iterator() {
-               checkState();
-               return Collections.unmodifiableList(children).iterator();
+               return iterator(true);
        }
        
        
 
 
+
        /**
         * Compare component equality based on the ID of this component.  Only the
         * ID and class type is used for a basis of comparison.
@@ -1516,7 +1562,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        /**
         * Helper method to add rotationally symmetric bounds at the specified coordinates.
         * The X-axis value is <code>x</code> and the radius at the specified position is
-        * <code>r</code>. 
+        * <code>r</code>.
         */
        protected static final void addBound(Collection<Coordinate> bounds, double x, double r) {
                bounds.add(new Coordinate(x, -r, -r));
@@ -1538,7 +1584,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
                                        length * density;
        }
        
-       protected static final double ringLongitudalUnitInertia(double outerRadius,
+       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;
@@ -1561,28 +1607,48 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
         * mechanism and when converting a finset into a freeform fin set.
         * This component must not have a parent, otherwise this method will fail.
         * <p>
-        * The fields are copied by reference, and the supplied component must not be used
-        * after the call, as it is in an undefined state.  This is enforced by invalidating
-        * the source component.
-        * 
-        * TODO: MEDIUM: Make general to copy all private/protected fields...
-        */
-       protected void copyFrom(RocketComponent src) {
+        * The child components in the source tree are copied into the current tree, however,
+        * the original components should not be used since they represent old copies of the
+        * components.  It is recommended to invalidate them by calling {@link #invalidate()}.
+        * <p>
+        * This method returns a list of components that should be invalidated after references
+        * to them have been removed (for example by firing appropriate events).  The list contains
+        * all children and sub-children of the current component and the entire component
+        * tree of <code>src</code>.
+        *
+        * @return      a list of components that should not be used after this call.
+        */
+       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 "
-                                       + this);
+                       throw new UnsupportedOperationException("copyFrom called for non-root component, parent=" +
+                                       this.parent.toDebugString() + ", this=" + this.toDebugString());
                }
                
-               // Set parents and children
-               this.children = src.children;
-               src.children = new ArrayList<RocketComponent>();
+               // Add current structure to be invalidated
+               Iterator<RocketComponent> iterator = this.iterator(false);
+               while (iterator.hasNext()) {
+                       toInvalidate.add(iterator.next());
+               }
                
-               for (RocketComponent c : this.children) {
-                       c.parent = this;
+               // 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;
@@ -1598,7 +1664,108 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
                this.comment = src.comment;
                this.id = src.id;
                
-               src.invalidated = new TraceException();
+               // 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.
+        *
+        * This iterator is fail-fast if the root of the structure is a Rocket.
+        */
+       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;
+                               treeModID = root.getTreeModID();
+                       } else {
+                               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();
+                       if (returnSelf)
+                               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) {
+                                       throw new IllegalStateException("Rocket modified while being iterated");
+                               }
+                       }
+               }
+               
+               @Override
+               public void remove() {
+                       throw new UnsupportedOperationException("remove() not supported by " +
+                                       "RocketComponent iterator");
+               }
        }
        
 }