version 1.1.3
authorplaa <plaa@180e2498-e6e9-4542-8430-84ac67f01cd8>
Wed, 6 Oct 2010 05:18:11 +0000 (05:18 +0000)
committerplaa <plaa@180e2498-e6e9-4542-8430-84ac67f01cd8>
Wed, 6 Oct 2010 05:18:11 +0000 (05:18 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@87 180e2498-e6e9-4542-8430-84ac67f01cd8

22 files changed:
ChangeLog
ReleaseNotes
build.properties
src/META-INF/services/net.sf.openrocket.optimization.rocketoptimization.RocketOptimizationParameterService [new file with mode: 0644]
src/net/sf/openrocket/document/Simulation.java
src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java [new file with mode: 0644]
src/net/sf/openrocket/gui/main/componenttree/ComponentTree.java
src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java
src/net/sf/openrocket/optimization/rocketoptimization/RocketOptimizationFunction.java
src/net/sf/openrocket/optimization/rocketoptimization/RocketOptimizationParameterService.java [new file with mode: 0644]
src/net/sf/openrocket/optimization/rocketoptimization/SimulationModifier.java
src/net/sf/openrocket/optimization/rocketoptimization/SimulationModifierService.java [new file with mode: 0644]
src/net/sf/openrocket/rocketcomponent/BodyComponent.java
src/net/sf/openrocket/rocketcomponent/BodyTube.java
src/net/sf/openrocket/rocketcomponent/RocketComponent.java
src/net/sf/openrocket/rocketcomponent/Transition.java
src/net/sf/openrocket/util/TextUtil.java
web/html/actions/updates.php
web/html/download.html
web/html/index.html
web/htp/htp.def
web/htp/news.htp

index fa9cde2e40284fbdfee037083524517bdd7ed0eb..8429a3d4f12dcdb9a6e03de8c9d334a3ec7d3083 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2010-10-06  Sampo Niskanen
+
+       * Released version 1.1.3
+
+2010-10-05  Sampo Niskanen
+
+       * Display comment as tooltip in component tree
+       * Limited allowed component attachments to those of the component
+         add buttons
+
 2010-10-03  Sampo Niskanen
 
        * Added VBOSE logging level
index 0f627333c4d01974ee1afb8ef5674f07c35e051f..613117165ae332fbfe8638ee6c7d3ecc695f75de 100644 (file)
@@ -1,3 +1,10 @@
+OpenRocket 1.1.3  (2010-10-06):
+-------------------------------
+
+Support for drag-drop moving and copying of components.  Fixes a
+severe bug in the undo system.
+
+
 OpenRocket 1.1.2  (2010-09-07):
 -------------------------------
 
index feb33a99016f976e5035db89d52288411035f72b..e0b2d14ea3fd5f0842d83afe624e2156f2335889 100644 (file)
@@ -1,7 +1,7 @@
 
 # The OpenRocket build version
 
-build.version=1.1.3pre
+build.version=1.1.3
 
 
 # The source of the package.  When building a package for a specific
diff --git a/src/META-INF/services/net.sf.openrocket.optimization.rocketoptimization.RocketOptimizationParameterService b/src/META-INF/services/net.sf.openrocket.optimization.rocketoptimization.RocketOptimizationParameterService
new file mode 100644 (file)
index 0000000..e69de29
index d7afa7c8ba3a33dd257f3d8a221945f533167ae1..db462aad8f158b182aacc57b2bf9c70b4ff96cfb 100644 (file)
@@ -9,6 +9,7 @@ import javax.swing.event.ChangeListener;
 import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
 import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
 import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.masscalc.BasicMassCalculator;
 import net.sf.openrocket.masscalc.MassCalculator;
 import net.sf.openrocket.rocketcomponent.Configuration;
@@ -23,11 +24,13 @@ import net.sf.openrocket.simulation.SimulationStepper;
 import net.sf.openrocket.simulation.exception.SimulationException;
 import net.sf.openrocket.simulation.exception.SimulationListenerException;
 import net.sf.openrocket.simulation.listeners.SimulationListener;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.ChangeSource;
 
 
 public class Simulation implements ChangeSource, Cloneable {
+       private static final LogHelper log = Application.getLogger();
        
        public static enum Status {
                /** Up-to-date */
@@ -238,22 +241,16 @@ public class Simulation implements ChangeSource, Cloneable {
                        throw new SimulationException("Cannot simulate imported simulation.");
                }
                
-               AerodynamicCalculator aerodynamicCalculator;
                SimulationEngine simulator;
-               SimulationStepper stepper;
-               MassCalculator massCalculator;
                
                try {
-                       aerodynamicCalculator = aerodynamicCalculatorClass.newInstance();
                        simulator = simulationEngineClass.newInstance();
-                       stepper = simulationStepperClass.newInstance();
-                       massCalculator = massCalculatorClass.newInstance();
                } catch (InstantiationException e) {
-                       throw new IllegalStateException("Cannot instantiate calculator/simulator.", e);
+                       throw new IllegalStateException("Cannot instantiate simulator.", e);
                } catch (IllegalAccessException e) {
-                       throw new IllegalStateException("Cannot access calc/sim instance?! BUG!", e);
+                       throw new IllegalStateException("Cannot access simulator instance?! BUG!", e);
                } catch (NullPointerException e) {
-                       throw new IllegalStateException("Calculator or simulator null", e);
+                       throw new IllegalStateException("Simulator null", e);
                }
                
                SimulationConditions simulationConditions = conditions.toSimulationConditions();
@@ -274,12 +271,11 @@ public class Simulation implements ChangeSource, Cloneable {
                }
                
                long t1, t2;
-               System.out.println("Simulation: calling simulator");
+               log.debug("Simulation: calling simulator");
                t1 = System.currentTimeMillis();
                simulatedData = simulator.simulate(simulationConditions);
                t2 = System.currentTimeMillis();
-               System.out.println("Simulation: returning from simulator, " +
-                               "simulation took " + (t2 - t1) + "ms");
+               log.debug("Simulation: returning from simulator, simulation took " + (t2 - t1) + "ms");
                
                // Set simulated info after simulation, will not be set in case of exception
                simulatedConditions = conditions.clone();
diff --git a/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java b/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java
new file mode 100644 (file)
index 0000000..39f9d2b
--- /dev/null
@@ -0,0 +1,86 @@
+package net.sf.openrocket.gui.dialogs.optimization;
+
+import java.awt.Window;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+import javax.swing.JDialog;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.optimization.rocketoptimization.RocketOptimizationParameter;
+import net.sf.openrocket.optimization.rocketoptimization.RocketOptimizationParameterService;
+import net.sf.openrocket.optimization.rocketoptimization.SimulationModifier;
+import net.sf.openrocket.optimization.rocketoptimization.SimulationModifierService;
+import net.sf.openrocket.util.BugException;
+
+public class GeneralOptimizationDialog extends JDialog {
+       
+       private final List<RocketOptimizationParameter> optimizationParameters = new ArrayList<RocketOptimizationParameter>();
+       private final Map<Object, List<SimulationModifier>> simulationModifiers =
+                       new HashMap<Object, List<SimulationModifier>>();
+       
+
+       private final OpenRocketDocument document;
+       
+       public GeneralOptimizationDialog(OpenRocketDocument document, Window parent) {
+               this.document = document;
+               
+               loadOptimizationParameters();
+               loadSimulationModifiers();
+       }
+       
+       
+       private void loadOptimizationParameters() {
+               ServiceLoader<RocketOptimizationParameterService> loader =
+                               ServiceLoader.load(RocketOptimizationParameterService.class);
+               
+               for (RocketOptimizationParameterService g : loader) {
+                       optimizationParameters.addAll(g.getParameters(document));
+               }
+               
+               if (optimizationParameters.isEmpty()) {
+                       throw new BugException("No rocket optimization parameters found, distribution built wrong.");
+               }
+               
+               Collections.sort(optimizationParameters, new Comparator<RocketOptimizationParameter>() {
+                       @Override
+                       public int compare(RocketOptimizationParameter o1, RocketOptimizationParameter o2) {
+                               return o1.getName().compareTo(o2.getName());
+                       }
+               });
+       }
+       
+       
+       private void loadSimulationModifiers() {
+               ServiceLoader<SimulationModifierService> loader = ServiceLoader.load(SimulationModifierService.class);
+               
+               for (SimulationModifierService g : loader) {
+                       for (SimulationModifier m : g.getModifiers(document)) {
+                               Object key = m.getRelatedObject();
+                               List<SimulationModifier> list = simulationModifiers.get(key);
+                               if (list == null) {
+                                       list = new ArrayList<SimulationModifier>();
+                                       simulationModifiers.put(key, list);
+                               }
+                               list.add(m);
+                       }
+               }
+               
+               for (Object key : simulationModifiers.keySet()) {
+                       List<SimulationModifier> list = simulationModifiers.get(key);
+                       Collections.sort(list, new Comparator<SimulationModifier>() {
+                               @Override
+                               public int compare(SimulationModifier o1, SimulationModifier o2) {
+                                       return o1.getName().compareTo(o2.getName());
+                               }
+                       });
+               }
+               
+       }
+       
+}
index e680c8554b97590c1fb68e3d6dced20488c9d347..09d229bc0106598dc7282fa70ae167821175c46e 100644 (file)
@@ -9,6 +9,7 @@ import java.awt.Graphics2D;
 import javax.swing.DropMode;
 import javax.swing.Icon;
 import javax.swing.JTree;
+import javax.swing.ToolTipManager;
 
 import net.sf.openrocket.document.OpenRocketDocument;
 
@@ -41,8 +42,13 @@ public class ComponentTree extends JTree {
                
                // Expand whole tree by default
                expandTree();
+               
+               // Enable tooltips for this component
+               ToolTipManager.sharedInstance().registerComponent(this);
+               
        }
        
+       
        public void expandTree() {
                for (int i = 0; i < getRowCount(); i++)
                        expandRow(i);
index 75fb2933d17b195419b72bc6ac9257e11f09202c..a7e8386ef6b354261a2eb9b69200eab30956de9b 100644 (file)
@@ -8,24 +8,38 @@ import javax.swing.JTree;
 import javax.swing.tree.DefaultTreeCellRenderer;
 
 import net.sf.openrocket.gui.main.ComponentIcons;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.util.TextUtil;
 
 public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
-
-    @Override
+       
+       @Override
        public Component getTreeCellRendererComponent(
-            JTree tree,
-            Object value,
-            boolean sel,
-            boolean expanded,
-            boolean leaf,
-            int row,
-            boolean hasFocus) {
-
-       super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
-       
-       setIcon(ComponentIcons.getSmallIcon(value.getClass()));
-       
-       return this;
-    }
+                       JTree tree,
+                       Object value,
+                       boolean sel,
+                       boolean expanded,
+                       boolean leaf,
+                       int row,
+                       boolean hasFocus) {
+               
+               super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
+               
+               // Set icon
+               setIcon(ComponentIcons.getSmallIcon(value.getClass()));
+               
+               // Set tooltip
+               RocketComponent c = (RocketComponent) value;
+               String comment = c.getComment().trim();
+               if (comment.length() > 0) {
+                       comment = TextUtil.htmlEncode(comment);
+                       comment = "<html>" + comment.replace("\n", "<br>");
+                       this.setToolTipText(comment);
+               } else {
+                       this.setToolTipText(null);
+               }
+               
+               return this;
+       }
        
 }
index 7a8404b16bdd96dd952dc57cfc65966b60003b94..c975a8a4fc41bc71b6f4f2c57376883ddcb2a5ba 100644 (file)
@@ -98,7 +98,7 @@ public class RocketOptimizationFunction implements Function {
                        return value;
                }
                
-               // TODO: CRITICAL: is in domain?
+               // TODO: : is in domain?
                return 0;
        }
        
diff --git a/src/net/sf/openrocket/optimization/rocketoptimization/RocketOptimizationParameterService.java b/src/net/sf/openrocket/optimization/rocketoptimization/RocketOptimizationParameterService.java
new file mode 100644 (file)
index 0000000..ecff025
--- /dev/null
@@ -0,0 +1,23 @@
+package net.sf.openrocket.optimization.rocketoptimization;
+
+import java.util.Collection;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+
+/**
+ * A service for generating rocket optimization parameters.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public interface RocketOptimizationParameterService {
+       
+       /**
+        * Return all available rocket optimization parameters for this document.
+        * These should be new instances unless the parameter implementation is stateless.
+        * 
+        * @param document      the design document
+        * @return                      a collection of the rocket optimization parameters.
+        */
+       public Collection<RocketOptimizationParameter> getParameters(OpenRocketDocument document);
+       
+}
index f0e1e7e1470a091741ba9042c39355cd016099aa..a22507d042957f74d8755ba31a679c7d17fa9b5e 100644 (file)
@@ -1,6 +1,8 @@
 package net.sf.openrocket.optimization.rocketoptimization;
 
 import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.ChangeSource;
 
 /**
  * An interface what modifies a single parameter in a rocket simulation
@@ -8,14 +10,80 @@ import net.sf.openrocket.document.Simulation;
  * 
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
-public interface SimulationModifier {
+public interface SimulationModifier extends ChangeSource {
        
+       /**
+        * Return a name describing this modifier.
+        * @return      a name describing this modifier.
+        */
+       public String getName();
+       
+       
+       /**
+        * Return the object this modifier is related to.  This is for example the
+        * rocket component this modifier is modifying.  This object can be used by a
+        * UI to group related modifiers.
+        * 
+        * @return      the object this modifier is related to, or <code>null</code>.
+        */
+       public Object getRelatedObject();
+       
+       
+       /**
+        * Return the current value of the modifier in SI units.
+        * @return      the current value of this parameter in SI units.
+        */
+       public double getCurrentValue();
+       
+       
+       /**
+        * Return the minimum value (corresponding to scaled value 0) in SI units.
+        * @return      the value corresponding to scaled value 0.
+        */
+       public double getMinValue();
+       
+       /**
+        * Set the minimum value (corresponding to scaled value 0) in SI units.
+        * @param value the value corresponding to scaled value 0.
+        */
+       public void setMinValue(double value);
+       
+       
+       /**
+        * Return the maximum value (corresponding to scaled value 1) in SI units.
+        * @return      the value corresponding to scaled value 1.
+        */
+       public double getMaxValue();
+       
+       /**
+        * Set the maximum value (corresponding to scaled value 1) in SI units.
+        * @param value the value corresponding to scaled value 1.
+        */
+       public void setMaxValue(double value);
+       
+       
+       /**
+        * Return the unit group used for the values returned by {@link #getCurrentValue()} etc.
+        * @return      the unit group
+        */
+       public UnitGroup getUnitGroup();
+       
+       
+       /**
+        * Return the current scaled value.  This is normally within the range [0...1], but
+        * can be outside the range if the current value is outside of the min and max values.
+        * @return
+        */
+       public double getCurrentScaledValue();
+       
+       
+
        /**
         * Modify the specified simulation to the corresponding parameter value.
         * 
         * @param simulation    the simulation to modify
-        * @param value                 a value in the range [0...1]
+        * @param scaledValue   the scaled value in the range [0...1]
         */
-       public void modify(Simulation simulation, double value);
+       public void modify(Simulation simulation, double scaledValue);
        
 }
diff --git a/src/net/sf/openrocket/optimization/rocketoptimization/SimulationModifierService.java b/src/net/sf/openrocket/optimization/rocketoptimization/SimulationModifierService.java
new file mode 100644 (file)
index 0000000..43b6196
--- /dev/null
@@ -0,0 +1,23 @@
+package net.sf.openrocket.optimization.rocketoptimization;
+
+import java.util.Collection;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+
+/**
+ * A service for generating simulation modifiers.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public interface SimulationModifierService {
+       
+       /**
+        * Return all available simulation modifiers for this document.
+        * 
+        * @param document      the design document
+        * @return                      a collection of the rocket optimization parameters.
+        */
+       public Collection<SimulationModifier> getModifiers(OpenRocketDocument document);
+       
+
+}
index 8c888320d487537bebc2ba926d6eef5338085a68..884893d559f90949d80a5ee0854f667ad12c3a31 100644 (file)
@@ -64,20 +64,4 @@ public abstract class BodyComponent extends ExternalComponent {
                return true;
        }
        
-       /**
-        * Check whether the given type can be added to this component.  BodyComponents allow any
-        * InternalComponents or ExternalComponents, excluding BodyComponents, to be added.
-        * 
-        * @param type  The RocketComponent class type to add.
-        * @return      Whether such a component can be added.
-        */
-       @Override
-       public boolean isCompatible(Class<? extends RocketComponent> type) {
-               if (InternalComponent.class.isAssignableFrom(type))
-                       return true;
-               if (ExternalComponent.class.isAssignableFrom(type) &&
-                               !BodyComponent.class.isAssignableFrom(type))
-                       return true;
-               return false;
-       }
 }
index b84478e7dc7f6578bb72a2e08173615f38fd717a..086c9efced9d03f6bbd8011c46e565ec86e066a0 100644 (file)
@@ -281,6 +281,24 @@ public class BodyTube extends SymmetricComponent implements MotorMount {
        }
        
        
+
+       /**
+        * Check whether the given type can be added to this component.  BodyTubes allow any
+        * InternalComponents or ExternalComponents, excluding BodyComponents, to be added.
+        * 
+        * @param type  The RocketComponent class type to add.
+        * @return      Whether such a component can be added.
+        */
+       @Override
+       public boolean isCompatible(Class<? extends RocketComponent> type) {
+               if (InternalComponent.class.isAssignableFrom(type))
+                       return true;
+               if (ExternalComponent.class.isAssignableFrom(type) &&
+                               !BodyComponent.class.isAssignableFrom(type))
+                       return true;
+               return false;
+       }
+       
        ////////////////  Motor mount  /////////////////
        
        @Override
index 1dd1b324a665165aedf25de99aba91364c233a4d..f6d575e3056566abde83255dff9bd6528199624f 100644 (file)
@@ -107,7 +107,6 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
        private String comment = "";
        
        // Unique ID of the component
-       // TODO: CRITICAL: Sort out usage of ID and undo defect
        private String id = null;
        
        /**
index af559b5ba086dc49d25cdf0858adf816972ee611..53b1a196e6246843a8407e4ffde501780047e55c 100644 (file)
@@ -13,15 +13,15 @@ import net.sf.openrocket.util.MathUtil;
 public class Transition extends SymmetricComponent {
        private static final double CLIP_PRECISION = 0.0001;
        
-       
+
        private Shape type;
        private double shapeParameter;
-       private boolean clipped;    // Not to be read - use isClipped(), which may be overriden
+       private boolean clipped; // Not to be read - use isClipped(), which may be overriden
        
        private double radius1, radius2;
-       private boolean autoRadius1, autoRadius2;   // Whether the start radius is automatic
-       
-       
+       private boolean autoRadius1, autoRadius2; // Whether the start radius is automatic
+                       
+
        private double foreShoulderRadius;
        private double foreShoulderThickness;
        private double foreShoulderLength;
@@ -31,9 +31,9 @@ public class Transition extends SymmetricComponent {
        private double aftShoulderLength;
        private boolean aftShoulderCapped;
        
-       
+
        // Used to cache the clip length
-       private double clipLength=-1;
+       private double clipLength = -1;
        
        public Transition() {
                super();
@@ -50,11 +50,11 @@ public class Transition extends SymmetricComponent {
        }
        
        
-       
-       
+
+
        ////////  Fore radius  ////////
        
-       
+
        @Override
        public double getForeRadius() {
                if (isForeRadiusAutomatic()) {
@@ -76,8 +76,8 @@ public class Transition extends SymmetricComponent {
                        return;
                
                this.autoRadius1 = false;
-               this.radius1 = Math.max(radius,0);
-
+               this.radius1 = Math.max(radius, 0);
+               
                if (this.thickness > this.radius1 && this.thickness > this.radius2)
                        this.thickness = Math.max(this.radius1, this.radius2);
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
@@ -96,7 +96,7 @@ public class Transition extends SymmetricComponent {
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
        
-
+       
        ////////  Aft radius  /////////
        
        @Override
@@ -116,19 +116,19 @@ public class Transition extends SymmetricComponent {
        }
        
        
-       
+
        public void setAftRadius(double radius) {
                if ((this.radius2 == radius) && (autoRadius2 == false))
                        return;
                
                this.autoRadius2 = false;
-               this.radius2 = Math.max(radius,0);
-
+               this.radius2 = Math.max(radius, 0);
+               
                if (this.thickness > this.radius1 && this.thickness > this.radius2)
                        this.thickness = Math.max(this.radius1, this.radius2);
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-
+       
        @Override
        public boolean isAftRadiusAutomatic() {
                return autoRadius2;
@@ -143,7 +143,7 @@ public class Transition extends SymmetricComponent {
        }
        
        
-       
+
        //// Radius automatics
        
        @Override
@@ -152,18 +152,18 @@ public class Transition extends SymmetricComponent {
                        return -1;
                return getAftRadius();
        }
-
-
+       
+       
        @Override
        protected double getRearAutoRadius() {
                if (isForeRadiusAutomatic())
                        return -1;
                return getForeRadius();
        }
-
-
        
        
+
+
        ////////  Type & shape  /////////
        
        public Shape getType() {
@@ -192,7 +192,7 @@ public class Transition extends SymmetricComponent {
                this.shapeParameter = MathUtil.clamp(n, type.minParameter(), type.maxParameter());
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-
+       
        public boolean isClipped() {
                if (!type.isClippable())
                        return false;
@@ -209,7 +209,7 @@ public class Transition extends SymmetricComponent {
        public boolean isClippedEnabled() {
                return type.isClippable();
        }
-
+       
        public double getShapeParameterMin() {
                return type.minParameter();
        }
@@ -224,29 +224,29 @@ public class Transition extends SymmetricComponent {
        public double getForeShoulderRadius() {
                return foreShoulderRadius;
        }
-
+       
        public void setForeShoulderRadius(double foreShoulderRadius) {
                if (MathUtil.equals(this.foreShoulderRadius, foreShoulderRadius))
                        return;
                this.foreShoulderRadius = foreShoulderRadius;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-
+       
        public double getForeShoulderThickness() {
                return foreShoulderThickness;
        }
-
+       
        public void setForeShoulderThickness(double foreShoulderThickness) {
                if (MathUtil.equals(this.foreShoulderThickness, foreShoulderThickness))
                        return;
                this.foreShoulderThickness = foreShoulderThickness;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-
+       
        public double getForeShoulderLength() {
                return foreShoulderLength;
        }
-
+       
        public void setForeShoulderLength(double foreShoulderLength) {
                if (MathUtil.equals(this.foreShoulderLength, foreShoulderLength))
                        return;
@@ -264,36 +264,36 @@ public class Transition extends SymmetricComponent {
                this.foreShoulderCapped = capped;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-
-
        
        
+
+
        public double getAftShoulderRadius() {
                return aftShoulderRadius;
        }
-
+       
        public void setAftShoulderRadius(double aftShoulderRadius) {
                if (MathUtil.equals(this.aftShoulderRadius, aftShoulderRadius))
                        return;
                this.aftShoulderRadius = aftShoulderRadius;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-
+       
        public double getAftShoulderThickness() {
                return aftShoulderThickness;
        }
-
+       
        public void setAftShoulderThickness(double aftShoulderThickness) {
                if (MathUtil.equals(this.aftShoulderThickness, aftShoulderThickness))
                        return;
                this.aftShoulderThickness = aftShoulderThickness;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-
+       
        public double getAftShoulderLength() {
                return aftShoulderLength;
        }
-
+       
        public void setAftShoulderLength(double aftShoulderLength) {
                if (MathUtil.equals(this.aftShoulderLength, aftShoulderLength))
                        return;
@@ -311,10 +311,10 @@ public class Transition extends SymmetricComponent {
                this.aftShoulderCapped = capped;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-
-
        
        
+
+
        ///////////   Shape implementations   ////////////
        
 
@@ -324,17 +324,17 @@ public class Transition extends SymmetricComponent {
         */
        @Override
        public double getRadius(double x) {
-               if (x<0 || x>length)
+               if (x < 0 || x > length)
                        return 0;
                
-               double r1=getForeRadius();
-               double r2=getAftRadius();
-
+               double r1 = getForeRadius();
+               double r2 = getAftRadius();
+               
                if (r1 == r2)
                        return r1;
                
                if (r1 > r2) {
-                       x = length-x;
+                       x = length - x;
                        double tmp = r1;
                        r1 = r2;
                        r2 = tmp;
@@ -343,29 +343,29 @@ public class Transition extends SymmetricComponent {
                if (isClipped()) {
                        // Check clip calculation
                        if (clipLength < 0)
-                               calculateClip(r1,r2);
-                       return type.getRadius(clipLength+x, r2, clipLength+length, shapeParameter);
+                               calculateClip(r1, r2);
+                       return type.getRadius(clipLength + x, r2, clipLength + length, shapeParameter);
                } else {
                        // Not clipped
-                       return r1 + type.getRadius(x, r2-r1, length, shapeParameter);
+                       return r1 + type.getRadius(x, r2 - r1, length, shapeParameter);
                }
        }
-
+       
        /**
         * Numerically solve clipLength from the equation
         *     r1 == type.getRadius(clipLength,r2,clipLength+length)
         * using a binary search.  It assumes getRadius() to be monotonically increasing.
         */
        private void calculateClip(double r1, double r2) {
-               double min=0, max=length;
+               double min = 0, max = length;
                
                if (r1 >= r2) {
-                       double tmp=r1;
+                       double tmp = r1;
                        r1 = r2;
                        r2 = tmp;
                }
                
-               if (r1==0) {
+               if (r1 == 0) {
                        clipLength = 0;
                        return;
                }
@@ -378,22 +378,22 @@ public class Transition extends SymmetricComponent {
                // Required:
                //    getR(min,min+length,r2) - r1 < 0
                //    getR(max,max+length,r2) - r1 > 0
-
-               int n=0;
-               while (type.getRadius(max, r2, max+length, shapeParameter) - r1 < 0) {
+               
+               int n = 0;
+               while (type.getRadius(max, r2, max + length, shapeParameter) - r1 < 0) {
                        min = max;
                        max *= 2;
                        n++;
-                       if (n>10)
+                       if (n > 10)
                                break;
                }
-
+               
                while (true) {
-                       clipLength = (min+max)/2;
-                       if ((max-min)<CLIP_PRECISION)
+                       clipLength = (min + max) / 2;
+                       if ((max - min) < CLIP_PRECISION)
                                return;
-                       double val = type.getRadius(clipLength, r2, clipLength+length, shapeParameter);
-                       if (val-r1 > 0) {
+                       double val = type.getRadius(clipLength, r2, clipLength + length, shapeParameter);
+                       if (val - r1 > 0) {
                                max = clipLength;
                        } else {
                                min = clipLength;
@@ -404,9 +404,9 @@ public class Transition extends SymmetricComponent {
        
        @Override
        public double getInnerRadius(double x) {
-               return Math.max(getRadius(x)-thickness,0);
+               return Math.max(getRadius(x) - thickness, 0);
        }
-               
+       
        
 
        @Override
@@ -444,7 +444,7 @@ public class Transition extends SymmetricComponent {
                
                return mass;
        }
-
+       
        @Override
        public Coordinate getComponentCG() {
                Coordinate cg = super.getComponentCG();
@@ -455,25 +455,25 @@ public class Transition extends SymmetricComponent {
                }
                if (isForeShoulderCapped()) {
                        final double ir = Math.max(getForeShoulderRadius() - getForeShoulderThickness(), 0);
-                       cg = cg.average(ringCG(ir, 0, -getForeShoulderLength(), 
-                                       getForeShoulderThickness()-getForeShoulderLength(),
+                       cg = cg.average(ringCG(ir, 0, -getForeShoulderLength(),
+                                       getForeShoulderThickness() - getForeShoulderLength(),
                                        getMaterial().getDensity()));
                }
                
                if (getAftShoulderLength() > 0.001) {
                        final double ir = Math.max(getAftShoulderRadius() - getAftShoulderThickness(), 0);
-                       cg = cg.average(ringCG(getAftShoulderRadius(), ir, getLength(), 
-                                       getLength()+getAftShoulderLength(), getMaterial().getDensity()));
+                       cg = cg.average(ringCG(getAftShoulderRadius(), ir, getLength(),
+                                       getLength() + getAftShoulderLength(), getMaterial().getDensity()));
                }
                if (isAftShoulderCapped()) {
                        final double ir = Math.max(getAftShoulderRadius() - getAftShoulderThickness(), 0);
-                       cg = cg.average(ringCG(ir, 0, 
-                                       getLength()+getAftShoulderLength()-getAftShoulderThickness(), 
-                                       getLength()+getAftShoulderLength(), getMaterial().getDensity()));
+                       cg = cg.average(ringCG(ir, 0,
+                                       getLength() + getAftShoulderLength() - getAftShoulderThickness(),
+                                       getLength() + getAftShoulderLength(), getMaterial().getDensity()));
                }
                return cg;
        }
-
+       
        
        /*
         * The moments of inertia are not explicitly corrected for the shoulders.
@@ -498,14 +498,29 @@ public class Transition extends SymmetricComponent {
        }
        
        
+       /**
+        * Check whether the given type can be added to this component.  Transitions allow any
+        * InternalComponents to be added.
+        * 
+        * @param type  The RocketComponent class type to add.
+        * @return      Whether such a component can be added.
+        */
+       @Override
+       public boolean isCompatible(Class<? extends RocketComponent> type) {
+               if (InternalComponent.class.isAssignableFrom(type))
+                       return true;
+               return false;
+       }
+       
        
+
        /**
         * An enumeration listing the possible shapes of transitions.
         * 
         * @author Sampo Niskanen <sampo.niskanen@iki.fi>
         */
        public static enum Shape {
-
+               
                /**
                 * Conical shape.
                 */
@@ -517,10 +532,10 @@ public class Transition extends SymmetricComponent {
                                assert x >= 0;
                                assert x <= length;
                                assert radius >= 0;
-                               return radius*x/length;
+                               return radius * x / length;
                        }
                },
-
+               
                /**
                 * Ogive shape.  The shape parameter is the portion of an extended tangent ogive
                 * that will be used.  That is, for param==1 a tangent ogive will be produced, and
@@ -528,21 +543,23 @@ public class Transition extends SymmetricComponent {
                 */
                OGIVE("Ogive",
                                "An ogive nose cone has a profile that is a segment of a circle.  " +
-                               "The shape parameter value 1 produces a <b>tangent ogive</b>, which has " +
-                               "a smooth transition to the body tube, values less than 1 produce "+
-                               "<b>secant ogives</b>.",
+                                               "The shape parameter value 1 produces a <b>tangent ogive</b>, which has " +
+                                               "a smooth transition to the body tube, values less than 1 produce " +
+                                               "<b>secant ogives</b>.",
                                "An ogive transition has a profile that is a segment of a circle.  " +
-                               "The shape parameter value 1 produces a <b>tangent ogive</b>, which has " +
-                               "a smooth transition to the body tube at the aft end, values less than 1 " +
-                               "produce <b>secant ogives</b>.") {
+                                               "The shape parameter value 1 produces a <b>tangent ogive</b>, which has " +
+                                               "a smooth transition to the body tube at the aft end, values less than 1 " +
+                                               "produce <b>secant ogives</b>.") {
                        @Override
                        public boolean usesParameter() {
-                               return true;   // Range 0...1 is default
+                               return true; // Range 0...1 is default
                        }
+                       
                        @Override
                        public double defaultParameter() {
-                               return 1.0;    // Tangent ogive by default
+                               return 1.0; // Tangent ogive by default
                        }
+                       
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
@@ -562,56 +579,58 @@ public class Transition extends SymmetricComponent {
                                        return CONICAL.getRadius(x, radius, length, param);
                                
                                // Radius of circle is:
-                               double R = sqrt((pow2(length)+pow2(radius)) *
-                                               (pow2((2-param)*length) + pow2(param*radius))/(4*pow2(param*radius)));
-                               double L = length/param;
-//                             double R = (radius + length*length/(radius*param*param))/2;
-                               double y0 = sqrt(R*R - L*L);
-                               return sqrt(R*R - (L-x)*(L-x)) - y0;
+                               double R = sqrt((pow2(length) + pow2(radius)) *
+                                               (pow2((2 - param) * length) + pow2(param * radius)) / (4 * pow2(param * radius)));
+                               double L = length / param;
+                               //                              double R = (radius + length*length/(radius*param*param))/2;
+                               double y0 = sqrt(R * R - L * L);
+                               return sqrt(R * R - (L - x) * (L - x)) - y0;
                        }
                },
-
+               
                /**
                 * Ellipsoidal shape.
                 */
                ELLIPSOID("Ellipsoid",
-                               "An ellipsoidal nose cone has a profile of a half-ellipse "+
-                               "with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.",
-                               "An ellipsoidal transition has a profile of a half-ellipse "+
-                               "with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.  If the "+
-                               "transition is not clipped, then the profile is extended at the center by the "+
-                               "corresponding radius.",true) {
+                               "An ellipsoidal nose cone has a profile of a half-ellipse " +
+                                               "with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.",
+                               "An ellipsoidal transition has a profile of a half-ellipse " +
+                                               "with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.  If the " +
+                                               "transition is not clipped, then the profile is extended at the center by the " +
+                                               "corresponding radius.", true) {
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
                                assert x <= length;
                                assert radius >= 0;
-                               x = x*radius/length;
-                               return sqrt(2*radius*x-x*x);  // radius/length * sphere
+                               x = x * radius / length;
+                               return sqrt(2 * radius * x - x * x); // radius/length * sphere
                        }
                },
-
+               
                POWER("Power series",
-                               "A power series nose cone has a profile of "+
-                               "<i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)" +
-                               "<sup><i>k</i></sup> "+
-                               "where <i>k</i> is the shape parameter.  For <i>k</i>=0.5 this is a "+
-                               "<b>" + FRAC12 +"-power</b> or <b>parabolic</b> nose cone, for <i>k</i>=0.75 a "+
-                               "<b>" + FRAC34 +"-power</b>, and for <i>k</i>=1 a <b>conical</b> nose cone.",
-                               "A power series transition has a profile of "+
-                               "<i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)" +
-                               "<sup><i>k</i></sup> "+
-                               "where <i>k</i> is the shape parameter.  For <i>k</i>=0.5 the transition is "+
-                               "<b>" + FRAC12 + "-power</b> or <b>parabolic</b>, for <i>k</i>=0.75 a " +
-                               "<b>" + FRAC34 + "-power</b>, and for <i>k</i>=1 <b>conical</b>.",true) {
+                               "A power series nose cone has a profile of " +
+                                               "<i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)" +
+                                               "<sup><i>k</i></sup> " +
+                                               "where <i>k</i> is the shape parameter.  For <i>k</i>=0.5 this is a " +
+                                               "<b>" + FRAC12 + "-power</b> or <b>parabolic</b> nose cone, for <i>k</i>=0.75 a " +
+                                               "<b>" + FRAC34 + "-power</b>, and for <i>k</i>=1 a <b>conical</b> nose cone.",
+                               "A power series transition has a profile of " +
+                                               "<i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)" +
+                                               "<sup><i>k</i></sup> " +
+                                               "where <i>k</i> is the shape parameter.  For <i>k</i>=0.5 the transition is " +
+                                               "<b>" + FRAC12 + "-power</b> or <b>parabolic</b>, for <i>k</i>=0.75 a " +
+                                               "<b>" + FRAC34 + "-power</b>, and for <i>k</i>=1 <b>conical</b>.", true) {
                        @Override
-                       public boolean usesParameter() {  // Range 0...1
+                       public boolean usesParameter() { // Range 0...1
                                return true;
                        }
+                       
                        @Override
                        public double defaultParameter() {
                                return 0.5;
                        }
+                       
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
@@ -619,40 +638,42 @@ public class Transition extends SymmetricComponent {
                                assert radius >= 0;
                                assert param >= 0;
                                assert param <= 1;
-                               if (param<=0.00001) {
-                                       if (x<=0.00001)
+                               if (param <= 0.00001) {
+                                       if (x <= 0.00001)
                                                return 0;
                                        else
                                                return radius;
                                }
-                               return radius*Math.pow(x/length, param);
+                               return radius * Math.pow(x / length, param);
                        }
                        
                },
                
                PARABOLIC("Parabolic series",
-                               "A parabolic series nose cone has a profile of a parabola.  The shape "+
-                               "parameter defines the segment of the parabola to utilize.  The shape " +
-                               "parameter 1.0 produces a <b>full parabola</b> which is tangent to the body " +
-                               "tube, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a " +
-                               "<b>1/2 parabola</b> and 0 produces a <b>conical</b> nose cone.",
-                               "A parabolic series transition has a profile of a parabola.  The shape "+
-                               "parameter defines the segment of the parabola to utilize.  The shape " +
-                               "parameter 1.0 produces a <b>full parabola</b> which is tangent to the body " +
-                               "tube at the aft end, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a " +
-                               "<b>1/2 parabola</b> and 0 produces a <b>conical</b> transition.") {
+                               "A parabolic series nose cone has a profile of a parabola.  The shape " +
+                                               "parameter defines the segment of the parabola to utilize.  The shape " +
+                                               "parameter 1.0 produces a <b>full parabola</b> which is tangent to the body " +
+                                               "tube, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a " +
+                                               "<b>1/2 parabola</b> and 0 produces a <b>conical</b> nose cone.",
+                               "A parabolic series transition has a profile of a parabola.  The shape " +
+                                               "parameter defines the segment of the parabola to utilize.  The shape " +
+                                               "parameter 1.0 produces a <b>full parabola</b> which is tangent to the body " +
+                                               "tube at the aft end, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a " +
+                                               "<b>1/2 parabola</b> and 0 produces a <b>conical</b> transition.") {
                        
                        // In principle a parabolic transition is clippable, but the difference is
                        // negligible.
                        
                        @Override
-                       public boolean usesParameter() {  // Range 0...1
+                       public boolean usesParameter() { // Range 0...1
                                return true;
                        }
+                       
                        @Override
                        public double defaultParameter() {
                                return 1.0;
                        }
+                       
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
@@ -660,31 +681,33 @@ public class Transition extends SymmetricComponent {
                                assert radius >= 0;
                                assert param >= 0;
                                assert param <= 1;
-
-                               return radius * ((2*x/length - param*pow2(x/length))/(2-param));
+                               
+                               return radius * ((2 * x / length - param * pow2(x / length)) / (2 - param));
                        }
                },
                
-               
-               
+
+
                HAACK("Haack series",
                                "The Haack series nose cones are designed to minimize drag.  The shape parameter " +
-                               "0 produces an <b>LD-Haack</b> or <b>Von Karman</b> nose cone, which minimizes " +
-                               "drag for fixed length and diameter, while a value of 0.333 produces an " +
-                               "<b>LV-Haack</b> nose cone, which minimizes drag for fixed length and volume.",
+                                               "0 produces an <b>LD-Haack</b> or <b>Von Karman</b> nose cone, which minimizes " +
+                                               "drag for fixed length and diameter, while a value of 0.333 produces an " +
+                                               "<b>LV-Haack</b> nose cone, which minimizes drag for fixed length and volume.",
                                "The Haack series <i>nose cones</i> are designed to minimize drag.  " +
-                               "These transition shapes are their equivalents, but do not necessarily produce " +
-                               "optimal drag for transitions.  " +
-                               "The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> shape, " +
-                               "while a value of 0.333 produces an <b>LV-Haack</b> shape.",true) {
+                                               "These transition shapes are their equivalents, but do not necessarily produce " +
+                                               "optimal drag for transitions.  " +
+                                               "The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> shape, " +
+                                               "while a value of 0.333 produces an <b>LV-Haack</b> shape.", true) {
                        @Override
                        public boolean usesParameter() {
                                return true;
                        }
-                       @Override 
+                       
+                       @Override
                        public double maxParameter() {
-                               return 1.0/3.0;  // Range 0...1/3
+                               return 1.0 / 3.0; // Range 0...1/3
                        }
+                       
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
@@ -692,58 +715,58 @@ public class Transition extends SymmetricComponent {
                                assert radius >= 0;
                                assert param >= 0;
                                assert param <= 2;
-
-                               double theta = Math.acos(1-2*x/length); 
-                               if (param==0) {
-                                       return radius*sqrt((theta-sin(2*theta)/2)/Math.PI);
+                               
+                               double theta = Math.acos(1 - 2 * x / length);
+                               if (param == 0) {
+                                       return radius * sqrt((theta - sin(2 * theta) / 2) / Math.PI);
                                }
-                               return radius*sqrt((theta-sin(2*theta)/2+param*pow3(sin(theta)))/Math.PI);
+                               return radius * sqrt((theta - sin(2 * theta) / 2 + param * pow3(sin(theta))) / Math.PI);
                        }
                },
                
-//             POLYNOMIAL("Smooth polynomial",
-//                             "A polynomial is fitted such that the nose cone profile is horizontal "+
-//                             "at the aft end of the transition.  The angle at the tip is defined by "+
-//                             "the shape parameter.",
-//                             "A polynomial is fitted such that the transition profile is horizontal "+
-//                             "at the aft end of the transition.  The angle at the fore end is defined "+
-//                             "by the shape parameter.") {
-//                     @Override
-//                     public boolean usesParameter() {
-//                             return true;
-//                     }
-//                     @Override
-//                     public double maxParameter() {
-//                             return 3.0;   //  Range 0...3
-//                     }
-//                     @Override
-//                     public double defaultParameter() {
-//                             return 0.0;
-//                     }
-//                     public double getRadius(double x, double radius, double length, double param) {
-//                             assert x >= 0;
-//                             assert x <= length;
-//                             assert radius >= 0;
-//                             assert param >= 0;
-//                             assert param <= 3;
-//                             // p(x) = (k-2)x^3 + (3-2k)x^2 + k*x
-//                             x = x/length;
-//                             return radius*((((param-2)*x + (3-2*param))*x + param)*x);
-//                     }
-//             }
+               //              POLYNOMIAL("Smooth polynomial",
+               //                              "A polynomial is fitted such that the nose cone profile is horizontal "+
+               //                              "at the aft end of the transition.  The angle at the tip is defined by "+
+               //                              "the shape parameter.",
+               //                              "A polynomial is fitted such that the transition profile is horizontal "+
+               //                              "at the aft end of the transition.  The angle at the fore end is defined "+
+               //                              "by the shape parameter.") {
+               //                      @Override
+               //                      public boolean usesParameter() {
+               //                              return true;
+               //                      }
+               //                      @Override
+               //                      public double maxParameter() {
+               //                              return 3.0;   //  Range 0...3
+               //                      }
+               //                      @Override
+               //                      public double defaultParameter() {
+               //                              return 0.0;
+               //                      }
+               //                      public double getRadius(double x, double radius, double length, double param) {
+               //                              assert x >= 0;
+               //                              assert x <= length;
+               //                              assert radius >= 0;
+               //                              assert param >= 0;
+               //                              assert param <= 3;
+               //                              // p(x) = (k-2)x^3 + (3-2k)x^2 + k*x
+               //                              x = x/length;
+               //                              return radius*((((param-2)*x + (3-2*param))*x + param)*x);
+               //                      }
+               //              }
                ;
-                                               
+               
                // Privete fields of the shapes
                private final String name;
                private final String transitionDesc;
                private final String noseconeDesc;
                private final boolean canClip;
-
+               
                // Non-clippable constructor
                Shape(String name, String noseconeDesc, String transitionDesc) {
-                       this(name,noseconeDesc,transitionDesc,false);
+                       this(name, noseconeDesc, transitionDesc, false);
                }
-
+               
                // Clippable constructor
                Shape(String name, String noseconeDesc, String transitionDesc, boolean canClip) {
                        this.name = name;
@@ -773,7 +796,7 @@ public class Transition extends SymmetricComponent {
                public String getNoseConeDescription() {
                        return noseconeDesc;
                }
-
+               
                /**
                 * Check whether the shape differs in clipped mode.  The clipping should be
                 * enabled by default if possible.
@@ -788,7 +811,7 @@ public class Transition extends SymmetricComponent {
                public boolean usesParameter() {
                        return false;
                }
-
+               
                /**
                 * Return the minimum value of the shape parameter.  (Default 0.)
                 */
@@ -809,7 +832,7 @@ public class Transition extends SymmetricComponent {
                public double defaultParameter() {
                        return 0.0;
                }
-
+               
                /**
                 * Calculate the basic radius of a transition with the given radius, length and
                 * shape parameter at the point x from the tip of the component.  It is assumed
@@ -823,7 +846,7 @@ public class Transition extends SymmetricComponent {
                 * @return       The basic radius at the given position.
                 */
                public abstract double getRadius(double x, double radius, double length, double param);
-
+               
                
                /**
                 * Returns the name of the shape (same as getName()).
index c6a1bb835c6e99c09983e4f60d0347bd58864c9b..32dffd849a4eb0c13cc92d8c1eb613df76e5b327 100644 (file)
@@ -2,11 +2,11 @@ package net.sf.openrocket.util;
 
 
 public class TextUtil {
-       private static final char[] HEX = { 
-               '0','1','2','3','4','5','6','7',
-               '8','9','a','b','c','d','e','f' 
+       private static final char[] HEX = {
+                       '0', '1', '2', '3', '4', '5', '6', '7',
+                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
        };
-
+       
        
        /**
         * Return the bytes formatted as a hexadecimal string.  The length of the
@@ -18,13 +18,13 @@ public class TextUtil {
         */
        public static final String hexString(byte[] bytes) {
                StringBuilder sb = new StringBuilder(bytes.length * 2);
-               for (byte b: bytes) {
+               for (byte b : bytes) {
                        sb.append(HEX[(b >>> 4) & 0xF]);
                        sb.append(HEX[b & 0xF]);
                }
                return sb.toString();
        }
-
+       
        /**
         * Return a string of the double value with suitable precision (5 digits).
         * The string is the shortest representation of the value including the
@@ -49,7 +49,7 @@ public class TextUtil {
                                return "Inf";
                }
                
-               
+
                final String sign = (d < 0) ? "-" : "";
                double abs = Math.abs(d);
                
@@ -95,7 +95,7 @@ public class TextUtil {
         */
        private static String decimalFormat(double value) {
                if (value >= 10000)
-                       return "" + (int)(value + 0.5);
+                       return "" + (int) (value + 0.5);
                
                int decimals = 1;
                double v = value;
@@ -108,8 +108,8 @@ public class TextUtil {
        }
        
        
-       
-       
+
+
        /*
         * value must be positive!
         */
@@ -118,42 +118,50 @@ public class TextUtil {
                // Calculate rounding and limit values (rounding slightly smaller)
                int rounding = 1;
                double limit = 0.5;
-               for (int i=0; i<decimals; i++) {
+               for (int i = 0; i < decimals; i++) {
                        rounding *= 10;
                        limit /= 10;
                }
-
-               // Round value
-               value = (Math.rint(value * rounding)+0.1) / rounding;
                
+               // Round value
+               value = (Math.rint(value * rounding) + 0.1) / rounding;
                
-               int whole = (int)value;
+
+               int whole = (int) value;
                value -= whole;
                
-               
+
                if (value < limit)
-                       return "" + whole; 
+                       return "" + whole;
                limit *= 10;
-
+               
                StringBuilder sb = new StringBuilder();
                sb.append("" + whole);
                sb.append('.');
-
                
-               for (int i = 0; i<decimals; i++) {
+
+               for (int i = 0; i < decimals; i++) {
                        
                        value *= 10;
-                       whole = (int)value;
+                       whole = (int) value;
                        value -= whole;
-                       sb.append((char)('0' + whole));
+                       sb.append((char) ('0' + whole));
                        
                        if (value < limit)
                                return sb.toString();
                        limit *= 10;
-
+                       
                }
-
+               
                return sb.toString();
        }
-
+       
+       
+       public static String htmlEncode(String s) {
+               s = s.replace("&", "&amp;");
+               s = s.replace("\"", "&quot;");
+               s = s.replace("<", "&lt;");
+               s = s.replace(">", "&gt;");
+               return s;
+       }
 }
index fa109631e4db9f2de4bfb82d6c300b739b4794ad..ea686483385befd13350f799d0d41bee72fccb64 100644 (file)
@@ -80,16 +80,18 @@ header("Content-type: text/plain");
 $version = $_GET["version"];
 $updates = "";
 
-$unstable = "1.1.2";
+$unstable = "1.1.3";
 $stable = "1.0.0";
 
-if (preg_match("/^1\.1\.1/", $version)) {
+if (preg_match("/^1\.1\.[12]/", $version)) {
   $updates = "Version: " . $unstable . "\n" .
-    "4: Fixed bug preventing addition of stages\n";
+    "5: Initial drag-and-drop support\n" .
+    "4: Bug fixes\n";
 } else if (preg_match("/^1\.1\.0/", $version)) {
   $updates = "Version: " . $unstable . "\n" .
     "6: Enhanced motor selection\n" .
     "5: Rewritten simulation code\n" .
+    "5: Drag-and-drop support\n" .
     "4: Bug fixes";
 } else if (preg_match("/^0\.9\.6/", $version)) {
   $updates = "Version: " . $stable . "\n" .
index 884d32e1a5f29adfd3a1db60d487fffc50d0d9d2..ddb2b5be3bead929bc9e683dde699f41782978c6 100644 (file)
   <div class="content">
 <div class="news">
       <h2>Recent news:</h2>
+  <p><span class="date">6.10.2010:</span> Version 1.1.3 is
+    <a href="download.html">released</a>!</p>
+  <p>This release includes support for moving and copying components
+    in the component tree using drag-and-drop.  Use normal DnD for
+    moving, and control-drag for copy.  This release also fixes a
+    severe bug in the undo system.</p>
   <p><span class="date">7.9.2010:</span> A bug-fix version 1.1.2 is
     <a href="download.html">released</a>!</p>
   <p>This release fixes a severe bug in 1.1.1 that prevented adding stages
         <a href="http://sourceforge.net/donate/index.php?group_id=260357"><img src="project-support.jpg" width="88" height="32" alt="Support This Project" /></a>
       </div>
         <div class="downloadbox">
-    <a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.2/OpenRocket-1.1.2.jar/download">
+    <a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.3/OpenRocket-1.1.3.jar/download">
       <strong>Download now!</strong>
-      <span>OpenRocket-1.1.2.jar</span>
+      <span>OpenRocket-1.1.3.jar</span>
     </a>
     <span class="alternative">
-      <a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.2/ReleaseNotes/view">Release notes</a> |
-            <a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.2/OpenRocket-1.1.2-src.zip/download">Source code</a>
+      <a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.3/ReleaseNotes/view">Release notes</a> |
+            <a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.3/OpenRocket-1.1.3-src.zip/download">Source code</a>
     </span>
   </div>
       <h3>Stable release</h3>
        Windows) by double-clicking the package icon.  No installation is
        required.</p>
       <p>From the command line OpenRocket can be started by
-      <span class="command">java -jar OpenRocket-1.1.2.jar</span></p>
+      <span class="command">java -jar OpenRocket-1.1.3.jar</span></p>
        
     </div>
     <div class="clear"></div>
index 9320b0060aad36ae09131f737c87b6d80d90e161..aa10d745a8342bac831c6d0a04ade368a986e602 100644 (file)
     <h2>Introduction</h2>
     <div class="rightpane">
         <div class="downloadbox">
-    <a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.2/OpenRocket-1.1.2.jar/download">
+    <a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.3/OpenRocket-1.1.3.jar/download">
       <strong>Download now!</strong>
-      <span>OpenRocket-1.1.2.jar</span>
+      <span>OpenRocket-1.1.3.jar</span>
     </a>
     <span class="alternative">
-      <a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.2/ReleaseNotes/view">Release notes</a> |
+      <a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.3/ReleaseNotes/view">Release notes</a> |
             <a href="download.html">Other versions</a>
     </span>
   </div>
     <div class="clear"></div>
 <div class="news">
       <h2>News</h2>
+  <p><span class="date">6.10.2010:</span> Version 1.1.3 is
+    <a href="download.html">released</a>!</p>
+  <p>This release includes support for moving and copying components
+    in the component tree using drag-and-drop.  Use normal DnD for
+    moving, and control-drag for copy.  This release also fixes a
+    severe bug in the undo system.</p>
   <p><span class="date">7.9.2010:</span> A bug-fix version 1.1.2 is
     <a href="download.html">released</a>!</p>
   <p>This release fixes a severe bug in 1.1.1 that prevented adding stages
index 17e166807ea1d57292b8afc9cbf3796f1e7851bd..8fd48dea324333f44d93f8f76881ac133e41ff6f 100644 (file)
@@ -1,5 +1,5 @@
 <set stableversion="1.0.0">
-<set developmentversion="1.1.2">
+<set developmentversion="1.1.3">
 <set version="${developmentversion}">
 
 <def name="downloadbox">
index da5a7076c4c08c184b1a7b371f7e12ee075e931f..03938a0d666045fe7742c4fa4aaa4988e32ca0cf 100644 (file)
@@ -9,6 +9,14 @@
 
   <!--- Remember to move the position of "onlyrecent" below! --->
 
+  <p><span class="date">6.10.2010:</span> Version 1.1.3 is 
+    <a href="download.html">released</a>!</p>
+
+  <p>This release includes support for moving and copying components
+    in the component tree using drag-and-drop.  Use normal DnD for
+    moving, and control-drag for copy.  This release also fixes a
+    severe bug in the undo system.</p>
+
   <p><span class="date">7.9.2010:</span> A bug-fix version 1.1.2 is 
     <a href="download.html">released</a>!</p>