diff --git a/.idea/misc.xml b/.idea/misc.xml index 6f34b5b648..33b4462877 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -46,7 +46,7 @@ - + \ No newline at end of file diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 90b271386f..7e53c5eeda 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -1482,6 +1482,17 @@ FuelTank.tab.General = Fuel Tank FuelTank.tab.ttip.General = Fuel settings ! Engine Nozzle Nozzle.Nozzle = Engine Nozzle +EngineNozzle.lbl.shape = Nozzle Shape +EngineNozzle.lbl.Clipped = Clipped +EngineNozzle.lbl.Shapeparam = Shape parameter +EngineNozzle.lbl.length = Length +EngineNozzle.lbl.foreDiam = Fore Diameter +EngineNozzle.lbl.aftdiam = Aft Diameter +EngineNozzle.lbl.automatic = Automatic +EngineNozzle.lbl.wallthick = Wall thickness +EngineNozzle.tab.General = General +EngineNozzle.lbl.Generalproperties = General Properties +compaddbuttons.Enginenozzle = Engine Nozzle ! Parachute Parachute.Parachute = Parachute ! ShockCord diff --git a/core/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java b/core/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java index 1bfcfa2ee4..a4eb6058df 100644 --- a/core/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java +++ b/core/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java @@ -7,10 +7,7 @@ import net.sf.openrocket.aerodynamics.FlightConditions; import net.sf.openrocket.aerodynamics.Warning; import net.sf.openrocket.aerodynamics.WarningSet; -import net.sf.openrocket.rocketcomponent.BodyTube; -import net.sf.openrocket.rocketcomponent.RocketComponent; -import net.sf.openrocket.rocketcomponent.SymmetricComponent; -import net.sf.openrocket.rocketcomponent.Transition; +import net.sf.openrocket.rocketcomponent.*; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.LinearInterpolator; @@ -69,7 +66,7 @@ public SymmetricComponentCalc(RocketComponent c) { shape = ((Transition) component).getType(); param = ((Transition) component).getShapeParameter(); frontalArea = Math.abs(Math.PI * (foreRadius * foreRadius - aftRadius * aftRadius)); - + double r = component.getRadius(0.99 * length); sinphi = (aftRadius - r) / MathUtil.hypot(aftRadius - r, 0.01 * length); } else { diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java index 8393737f62..22e4feafcc 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java @@ -41,6 +41,7 @@ class DocumentConfig { constructors.put("tubefinset", TubeFinSet.class.getConstructor(new Class[0])); constructors.put("launchlug", LaunchLug.class.getConstructor(new Class[0])); constructors.put("railbutton", RailButton.class.getConstructor(new Class[0])); + constructors.put("enginenozzle", EngineNozzle.class.getConstructor(new Class[0])); // Internal components constructors.put("engineblock", EngineBlock.class.getConstructor(new Class[0])); @@ -201,6 +202,9 @@ class DocumentConfig { setters.put("NoseCone:foreshoulderlength", null); setters.put("NoseCone:foreshoulderthickness", null); setters.put("NoseCone:foreshouldercapped", null); + + // Engine Nozzle -- pretty much just transition? + // Is anything needed here?? // FinSet setters.put("FinSet:fincount", new IntSetter( diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/EngineNozzleSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/EngineNozzleSaver.java new file mode 100644 index 0000000000..9df4ee7170 --- /dev/null +++ b/core/src/net/sf/openrocket/file/openrocket/savers/EngineNozzleSaver.java @@ -0,0 +1,26 @@ +package net.sf.openrocket.file.openrocket.savers; + +import java.util.ArrayList; +import java.util.List; + +public class EngineNozzleSaver extends TransitionSaver { + + private static final EngineNozzleSaver instance = new EngineNozzleSaver(); + + public ArrayList getElements(net.sf.openrocket.rocketcomponent.EngineNozzle c) { + ArrayList list = new ArrayList(); + + list.add(""); + instance.addParams(c, list); + list.add(""); + + return list; + } + + @Override + protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List elements) { + super.addParams(c, elements); + + } + +} diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/TransitionSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/TransitionSaver.java index 0a4169f9e1..5900901509 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/TransitionSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/TransitionSaver.java @@ -8,7 +8,8 @@ import net.sf.openrocket.rocketcomponent.Transition; -public class TransitionSaver extends SymmetricComponentSaver { +public class +TransitionSaver extends SymmetricComponentSaver { private static final TransitionSaver instance = new TransitionSaver(); diff --git a/core/src/net/sf/openrocket/rocketcomponent/EngineNozzle.java b/core/src/net/sf/openrocket/rocketcomponent/EngineNozzle.java index a518ce6fa5..f16f7b9f8c 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/EngineNozzle.java +++ b/core/src/net/sf/openrocket/rocketcomponent/EngineNozzle.java @@ -11,7 +11,7 @@ import static net.sf.openrocket.util.MathUtil.pow2; import static net.sf.openrocket.util.MathUtil.pow3; -public class EngineNozzle extends SymmetricComponent { +public class EngineNozzle extends Transition { private static Translator trans = Application.getTranslator(); private static final double CLIP_PRECISION = 0.0001; @@ -35,10 +35,10 @@ public EngineNozzle() { this.foreRadius = DEFAULT_RADIUS; this.aftRadius = DEFAULT_RADIUS; this.length = DEFAULT_RADIUS * 3; - this.autoForeRadius = true; + this.autoForeRadius = false; this.autoAftRadius = true; - this.type = Shape.CONICAL; - this.shapeParameter = 0; + this.type = Shape.PARABOLIC; + this.shapeParameter = 1; this.clipped = true; } @@ -272,8 +272,6 @@ public void setForeShoulderCapped(boolean capped) { } - - public double getAftShoulderRadius() { return aftShoulderRadius; } @@ -320,341 +318,6 @@ public void setAftShoulderCapped(boolean capped) { } ///////////////////////// End Getters & Setters - public static enum Shape { - - /** - * Conical shape. - */ - //// Conical - CONICAL(trans.get("Shape.Conical"), - //// A conical nose cone has a profile of a triangle. - trans.get("Shape.Conical.desc1"), - //// A conical transition has straight sides. - trans.get("Shape.Conical.desc2")) { - @Override - public double getRadius(double x, double radius, double length, double param) { - assert x >= 0; - assert x <= length; - assert radius >= 0; - 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 - * for smaller values the shape straightens out into a cone at param==0. - */ - //// Ogive - OGIVE(trans.get("Shape.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. - trans.get("Shape.Ogive.desc1"), - //// 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. - trans.get("Shape.Ogive.desc2")) { - @Override - public boolean usesParameter() { - return true; // Range 0...1 is default - } - - @Override - public double defaultParameter() { - return 1.0; // Tangent ogive by default - } - - @Override - 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 <= 1; - - // Impossible to calculate ogive for length < radius, scale instead - // TODO: LOW: secant ogive could be calculated lower - if (length < radius) { - x = x * radius / length; - length = radius; - } - - if (param < 0.001) - return CONICAL.getRadius(x, radius, length, param); - - // Radius of circle is: - double R = MathUtil.safeSqrt((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 = MathUtil.safeSqrt(R * R - L * L); - return MathUtil.safeSqrt(R * R - (L - x) * (L - x)) - y0; - } - }, - - /** - * Ellipsoidal shape. - */ - //// Ellipsoid - ELLIPSOID(trans.get("Shape.Ellipsoid"), - //// An ellipsoidal nose cone has a profile of a half-ellipse with major axes of lengths 2×Length and Diameter. - trans.get("Shape.Ellipsoid.desc1"), - //// 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. - trans.get("Shape.Ellipsoid.desc2"), 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 MathUtil.safeSqrt(2 * radius * x - x * x); // radius/length * sphere - } - }, - - //// Power series - POWER(trans.get("Shape.Powerseries"), - trans.get("Shape.Powerseries.desc1"), - trans.get("Shape.Powerseries.desc2"), true) { - @Override - 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; - assert x <= length; - assert radius >= 0; - assert param >= 0; - assert param <= 1; - if (param <= 0.00001) { - if (x <= 0.00001) - return 0; - else - return radius; - } - return radius * Math.pow(x / length, param); - } - - }, - - //// Parabolic series - PARABOLIC(trans.get("Shape.Parabolicseries"), - ////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. - trans.get("Shape.Parabolicseries.desc1"), - ////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. - trans.get("Shape.Parabolicseries.desc2")) { - - // In principle a parabolic transition is clippable, but the difference is - // negligible. - - @Override - 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; - assert x <= length; - assert radius >= 0; - assert param >= 0; - assert param <= 1; - - return radius * ((2 * x / length - param * pow2(x / length)) / (2 - param)); - } - }, - - //// Haack series - HAACK(trans.get("Shape.Haackseries"), - //// 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. - trans.get("Shape.Haackseries.desc1"), - //// 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. - trans.get("Shape.Haackseries.desc2"), true) { - - @Override - public boolean usesParameter() { - return true; - } - - @Override - public double maxParameter() { - return 1.0 / 3.0; // Range 0...1/3 - } - - @Override - 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 <= 2; - - double theta = Math.acos(1 - 2 * x / length); - if (MathUtil.equals(param, 0)) { - return radius * MathUtil.safeSqrt((theta - sin(2 * theta) / 2) / Math.PI); - } - return radius * MathUtil.safeSqrt((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); - // } - // } - ; - - // 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); - } - - // Clippable constructor - Shape(String name, String noseconeDesc, String transitionDesc, boolean canClip) { - this.name = name; - this.canClip = canClip; - this.noseconeDesc = noseconeDesc; - this.transitionDesc = transitionDesc; - } - - - /** - * Return the name of the transition shape name. - */ - public String getName() { - return name; - } - - /** - * Get a description of the Transition shape. - */ - public String getTransitionDescription() { - return transitionDesc; - } - - /** - * Get a description of the NoseCone shape. - */ - public String getNoseConeDescription() { - return noseconeDesc; - } - - /** - * Check whether the shape differs in clipped mode. The clipping should be - * enabled by default if possible. - */ - public boolean isClippable() { - return canClip; - } - - /** - * Return whether the shape uses the shape parameter. (Default false.) - */ - public boolean usesParameter() { - return false; - } - - /** - * Return the minimum value of the shape parameter. (Default 0.) - */ - public double minParameter() { - return 0.0; - } - - /** - * Return the maximum value of the shape parameter. (Default 1.) - */ - public double maxParameter() { - return 1.0; - } - - /** - * Return the default value of the shape parameter. (Default 0.) - */ - 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 - * that the fore radius if zero and the aft radius is radius >= 0. - * Boattails are achieved by reversing the component. - * - * @param x Position from the tip of the component. - * @param radius Aft end radius >= 0. - * @param length Length of the transition >= 0. - * @param param Valid shape parameter. - * @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()). - */ - @Override - public String toString() { - return name; - } - - /** - * Lookup the Shape given the localized name. This differs from the standard valueOf as that looks up - * based on the canonical name, not the localized name which is an instance var. - * - * @param localizedName - * @return - */ - public static Shape toShape(String localizedName) { - Shape[] values = Shape.values(); - for (Shape value : values) { - if (value.getName().equals(localizedName)) { - return value; - } - } - return null; - } - } - /** * Numerically solve clipLength from the equation * r1 == type.getRadius(clipLength,r2,clipLength+length) diff --git a/swing/src/net/sf/openrocket/gui/configdialog/EngineNozzleConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/EngineNozzleConfig.java new file mode 100644 index 0000000000..ca793f9c08 --- /dev/null +++ b/swing/src/net/sf/openrocket/gui/configdialog/EngineNozzleConfig.java @@ -0,0 +1,155 @@ +package net.sf.openrocket.gui.configdialog; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.document.OpenRocketDocument; +import net.sf.openrocket.gui.SpinnerEditor; +import net.sf.openrocket.gui.adaptors.BooleanModel; +import net.sf.openrocket.gui.adaptors.DoubleModel; +import net.sf.openrocket.gui.components.BasicSlider; +import net.sf.openrocket.gui.components.DescriptionArea; +import net.sf.openrocket.gui.components.UnitSelector; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.EngineNozzle; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.unit.UnitGroup; + +public class EngineNozzleConfig extends RocketComponentConfig { + + private static final Translator trans = Application.getTranslator(); + private JComboBox typeBox; + private JLabel shapeLabel; + private JSpinner shapeSpinner; + private BasicSlider shapeSlider; + private DescriptionArea description; + private static final String PREDESC = ""; // ??? + + public EngineNozzleConfig(OpenRocketDocument d, RocketComponent c) { + super(d, c); + + final JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", "")); + + panel.add(new JLabel(trans.get("EngineNozzle.lbl.shape"))); + + EngineNozzle.Shape selected = ((EngineNozzle) component).getType(); + EngineNozzle.Shape[] typeList = EngineNozzle.Shape.values(); + + typeBox = new JComboBox(typeList); + typeBox.setEditable(false); + typeBox.setSelectedItem(selected); + typeBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + EngineNozzle.Shape s = (EngineNozzle.Shape) typeBox.getSelectedItem(); + ((EngineNozzle) component).setType(s); + description.setText(PREDESC + s.getTransitionDescription()); + updateEnabled(); + } + }); + panel.add(typeBox, "span, split 2"); + + { + final JCheckBox checkbox = new JCheckBox(new BooleanModel(component, "Clipped")); + checkbox.setText(trans.get("EngineNozzle.lbl.Clipped")); + panel.add(checkbox, "wrap"); + + // shape parameter + this.shapeLabel = new JLabel(trans.get("EngineNozzle.lbl.Shapeparam")); + panel.add(shapeLabel); + //updateEnabled(); + } + + { + final DoubleModel shapeModel = new DoubleModel(component, "ShapeParameter"); + this.shapeSpinner = new JSpinner(shapeModel.getSpinnerModel()); + panel.add(shapeSpinner, "growx"); + DoubleModel min = new DoubleModel(component, "ShapeParameterMin"); + DoubleModel max = new DoubleModel(component, "ShapeParameterMax"); + this.shapeSlider = new BasicSlider(shapeModel.getSliderModel(min, max)); + panel.add(shapeSlider, "skip, w 100lp, wrap"); + updateEnabled(); + } + + { + panel.add(new JLabel(trans.get("EngineNozzle.lbl.length"))); + final DoubleModel lengthModel = new DoubleModel(component, "Length", UnitGroup.UNITS_LENGTH, 0); + final JSpinner lengthSpinner = new JSpinner(lengthModel.getSpinnerModel()); + lengthSpinner.setEditor(new SpinnerEditor(lengthSpinner)); + panel.add(lengthSpinner, "growx"); + panel.add(new UnitSelector(lengthModel), "growx"); + panel.add(new BasicSlider(lengthModel.getSliderModel(0, 0.05, 0.3)), "w 100lp, wrap"); + } + + { + panel.add(new JLabel(trans.get("EngineNozzle.lbl.foreDiam"))); + final DoubleModel foreRadiusModel = new DoubleModel(component, "ForeRadius", 2, UnitGroup.UNITS_LENGTH, 0); + final JSpinner foreRadiusSpinner = new JSpinner(foreRadiusModel.getSpinnerModel()); + foreRadiusSpinner.setEditor(new SpinnerEditor(foreRadiusSpinner)); + panel.add(foreRadiusSpinner, "growx"); + panel.add(new UnitSelector(foreRadiusModel), "growx"); + panel.add(new BasicSlider(foreRadiusModel.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap 0px"); + + final JCheckBox checkbox = new JCheckBox(foreRadiusModel.getAutomaticAction()); + checkbox.setText(trans.get("EngineNozzle.lbl.automatic")); + panel.add(checkbox, "skip, span 2, wrap"); + } + + { + panel.add(new JLabel(trans.get("EngineNozzle.lbl.aftdiam"))); + final DoubleModel aftRadiusModel = new DoubleModel(component, "AftRadius", 2, UnitGroup.UNITS_LENGTH, 0); + final JSpinner aftRadiusSpinner = new JSpinner(aftRadiusModel.getSpinnerModel()); + aftRadiusSpinner.setEditor(new SpinnerEditor(aftRadiusSpinner)); + panel.add(aftRadiusSpinner, "growx"); + panel.add(new UnitSelector(aftRadiusModel), "growx"); + panel.add(new BasicSlider(aftRadiusModel.getSliderModel(0, 0.04, 0.5)), "w 100lp, wrap 0px"); + + final JCheckBox checkbox = new JCheckBox(aftRadiusModel.getAutomaticAction()); + checkbox.setText(trans.get("EngineNozzle.lbl.automatic")); + panel.add(checkbox, "skip, span 2, wrap"); + } + + { + panel.add(new JLabel(trans.get("EngineNozzle.lbl.wallthick"))); + final DoubleModel thickModel = new DoubleModel(component, "Thickness", UnitGroup.UNITS_LENGTH, 0); + final JSpinner thickSpinner = new JSpinner(thickModel.getSpinnerModel()); + thickSpinner.setEditor(new SpinnerEditor(thickSpinner)); + panel.add(thickSpinner, "growx"); + panel.add(new UnitSelector(thickModel), "growx"); + panel.add(new BasicSlider(thickModel.getSliderModel(0, 0.01)), "w 100lp, wrap 0px"); + } + + JPanel panel2 = new JPanel(new MigLayout("ins 0")); + description = new DescriptionArea(5); + description.setText(PREDESC + ((EngineNozzle) component).getType().getTransitionDescription()); + panel2.add(description, "wmin 250lp, spanx, growx, wrap para"); + + panel2.add(materialPanel(Material.Type.BULK), "span, wrap"); + panel.add(panel2, "cell 4 0, gapleft paragraph, aligny 0%, spany"); + + // tabs + tabbedPane.insertTab(trans.get("EngineNozzle.tab.General"), null, panel, + trans.get("EngineNozzle.lbl.Generalproperties"), 0); + tabbedPane.insertTab(trans.get("TransitionCfg.tab.Shoulder"), null, shoulderTab(), + trans.get("TransitionCfg.tab.Shoulderproperties"), 1); + tabbedPane.setSelectedIndex(0); + } + + private void updateEnabled() { + boolean e = ((EngineNozzle) component).getType().usesParameter(); + shapeLabel.setEnabled(e); + shapeSpinner.setEnabled(e); + shapeSlider.setEnabled(e); + } + + +} diff --git a/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java b/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java index a87255c1dc..d5bb56ec3f 100644 --- a/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java +++ b/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java @@ -25,6 +25,7 @@ import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; +import net.sf.openrocket.rocketcomponent.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,31 +36,6 @@ import net.sf.openrocket.gui.main.componenttree.ComponentTreeModel; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.logging.Markers; -import net.sf.openrocket.rocketcomponent.AxialStage; -import net.sf.openrocket.rocketcomponent.BodyComponent; -import net.sf.openrocket.rocketcomponent.BodyTube; -import net.sf.openrocket.rocketcomponent.Bulkhead; -import net.sf.openrocket.rocketcomponent.CenteringRing; -import net.sf.openrocket.rocketcomponent.EllipticalFinSet; -import net.sf.openrocket.rocketcomponent.EngineBlock; -import net.sf.openrocket.rocketcomponent.FreeformFinSet; -import net.sf.openrocket.rocketcomponent.InnerTube; -import net.sf.openrocket.rocketcomponent.LaunchLug; -import net.sf.openrocket.rocketcomponent.MassComponent; -import net.sf.openrocket.rocketcomponent.NoseCone; -import net.sf.openrocket.rocketcomponent.Parachute; -import net.sf.openrocket.rocketcomponent.ParallelStage; -import net.sf.openrocket.rocketcomponent.PodSet; -import net.sf.openrocket.rocketcomponent.RailButton; -import net.sf.openrocket.rocketcomponent.Rocket; -import net.sf.openrocket.rocketcomponent.RocketComponent; -import net.sf.openrocket.rocketcomponent.ShockCord; -import net.sf.openrocket.rocketcomponent.Streamer; -import net.sf.openrocket.rocketcomponent.Transition; -import net.sf.openrocket.rocketcomponent.TrapezoidFinSet; -import net.sf.openrocket.rocketcomponent.TubeCoupler; -import net.sf.openrocket.rocketcomponent.TubeFinSet; -import net.sf.openrocket.rocketcomponent.FuelTank; import net.sf.openrocket.startup.Application; import net.sf.openrocket.startup.Preferences; import net.sf.openrocket.util.BugException; @@ -158,7 +134,9 @@ public ComponentAddButtons(OpenRocketDocument document, TreeSelectionModel model //// Engine\nblock new ComponentButton(EngineBlock.class, trans.get("compaddbuttons.Engineblock")), //// Fuel\ntank - new ComponentButton(FuelTank.class, trans.get("compaddbuttons.Fueltank"))); + new ComponentButton(FuelTank.class, trans.get("compaddbuttons.Fueltank")), + //// Engine\nNozzle + new BodyComponentButton(EngineNozzle.class, trans.get("compaddbuttons.Enginenozzle"))); row++;