From ccf94c198483ee58fcae432dcb0721c75c7a556c Mon Sep 17 00:00:00 2001 From: plaa Date: Wed, 6 Oct 2010 05:18:11 +0000 Subject: [PATCH 1/1] version 1.1.3 git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@87 180e2498-e6e9-4542-8430-84ac67f01cd8 --- ChangeLog | 10 + ReleaseNotes | 7 + build.properties | 2 +- ...ization.RocketOptimizationParameterService | 0 .../sf/openrocket/document/Simulation.java | 20 +- .../GeneralOptimizationDialog.java | 86 ++++ .../gui/main/componenttree/ComponentTree.java | 6 + .../componenttree/ComponentTreeRenderer.java | 46 ++- .../RocketOptimizationFunction.java | 2 +- .../RocketOptimizationParameterService.java | 23 ++ .../SimulationModifier.java | 74 +++- .../SimulationModifierService.java | 23 ++ .../rocketcomponent/BodyComponent.java | 16 - .../openrocket/rocketcomponent/BodyTube.java | 18 + .../rocketcomponent/RocketComponent.java | 1 - .../rocketcomponent/Transition.java | 383 ++++++++++-------- src/net/sf/openrocket/util/TextUtil.java | 58 +-- web/html/actions/updates.php | 8 +- web/html/download.html | 16 +- web/html/index.html | 12 +- web/htp/htp.def | 2 +- web/htp/news.htp | 8 + 22 files changed, 554 insertions(+), 267 deletions(-) create mode 100644 src/META-INF/services/net.sf.openrocket.optimization.rocketoptimization.RocketOptimizationParameterService create mode 100644 src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java create mode 100644 src/net/sf/openrocket/optimization/rocketoptimization/RocketOptimizationParameterService.java create mode 100644 src/net/sf/openrocket/optimization/rocketoptimization/SimulationModifierService.java diff --git a/ChangeLog b/ChangeLog index fa9cde2e..8429a3d4 100644 --- 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 diff --git a/ReleaseNotes b/ReleaseNotes index 0f627333..61311716 100644 --- a/ReleaseNotes +++ b/ReleaseNotes @@ -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): ------------------------------- diff --git a/build.properties b/build.properties index feb33a99..e0b2d14e 100644 --- a/build.properties +++ b/build.properties @@ -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 index 00000000..e69de29b diff --git a/src/net/sf/openrocket/document/Simulation.java b/src/net/sf/openrocket/document/Simulation.java index d7afa7c8..db462aad 100644 --- a/src/net/sf/openrocket/document/Simulation.java +++ b/src/net/sf/openrocket/document/Simulation.java @@ -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 index 00000000..39f9d2b2 --- /dev/null +++ b/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java @@ -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 optimizationParameters = new ArrayList(); + private final Map> simulationModifiers = + new HashMap>(); + + + private final OpenRocketDocument document; + + public GeneralOptimizationDialog(OpenRocketDocument document, Window parent) { + this.document = document; + + loadOptimizationParameters(); + loadSimulationModifiers(); + } + + + private void loadOptimizationParameters() { + ServiceLoader 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() { + @Override + public int compare(RocketOptimizationParameter o1, RocketOptimizationParameter o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + } + + + private void loadSimulationModifiers() { + ServiceLoader loader = ServiceLoader.load(SimulationModifierService.class); + + for (SimulationModifierService g : loader) { + for (SimulationModifier m : g.getModifiers(document)) { + Object key = m.getRelatedObject(); + List list = simulationModifiers.get(key); + if (list == null) { + list = new ArrayList(); + simulationModifiers.put(key, list); + } + list.add(m); + } + } + + for (Object key : simulationModifiers.keySet()) { + List list = simulationModifiers.get(key); + Collections.sort(list, new Comparator() { + @Override + public int compare(SimulationModifier o1, SimulationModifier o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + } + + } + +} diff --git a/src/net/sf/openrocket/gui/main/componenttree/ComponentTree.java b/src/net/sf/openrocket/gui/main/componenttree/ComponentTree.java index e680c855..09d229bc 100644 --- a/src/net/sf/openrocket/gui/main/componenttree/ComponentTree.java +++ b/src/net/sf/openrocket/gui/main/componenttree/ComponentTree.java @@ -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); diff --git a/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java b/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java index 75fb2933..a7e8386e 100644 --- a/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java +++ b/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java @@ -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 = "" + comment.replace("\n", "
"); + this.setToolTipText(comment); + } else { + this.setToolTipText(null); + } + + return this; + } } diff --git a/src/net/sf/openrocket/optimization/rocketoptimization/RocketOptimizationFunction.java b/src/net/sf/openrocket/optimization/rocketoptimization/RocketOptimizationFunction.java index 7a8404b1..c975a8a4 100644 --- a/src/net/sf/openrocket/optimization/rocketoptimization/RocketOptimizationFunction.java +++ b/src/net/sf/openrocket/optimization/rocketoptimization/RocketOptimizationFunction.java @@ -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 index 00000000..ecff025b --- /dev/null +++ b/src/net/sf/openrocket/optimization/rocketoptimization/RocketOptimizationParameterService.java @@ -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 + */ +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 getParameters(OpenRocketDocument document); + +} diff --git a/src/net/sf/openrocket/optimization/rocketoptimization/SimulationModifier.java b/src/net/sf/openrocket/optimization/rocketoptimization/SimulationModifier.java index f0e1e7e1..a22507d0 100644 --- a/src/net/sf/openrocket/optimization/rocketoptimization/SimulationModifier.java +++ b/src/net/sf/openrocket/optimization/rocketoptimization/SimulationModifier.java @@ -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 */ -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 null. + */ + 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 index 00000000..43b61966 --- /dev/null +++ b/src/net/sf/openrocket/optimization/rocketoptimization/SimulationModifierService.java @@ -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 + */ +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 getModifiers(OpenRocketDocument document); + + +} diff --git a/src/net/sf/openrocket/rocketcomponent/BodyComponent.java b/src/net/sf/openrocket/rocketcomponent/BodyComponent.java index 8c888320..884893d5 100644 --- a/src/net/sf/openrocket/rocketcomponent/BodyComponent.java +++ b/src/net/sf/openrocket/rocketcomponent/BodyComponent.java @@ -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 type) { - if (InternalComponent.class.isAssignableFrom(type)) - return true; - if (ExternalComponent.class.isAssignableFrom(type) && - !BodyComponent.class.isAssignableFrom(type)) - return true; - return false; - } } diff --git a/src/net/sf/openrocket/rocketcomponent/BodyTube.java b/src/net/sf/openrocket/rocketcomponent/BodyTube.java index b84478e7..086c9efc 100644 --- a/src/net/sf/openrocket/rocketcomponent/BodyTube.java +++ b/src/net/sf/openrocket/rocketcomponent/BodyTube.java @@ -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 type) { + if (InternalComponent.class.isAssignableFrom(type)) + return true; + if (ExternalComponent.class.isAssignableFrom(type) && + !BodyComponent.class.isAssignableFrom(type)) + return true; + return false; + } + //////////////// Motor mount ///////////////// @Override diff --git a/src/net/sf/openrocket/rocketcomponent/RocketComponent.java b/src/net/sf/openrocket/rocketcomponent/RocketComponent.java index 1dd1b324..f6d575e3 100644 --- a/src/net/sf/openrocket/rocketcomponent/RocketComponent.java +++ b/src/net/sf/openrocket/rocketcomponent/RocketComponent.java @@ -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; /** diff --git a/src/net/sf/openrocket/rocketcomponent/Transition.java b/src/net/sf/openrocket/rocketcomponent/Transition.java index af559b5b..53b1a196 100644 --- a/src/net/sf/openrocket/rocketcomponent/Transition.java +++ b/src/net/sf/openrocket/rocketcomponent/Transition.java @@ -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) 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 type) { + if (InternalComponent.class.isAssignableFrom(type)) + return true; + return false; + } + + /** * An enumeration listing the possible shapes of transitions. * * @author Sampo Niskanen */ 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 tangent ogive, which has " + - "a smooth transition to the body tube, values less than 1 produce "+ - "secant ogives.", + "The shape parameter value 1 produces a tangent ogive, which has " + + "a smooth transition to the body tube, values less than 1 produce " + + "secant ogives.", "An ogive transition has a profile that is a segment of a circle. " + - "The shape parameter value 1 produces a tangent ogive, which has " + - "a smooth transition to the body tube at the aft end, values less than 1 " + - "produce secant ogives.") { + "The shape parameter value 1 produces a tangent ogive, which has " + + "a smooth transition to the body tube at the aft end, values less than 1 " + + "produce secant ogives.") { @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×Length and Diameter.", - "An ellipsoidal transition has a profile of a half-ellipse "+ - "with major axes of lengths 2×Length and Diameter. 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×Length and Diameter.", + "An ellipsoidal transition has a profile of a half-ellipse " + + "with major axes of lengths 2×Length and Diameter. 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 "+ - "Radius × (x / Length)" + - "k "+ - "where k is the shape parameter. For k=0.5 this is a "+ - "" + FRAC12 +"-power or parabolic nose cone, for k=0.75 a "+ - "" + FRAC34 +"-power, and for k=1 a conical nose cone.", - "A power series transition has a profile of "+ - "Radius × (x / Length)" + - "k "+ - "where k is the shape parameter. For k=0.5 the transition is "+ - "" + FRAC12 + "-power or parabolic, for k=0.75 a " + - "" + FRAC34 + "-power, and for k=1 conical.",true) { + "A power series nose cone has a profile of " + + "Radius × (x / Length)" + + "k " + + "where k is the shape parameter. For k=0.5 this is a " + + "" + FRAC12 + "-power or parabolic nose cone, for k=0.75 a " + + "" + FRAC34 + "-power, and for k=1 a conical nose cone.", + "A power series transition has a profile of " + + "Radius × (x / Length)" + + "k " + + "where k is the shape parameter. For k=0.5 the transition is " + + "" + FRAC12 + "-power or parabolic, for k=0.75 a " + + "" + FRAC34 + "-power, and for k=1 conical.", 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 full parabola which is tangent to the body " + - "tube, 0.75 produces a 3/4 parabola, 0.5 procudes a " + - "1/2 parabola and 0 produces a conical 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 full parabola which is tangent to the body " + - "tube at the aft end, 0.75 produces a 3/4 parabola, 0.5 procudes a " + - "1/2 parabola and 0 produces a conical 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 full parabola which is tangent to the body " + + "tube, 0.75 produces a 3/4 parabola, 0.5 procudes a " + + "1/2 parabola and 0 produces a conical 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 full parabola which is tangent to the body " + + "tube at the aft end, 0.75 produces a 3/4 parabola, 0.5 procudes a " + + "1/2 parabola and 0 produces a conical 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 LD-Haack or Von Karman nose cone, which minimizes " + - "drag for fixed length and diameter, while a value of 0.333 produces an " + - "LV-Haack nose cone, which minimizes drag for fixed length and volume.", + "0 produces an LD-Haack or Von Karman nose cone, which minimizes " + + "drag for fixed length and diameter, while a value of 0.333 produces an " + + "LV-Haack nose cone, which minimizes drag for fixed length and volume.", "The Haack series nose cones 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 LD-Haack or Von Karman shape, " + - "while a value of 0.333 produces an LV-Haack shape.",true) { + "These transition shapes are their equivalents, but do not necessarily produce " + + "optimal drag for transitions. " + + "The shape parameter 0 produces an LD-Haack or Von Karman shape, " + + "while a value of 0.333 produces an LV-Haack 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()). diff --git a/src/net/sf/openrocket/util/TextUtil.java b/src/net/sf/openrocket/util/TextUtil.java index c6a1bb83..32dffd84 100644 --- a/src/net/sf/openrocket/util/TextUtil.java +++ b/src/net/sf/openrocket/util/TextUtil.java @@ -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", ">"); + return s; + } } diff --git a/web/html/actions/updates.php b/web/html/actions/updates.php index fa109631..ea686483 100644 --- a/web/html/actions/updates.php +++ b/web/html/actions/updates.php @@ -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" . diff --git a/web/html/download.html b/web/html/download.html index 884d32e1..ddb2b5be 100644 --- a/web/html/download.html +++ b/web/html/download.html @@ -45,6 +45,12 @@

Recent news:

+

6.10.2010: Version 1.1.3 is + released!

+

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.

7.9.2010: A bug-fix version 1.1.2 is released!

This release fixes a severe bug in 1.1.1 that prevented adding stages @@ -82,13 +88,13 @@ Support This Project

Stable release

@@ -105,7 +111,7 @@ Windows) by double-clicking the package icon. No installation is required.

From the command line OpenRocket can be started by - java -jar OpenRocket-1.1.2.jar

+ java -jar OpenRocket-1.1.3.jar

diff --git a/web/html/index.html b/web/html/index.html index 9320b006..aa10d745 100644 --- a/web/html/index.html +++ b/web/html/index.html @@ -46,12 +46,12 @@

Introduction

@@ -88,6 +88,12 @@

News

+

6.10.2010: Version 1.1.3 is + released!

+

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.

7.9.2010: A bug-fix version 1.1.2 is released!

This release fixes a severe bug in 1.1.1 that prevented adding stages diff --git a/web/htp/htp.def b/web/htp/htp.def index 17e16680..8fd48dea 100644 --- a/web/htp/htp.def +++ b/web/htp/htp.def @@ -1,5 +1,5 @@ - + diff --git a/web/htp/news.htp b/web/htp/news.htp index da5a7076..03938a0d 100644 --- a/web/htp/news.htp +++ b/web/htp/news.htp @@ -9,6 +9,14 @@ +

6.10.2010: Version 1.1.3 is + released!

+ +

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.

+

7.9.2010: A bug-fix version 1.1.2 is released!

-- 2.30.2