From 4e766c73d14263580424a4365f7d04055b024cb2 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Wed, 5 Nov 2014 19:26:48 -0600 Subject: [PATCH] Tube fin component, configuration, viewing, file io. --- core/resources/l10n/messages.properties | 4 + .../pix/componenticons/tubefin-large.png | Bin 0 -> 1523 bytes .../pix/componenticons/tubefin-small.png | Bin 0 -> 553 bytes .../barrowman/TubeFinSetCalc.java | 27 ++ .../defaults/DefaultAppearance.java | 3 +- .../file/openrocket/OpenRocketSaver.java | 16 + .../openrocket/importt/DocumentConfig.java | 18 +- .../openrocket/importt/PositionSetter.java | 4 + .../openrocket/savers/TubeFinSetSaver.java | 38 +++ .../rocketcomponent/TubeFinSet.java | 316 ++++++++++++++++++ .../sf/openrocket/startup/Preferences.java | 2 + .../gui/configdialog/TubeFinSetConfig.java | 166 +++++++++ .../figure3d/geometry/ComponentRenderer.java | 124 ++++--- .../gui/main/ComponentAddButtons.java | 9 +- .../openrocket/gui/main/ComponentIcons.java | 3 + .../gui/rocketfigure/TubeFinSetShapes.java | 70 ++++ 16 files changed, 742 insertions(+), 58 deletions(-) create mode 100644 core/resources/pix/componenticons/tubefin-large.png create mode 100644 core/resources/pix/componenticons/tubefin-small.png create mode 100644 core/src/net/sf/openrocket/aerodynamics/barrowman/TubeFinSetCalc.java create mode 100644 core/src/net/sf/openrocket/file/openrocket/savers/TubeFinSetSaver.java create mode 100644 core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java create mode 100644 swing/src/net/sf/openrocket/gui/configdialog/TubeFinSetConfig.java create mode 100644 swing/src/net/sf/openrocket/gui/rocketfigure/TubeFinSetShapes.java diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 6f4be16fb..671b4d472 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -617,6 +617,7 @@ compaddbuttons.Transition = Transition compaddbuttons.Trapezoidal = Trapezoidal compaddbuttons.Elliptical = Elliptical compaddbuttons.Freeform = Freeform +compaddbuttons.Tubefin = Tube fins compaddbuttons.Launchlug = Launch lug compaddbuttons.Innercomponent = Inner component compaddbuttons.Innertube = Inner tube @@ -1326,6 +1327,8 @@ InnerTube.InnerTube = Inner Tube TrapezoidFinSet.TrapezoidFinSet = Trapezoidal fin set ! FreeformFinSet FreeformFinSet.FreeformFinSet = Freeform fin set +! TubeFinSEt +TubeFinSet.TubeFinSet = Tube fin set !MassComponent MassComponent.MassComponent = Mass component ! Parachute @@ -1369,6 +1372,7 @@ ComponentIcons.Transition = Transition ComponentIcons.Trapezoidalfinset = Trapezoidal fin set ComponentIcons.Ellipticalfinset = Elliptical fin set ComponentIcons.Freeformfinset = Freeform fin set +ComponentIcons.Tubefinset = Tube fin set ComponentIcons.Launchlug = Launch lug ComponentIcons.Innertube = Inner tube ComponentIcons.Tubecoupler = Tube coupler diff --git a/core/resources/pix/componenticons/tubefin-large.png b/core/resources/pix/componenticons/tubefin-large.png new file mode 100644 index 0000000000000000000000000000000000000000..f16027fb605b380c0304309977946b860ede233c GIT binary patch literal 1523 zcmVWFU8GbZ8()Nlj2>E@cM*00mb`L_t(&-tC!9Z`4*4 zhM)W4@dOCXAdyf?q(*|$sz3uPx`Ik{iTDTX*|nAEZ)p2V%ATrO@HbEq5fy1NB~m9K zl5sq-eednUAF*dVlgT82gvQFmNt|)cbMHCtdyXTvI{!I7fG6k7} zOhKj~Q;;dh6l4nWp$>fCwUYqeTLdl5kp5JfR@9Ak{Z7*kt&hu)E4%4CeeYc%L~yTox!7={2O zNiq@0?(QxQM;yn*afA@rikDVBPqk6%r^kh`)?%&27{k>oU$e5Z!p(1Q(r&kzoBIUk zEKw9Agu^*el!g;7tCg%iTwXQ~Ctzb^11S~OTB0bbNU@;mFS)YS)s5(Xh&@bR^Q|_< zkR%De{Q4VOYo0!R%C&3PSX^8j-w-nqh@yyp*4DW5{T)6%cMjk8X*3%6zK`d5c%FyS z8kMP7{;Gp2K%8@gVMwpnqqnz5FYFP9AyKrK0$7VR24gHqk`RWwbhcizzP^s{``{eb zIb62v&e>FoohyleqpZxn?{lWr!uK0!&!gdac#Q@#%_d7rOU%s7ptVjVSt)cT%}S{O zm?E{}IHuih^ZfZLYinz)Z*0(Rx9M~`M{fp8pR7$6qS0s!-Kii5xO(*pKRQQ7R_h|o>)M)uV$Uxqtq%lgYwMZ$8f|r#dcZH;&l;X^p z7GW5&yStl7;sK`V9F9!sigSLw>Px3jp9Y}Q*%~moW^;!5`31JOcSz!xI7vv7q~tAj zz~gj(ieep3BG9G5SDQKX`j5}VaT*(7s_N{vti;&3+i4u`b{f#A)X*C?5)MFHdTGeyJ5KGt|8 zBm_|u@pk(yO}|;dT)6NVy|7n1uhg|Ex~?V3{lXYS6h%aFLK4RWdqD59Ju7l!X}{C&cV?IU$JsthkRh50@}#<`})x#6f_kMg|sIN|i9H+WY&G3g@d_wh%j{~tNT Z@ju3OdZKdv>#qO+002ovPDHLkV1ft0!Ycp( literal 0 HcmV?d00001 diff --git a/core/resources/pix/componenticons/tubefin-small.png b/core/resources/pix/componenticons/tubefin-small.png new file mode 100644 index 0000000000000000000000000000000000000000..e1aa89e524cd121cb968833053f15a4f4e92308b GIT binary patch literal 553 zcmV+^0@nSBP)JWK!p03B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00E6jL_t(I%axQp&f+i- zh9BFJcDFzjG!!%_2S7A56i5`@gc|@SpyLE^6dD@R&;TtoAX+47vY%qd_7-fiA1i*s zNUvOs|o~{r_+hqY(|nKdDYLn&pNf%(&=>QcDpF02!emOpa?XM zV+Ml(qtS@*c+6xn!CL!vQc5YJC}OwU5r$!2;6sledAe9E7!HTDS}p4JI$;>zRsSkV zr4q~Kl3J~H=XdZ5>YT$`%jI&R(P&_dpBqmAQtIv[0])); constructors.put("ellipticalfinset", EllipticalFinSet.class.getConstructor(new Class[0])); constructors.put("freeformfinset", FreeformFinSet.class.getConstructor(new Class[0])); + constructors.put("tubefinset", TubeFinSet.class.getConstructor(new Class[0])); constructors.put("launchlug", LaunchLug.class.getConstructor(new Class[0])); // Internal components @@ -226,6 +228,20 @@ class DocumentConfig { // FreeformFinSet points handled as a special handler + // TubeFinSet + setters.put("TubeFinSet:fincount", new IntSetter( + Reflection.findMethod(TubeFinSet.class, "setFinCount", int.class))); + setters.put("TubeFinSet:rotation", new DoubleSetter( + Reflection.findMethod(TubeFinSet.class, "setBaseRotation", double.class), Math.PI / 180.0)); + setters.put("TubeFinSet:thickness", new DoubleSetter( + Reflection.findMethod(TubeFinSet.class, "setThickness", double.class))); + setters.put("TubeFinSet:length", new DoubleSetter( + Reflection.findMethod(TubeFinSet.class, "setLength", double.class))); + setters.put("TubeFinSet:radius", new DoubleSetter( + Reflection.findMethod(TubeFinSet.class, "setOuterRadius", double.class), + "auto", + Reflection.findMethod(TubeFinSet.class, "setOuterRadiusAutomatic", boolean.class))); + // LaunchLug setters.put("LaunchLug:radius", new DoubleSetter( Reflection.findMethod(LaunchLug.class, "setOuterRadius", double.class))); diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/PositionSetter.java b/core/src/net/sf/openrocket/file/openrocket/importt/PositionSetter.java index fc7d00779..ad29d1e35 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/PositionSetter.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/PositionSetter.java @@ -9,6 +9,7 @@ import net.sf.openrocket.rocketcomponent.InternalComponent; import net.sf.openrocket.rocketcomponent.LaunchLug; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.RocketComponent.Position; +import net.sf.openrocket.rocketcomponent.TubeFinSet; class PositionSetter implements Setter { @@ -40,6 +41,9 @@ class PositionSetter implements Setter { } else if (c instanceof InternalComponent) { ((InternalComponent) c).setRelativePosition(type); c.setPositionValue(pos); + } else if (c instanceof TubeFinSet) { + ((TubeFinSet) c).setRelativePosition(type); + c.setPositionValue(pos); } else { warnings.add(Warning.FILE_INVALID_PARAMETER); } diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/TubeFinSetSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/TubeFinSetSaver.java new file mode 100644 index 000000000..af2ec3b2c --- /dev/null +++ b/core/src/net/sf/openrocket/file/openrocket/savers/TubeFinSetSaver.java @@ -0,0 +1,38 @@ +package net.sf.openrocket.file.openrocket.savers; + +import java.util.ArrayList; +import java.util.List; + +import net.sf.openrocket.rocketcomponent.TubeFinSet; + + +public class TubeFinSetSaver extends ExternalComponentSaver { + + private static final TubeFinSetSaver instance = new TubeFinSetSaver(); + + public static List getElements(net.sf.openrocket.rocketcomponent.RocketComponent c) { + List 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); + TubeFinSet fins = (TubeFinSet) c; + + elements.add("" + fins.getFinCount() + ""); + elements.add("" + (fins.getBaseRotation() * 180.0 / Math.PI) + ""); + if (fins.isOuterRadiusAutomatic()) + elements.add("auto"); + else + elements.add("" + fins.getOuterRadius() + ""); + elements.add("" + fins.getLength() + ""); + elements.add("" + fins.getThickness() + ""); + } + +} diff --git a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java new file mode 100644 index 000000000..84e1c2cd2 --- /dev/null +++ b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java @@ -0,0 +1,316 @@ +package net.sf.openrocket.rocketcomponent; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.preset.ComponentPreset; +import net.sf.openrocket.preset.ComponentPreset.Type; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.util.Coordinate; +import net.sf.openrocket.util.MathUtil; +import net.sf.openrocket.util.Transformation; + +public class TubeFinSet extends ExternalComponent { + private static final Translator trans = Application.getTranslator(); + + private final static double DEFAULT_RADIUS = 0.025; + + private boolean autoRadius = true; // Radius chosen automatically based on parent component + private double outerRadius = DEFAULT_RADIUS; + protected double thickness = 0.002; + + protected int fins = 6; + + /** + * Rotation angle of the first fin. Zero corresponds to the positive y-axis. + */ + protected double rotation = 0; + + /** + * Rotation about the x-axis by angle this.rotation. + */ + protected Transformation baseRotation = Transformation.rotate_x(rotation); + + /** + * Rotation about the x-axis by 2*PI/fins. + */ + protected Transformation finRotation = Transformation.rotate_x(2 * Math.PI / fins); + + + /** + * New FinSet with given number of fins and given base rotation angle. + * Sets the component relative position to POSITION_RELATIVE_BOTTOM, + * i.e. fins are positioned at the bottom of the parent component. + */ + public TubeFinSet() { + super(RocketComponent.Position.BOTTOM); + length = 0.10; + } + + public void setLength(double length) { + if (MathUtil.equals(this.length, length)) + return; + this.length = length; + fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); + } + + + public boolean isOuterRadiusAutomatic() { + return autoRadius; + } + + /** + * Return the outer radius of the body tube. + * + * @return the outside radius of the tube + */ + public double getOuterRadius() { + if (autoRadius) { + // Return auto radius from front or rear + double r = -1; + RocketComponent c = this.getParent(); + if (c != null) { + if (c instanceof SymmetricComponent) { + r = ((SymmetricComponent) c).getAftRadius(); + } + } + if (r < 0) + r = DEFAULT_RADIUS; + return r; + } + return outerRadius; + } + + /** + * Set the outer radius of the body tube. If the radius is less than the wall thickness, + * the wall thickness is decreased accordingly of the value of the radius. + * This method sets the automatic radius off. + * + * @param radius the outside radius in standard units + */ + public void setOuterRadius(double radius) { + if ((this.outerRadius == radius) && (autoRadius == false)) + return; + + this.autoRadius = false; + this.outerRadius = Math.max(radius, 0); + + if (this.thickness > this.outerRadius) + this.thickness = this.outerRadius; + fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); + clearPreset(); + } + + /** + * Sets whether the radius is selected automatically or not. + */ + public void setOuterRadiusAutomatic(boolean auto) { + if (autoRadius == auto) + return; + + autoRadius = auto; + fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); + clearPreset(); + } + + public double getInnerRadius() { + return Math.max(getOuterRadius() - thickness, 0); + } + + public void setInnerRadius(double r) { + setThickness(getOuterRadius() - r); + } + + /** + * Return the component wall thickness. + */ + public double getThickness() { + return Math.min(thickness, getOuterRadius()); + } + + + /** + * Set the component wall thickness. Values greater than the maximum radius are not + * allowed, and will result in setting the thickness to the maximum radius. + */ + public void setThickness(double thickness) { + if ((this.thickness == thickness)) + return; + this.thickness = MathUtil.clamp(thickness, 0, getOuterRadius()); + fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); + clearPreset(); + } + + + /** + * Return the number of fins in the set. + * @return The number of fins. + */ + public int getFinCount() { + return fins; + } + + /** + * Sets the number of fins in the set. + * @param n The number of fins, greater of equal to one. + */ + public void setFinCount(int n) { + if (fins == n) + return; + if (n < 1) + n = 1; + if (n > 8) + n = 8; + fins = n; + finRotation = Transformation.rotate_x(2 * Math.PI / fins); + fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); + } + + /** + * Gets the base rotation amount of the first fin. + * @return The base rotation amount. + */ + public double getBaseRotation() { + return rotation; + } + + public double getFinRotation() { + return 2 * Math.PI / fins; + } + + /** + * Sets the base rotation amount of the first fin. + * @param r The base rotation amount. + */ + public void setBaseRotation(double r) { + r = MathUtil.reduce180(r); + if (MathUtil.equals(r, rotation)) + return; + rotation = r; + baseRotation = Transformation.rotate_x(rotation); + fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); + } + + public Transformation getBaseRotationTransformation() { + return baseRotation; + } + + public Transformation getFinRotationTransformation() { + return finRotation; + } + + @Override + public void setRelativePosition(RocketComponent.Position position) { + super.setRelativePosition(position); + fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); + } + + + @Override + public void setPositionValue(double value) { + super.setPositionValue(value); + fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); + } + + @Override + public double getComponentVolume() { + double or = getOuterRadius(); + double ir = getInnerRadius(); + double volume = or * or - ir * ir; + volume *= Math.PI; + volume *= length; + volume *= fins; + return volume; + } + + @Override + public String getComponentName() { + //// Tube Fin Set + return trans.get("TubeFinSet.TubeFinSet"); + } + + @Override + public Coordinate getComponentCG() { + double mass = getComponentMass(); // safe + double halflength = length / 2; + + if (fins == 1) { + return baseRotation.transform( + new Coordinate(halflength, getOuterRadius() + getBodyRadius(), 0, mass)); + } else { + return new Coordinate(halflength, 0, 0, mass); + } + + } + + @Override + public double getLongitudinalUnitInertia() { + // FIXME - this is very likely completely wrong + // 1/12 * (3 * (r1^2 + r2^2) + h^2) + return (3 * (MathUtil.pow2(getInnerRadius())) + MathUtil.pow2(getOuterRadius()) + MathUtil.pow2(getLength())) / 12; + } + + @Override + public double getRotationalUnitInertia() { + // The rotational inertia of a single fin about its center. + // 1/2 * (r1^2 + r2^2) + double icentermass = (MathUtil.pow2(getInnerRadius()) + MathUtil.pow2(getOuterRadius())) / 2; + if (fins == 1) { + return icentermass; + } else { + // Use parallel axis rule and multiply by number of fins. + return fins * (icentermass + MathUtil.pow2(getOuterRadius()) + getBodyRadius()); + } + } + + @Override + public boolean allowsChildren() { + return false; + } + + @Override + public Type getPresetType() { + return ComponentPreset.Type.BODY_TUBE; + } + + @Override + public boolean isCompatible(Class type) { + // TODO Auto-generated method stub + return false; + } + + @Override + public Collection getComponentBounds() { + List bounds = new ArrayList(); + double r = getBodyRadius(); + + addBound(bounds, 0, 2 * (r + outerRadius)); + addBound(bounds, length, 2 * (r + outerRadius)); + + return bounds; + } + + /** + * Return the radius of the BodyComponent the fin set is situated on. Currently + * only supports SymmetricComponents and returns the radius at the starting point of the + * root chord. + * + * @return radius of the underlying BodyComponent or 0 if none exists. + */ + public double getBodyRadius() { + RocketComponent s; + + s = this.getParent(); + while (s != null) { + if (s instanceof SymmetricComponent) { + double x = this.toRelative(new Coordinate(0, 0, 0), s)[0].x; + return ((SymmetricComponent) s).getRadius(x); + } + s = s.getParent(); + } + return 0; + } + +} diff --git a/core/src/net/sf/openrocket/startup/Preferences.java b/core/src/net/sf/openrocket/startup/Preferences.java index 07e9d36c5..ba674f0ca 100644 --- a/core/src/net/sf/openrocket/startup/Preferences.java +++ b/core/src/net/sf/openrocket/startup/Preferences.java @@ -14,6 +14,7 @@ import net.sf.openrocket.rocketcomponent.LaunchLug; import net.sf.openrocket.rocketcomponent.MassObject; import net.sf.openrocket.rocketcomponent.RecoveryDevice; import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.TubeFinSet; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.BuildProperties; import net.sf.openrocket.util.Color; @@ -414,6 +415,7 @@ public abstract class Preferences { private static final HashMap, String> DEFAULT_COLORS = new HashMap, String>(); static { DEFAULT_COLORS.put(BodyComponent.class, "0,0,240"); + DEFAULT_COLORS.put(TubeFinSet.class, "0,0,200"); DEFAULT_COLORS.put(FinSet.class, "0,0,200"); DEFAULT_COLORS.put(LaunchLug.class, "0,0,180"); DEFAULT_COLORS.put(InternalComponent.class, "170,0,100"); diff --git a/swing/src/net/sf/openrocket/gui/configdialog/TubeFinSetConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/TubeFinSetConfig.java new file mode 100644 index 000000000..46752ce1d --- /dev/null +++ b/swing/src/net/sf/openrocket/gui/configdialog/TubeFinSetConfig.java @@ -0,0 +1,166 @@ +package net.sf.openrocket.gui.configdialog; + + +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.DoubleModel; +import net.sf.openrocket.gui.adaptors.EnumModel; +import net.sf.openrocket.gui.adaptors.IntegerModel; +import net.sf.openrocket.gui.components.BasicSlider; +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.startup.Application; +import net.sf.openrocket.unit.UnitGroup; + +public class TubeFinSetConfig extends RocketComponentConfig { + + private MotorConfig motorConfigPane = null; + private static final Translator trans = Application.getTranslator(); + + public TubeFinSetConfig(OpenRocketDocument d, RocketComponent c) { + super(d, c); + + JPanel primary = new JPanel(new MigLayout("fill")); + + + JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::][]", "")); + + //// Number of fins + panel.add(new JLabel(trans.get("EllipticalFinSetCfg.Nbroffins"))); + + IntegerModel im = new IntegerModel(component, "FinCount", 1, 8); + + JSpinner spin = new JSpinner(im.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + panel.add(spin, "growx, wrap"); + + //// Length: + panel.add(new JLabel(trans.get("LaunchLugCfg.lbl.Length"))); + + DoubleModel m = new DoubleModel(component, "Length", UnitGroup.UNITS_LENGTH, 0); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + panel.add(spin, "growx"); + + panel.add(new UnitSelector(m), "growx"); + panel.add(new BasicSlider(m.getSliderModel(0, 0.02, 0.1)), "w 100lp, wrap para"); + + + //// Outer diameter: + panel.add(new JLabel(trans.get("LaunchLugCfg.lbl.Outerdiam"))); + + DoubleModel od = new DoubleModel(component, "OuterRadius", 2, UnitGroup.UNITS_LENGTH, 0); + // Diameter = 2*Radius + + spin = new JSpinner(od.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + panel.add(spin, "growx"); + + panel.add(new UnitSelector(od), "growx"); + panel.add(new BasicSlider(od.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap rel"); + + + //// Inner diameter: + panel.add(new JLabel(trans.get("LaunchLugCfg.lbl.Innerdiam"))); + + // Diameter = 2*Radius + m = new DoubleModel(component, "InnerRadius", 2, UnitGroup.UNITS_LENGTH, 0); + + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + panel.add(spin, "growx"); + + panel.add(new UnitSelector(m), "growx"); + panel.add(new BasicSlider(m.getSliderModel(new DoubleModel(0), od)), "w 100lp, wrap rel"); + + + //// Wall thickness + //// Thickness: + panel.add(new JLabel(trans.get("LaunchLugCfg.lbl.Thickness"))); + + m = new DoubleModel(component, "Thickness", UnitGroup.UNITS_LENGTH, 0); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + panel.add(spin, "growx"); + + panel.add(new UnitSelector(m), "growx"); + panel.add(new BasicSlider(m.getSliderModel(0, 0.01)), "w 100lp, wrap 20lp"); + + + //// Base rotation + //// Fin rotation: + JLabel label = new JLabel(trans.get("TrapezoidFinSetCfg.lbl.Finrotation")); + //// The angle of the first fin in the fin set. + label.setToolTipText(trans.get("TrapezoidFinSetCfg.lbl.ttip.Finrotation")); + panel.add(label); + + m = new DoubleModel(component, "BaseRotation", UnitGroup.UNITS_ANGLE); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + panel.add(spin, "growx"); + + panel.add(new UnitSelector(m), "growx"); + panel.add(new BasicSlider(m.getSliderModel(-Math.PI, Math.PI)), "w 100lp, wrap"); + + primary.add(panel, "grow, gapright 20lp"); + panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::][]", "")); + + //// Position relative to: + panel.add(new JLabel(trans.get("LaunchLugCfg.lbl.Posrelativeto"))); + + JComboBox combo = new JComboBox( + new EnumModel(component, "RelativePosition", + new RocketComponent.Position[] { + RocketComponent.Position.TOP, + RocketComponent.Position.MIDDLE, + RocketComponent.Position.BOTTOM, + RocketComponent.Position.ABSOLUTE + })); + panel.add(combo, "spanx, growx, wrap"); + + //// plus + panel.add(new JLabel(trans.get("LaunchLugCfg.lbl.plus")), "right"); + + m = new DoubleModel(component, "PositionValue", UnitGroup.UNITS_LENGTH); + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + panel.add(spin, "growx"); + + panel.add(new UnitSelector(m), "growx"); + panel.add(new BasicSlider(m.getSliderModel( + new DoubleModel(component.getParent(), "Length", -1.0, UnitGroup.UNITS_NONE), + new DoubleModel(component.getParent(), "Length"))), + "w 100lp, wrap para"); + + + + //// Material + materialPanel(panel, Material.Type.BULK); + + + primary.add(panel, "grow"); + + //// General and General properties + tabbedPane.insertTab(trans.get("LaunchLugCfg.tab.General"), null, primary, + trans.get("LaunchLugCfg.tab.Generalprop"), 0); + tabbedPane.setSelectedIndex(0); + } + + @Override + public void updateFields() { + super.updateFields(); + } + +} diff --git a/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java b/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java index 8b244babf..055cfc7a3 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java @@ -17,6 +17,7 @@ import net.sf.openrocket.rocketcomponent.RingComponent; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.Transition; import net.sf.openrocket.rocketcomponent.Transition.Shape; +import net.sf.openrocket.rocketcomponent.TubeFinSet; import net.sf.openrocket.util.Coordinate; import org.slf4j.Logger; @@ -28,28 +29,28 @@ import org.slf4j.LoggerFactory; public class ComponentRenderer { @SuppressWarnings("unused") private static final Logger log = LoggerFactory.getLogger(ComponentRenderer.class); - + private int LOD = 80; - + GLU glu; GLUquadric q; FinRenderer fr = new FinRenderer(); - + public ComponentRenderer() { - + } - + public void init(GLAutoDrawable drawable) { glu = new GLU(); q = glu.gluNewQuadric(); glu.gluQuadricTexture(q, true); } - - + + public void updateFigure(GLAutoDrawable drawable) { - + } - + public Geometry getGeometry(final RocketComponent c, final Surface which) { return new Geometry() { @Override @@ -64,7 +65,7 @@ public class ComponentRenderer { } }; } - + public Geometry getGeometry(final Motor motor, Surface which) { return new Geometry() { @Override @@ -73,20 +74,20 @@ public class ComponentRenderer { } }; } - + protected void renderGeometry(GL2 gl, RocketComponent c, Surface which) { if (glu == null) throw new IllegalStateException(this + " Not Initialized"); - + glu.gluQuadricNormals(q, GLU.GLU_SMOOTH); - + Coordinate[] oo = c.toAbsolute(new Coordinate(0, 0, 0)); - + for (Coordinate o : oo) { gl.glPushMatrix(); - + gl.glTranslated(o.x, o.y, o.z); - + if (c instanceof BodyTube) { renderTube(gl, (BodyTube) c, which); } else if (c instanceof LaunchLug) { @@ -102,14 +103,16 @@ public class ComponentRenderer { } else if (c instanceof FinSet) { if (which == Surface.OUTSIDE) fr.renderFinSet(gl, (FinSet) c); + } else if (c instanceof TubeFinSet) { + renderTubeFins( gl, (TubeFinSet) c, which); } else { renderOther(gl, c); } gl.glPopMatrix(); } - + } - + private void renderOther(GL2 gl, RocketComponent c) { gl.glBegin(GL.GL_LINES); for (Coordinate cc : c.getComponentBounds()) { @@ -120,9 +123,9 @@ public class ComponentRenderer { } gl.glEnd(); } - + private void renderTransition(GL2 gl, Transition t, Surface which) { - + if (which == Surface.OUTSIDE || which == Surface.INSIDE) { gl.glPushMatrix(); gl.glRotated(90, 0, 1.0, 0); @@ -135,7 +138,7 @@ public class ComponentRenderer { } gl.glPopMatrix(); } - + if (which == Surface.EDGES || which == Surface.INSIDE) { //Render aft edge gl.glPushMatrix(); @@ -148,7 +151,7 @@ public class ComponentRenderer { glu.gluDisk(q, Math.max(0, t.getAftRadius() - t.getThickness()), t.getAftRadius(), LOD, 2); } gl.glPopMatrix(); - + // Render AFT shoulder if (t.getAftShoulderLength() > 0) { gl.glPushMatrix(); @@ -161,7 +164,7 @@ public class ComponentRenderer { gl.glRotated(90, 0, 1.0, 0); glu.gluDisk(q, t.getAftShoulderRadius(), t.getAftRadius(), LOD, 2); gl.glPopMatrix(); - + } else { renderTube(gl, Surface.INSIDE, t.getAftShoulderRadius(), iR, t.getAftShoulderLength()); gl.glPushMatrix(); @@ -171,7 +174,7 @@ public class ComponentRenderer { } gl.glPopMatrix(); } - + //Render Fore edge gl.glPushMatrix(); gl.glRotated(180, 0, 1.0, 0); @@ -183,7 +186,7 @@ public class ComponentRenderer { glu.gluDisk(q, Math.max(0, t.getForeRadius() - t.getThickness()), t.getForeRadius(), LOD, 2); } gl.glPopMatrix(); - + // Render Fore shoulder if (t.getForeShoulderLength() > 0) { gl.glPushMatrix(); @@ -197,7 +200,7 @@ public class ComponentRenderer { gl.glRotated(90, 0, 1.0, 0); glu.gluDisk(q, t.getForeShoulderRadius(), t.getForeRadius(), LOD, 2); gl.glPopMatrix(); - + } else { renderTube(gl, Surface.INSIDE, t.getForeShoulderRadius(), iR, t.getForeShoulderLength()); gl.glPushMatrix(); @@ -207,28 +210,28 @@ public class ComponentRenderer { } gl.glPopMatrix(); } - + } - + } - + private void renderTube(final GL2 gl, final Surface which, final double oR, final double iR, final double len) { gl.glPushMatrix(); //outside gl.glRotated(90, 0, 1.0, 0); if (which == Surface.OUTSIDE) glu.gluCylinder(q, oR, oR, len, LOD, 1); - + //edges gl.glRotated(180, 0, 1.0, 0); if (which == Surface.EDGES) glu.gluDisk(q, iR, oR, LOD, 2); - + gl.glRotated(180, 0, 1.0, 0); gl.glTranslated(0, 0, len); if (which == Surface.EDGES) glu.gluDisk(q, iR, oR, LOD, 2); - + //inside if (which == Surface.INSIDE) { glu.gluQuadricOrientation(q, GLU.GLU_INSIDE); @@ -237,59 +240,74 @@ public class ComponentRenderer { } gl.glPopMatrix(); } - + private void renderTube(GL2 gl, BodyTube t, Surface which) { renderTube(gl, which, t.getOuterRadius(), t.getInnerRadius(), t.getLength()); } - + private void renderRing(GL2 gl, RingComponent r) { - + gl.glRotated(90, 0, 1.0, 0); glu.gluCylinder(q, r.getOuterRadius(), r.getOuterRadius(), r.getLength(), LOD, 1); - + gl.glRotated(180, 0, 1.0, 0); glu.gluDisk(q, r.getInnerRadius(), r.getOuterRadius(), LOD, 2); - + gl.glRotated(180, 0, 1.0, 0); gl.glTranslated(0, 0, r.getLength()); glu.gluDisk(q, r.getInnerRadius(), r.getOuterRadius(), LOD, 2); - + glu.gluQuadricOrientation(q, GLU.GLU_INSIDE); glu.gluCylinder(q, r.getInnerRadius(), r.getInnerRadius(), -r.getLength(), LOD, 1); glu.gluQuadricOrientation(q, GLU.GLU_OUTSIDE); - + } - + private void renderLug(GL2 gl, LaunchLug t, Surface which) { renderTube(gl, which, t.getOuterRadius(), t.getInnerRadius(), t.getLength()); } - + + private void renderTubeFins(GL2 gl, TubeFinSet fs, Surface which) { + gl.glPushMatrix(); + gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + System.out.println(fs.getBaseRotation()); + gl.glRotated(fs.getBaseRotation() * (180.0 / Math.PI), 1, 0, 0); + for( int i = 0; i< fs.getFinCount(); i++ ) { + gl.glPushMatrix(); + gl.glTranslated(0, fs.getOuterRadius() + fs.getBodyRadius(), 0); + renderTube(gl, which, fs.getOuterRadius(), fs.getInnerRadius(), fs.getLength()); + gl.glPopMatrix(); + gl.glRotated(360.0 / fs.getFinCount(), 1, 0, 0); + } + gl.glPopMatrix(); + } + private void renderMassObject(GL2 gl, MassObject o) { gl.glRotated(90, 0, 1.0, 0); - + MassObjectRenderer.drawMassObject(gl, o, LOD / 2, LOD / 2); } - + private void renderMotor(final GL2 gl, Motor motor) { double l = motor.getLength(); double r = motor.getDiameter() / 2; - + gl.glPushMatrix(); - + gl.glRotated(90, 0, 1.0, 0); - + gl.glMatrixMode(GL.GL_TEXTURE); gl.glPushMatrix(); gl.glTranslated(0, .125, 0); gl.glScaled(1, .75, 0); - + glu.gluCylinder(q, r, r, l, LOD, 1); - + gl.glPopMatrix(); gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); - + { final double da = (2.0f * Math.PI) / LOD; final double dt = 1.0 / LOD; @@ -300,14 +318,14 @@ public class ComponentRenderer { gl.glVertex3d(r * Math.cos(da * i), r * Math.sin(da * i), 0); gl.glTexCoord2d(i * dt, 0); gl.glVertex3d(0, 0, 0); - + } gl.glEnd(); } - + gl.glTranslated(0, 0, l); gl.glRotated(180, 0, 1.0, 0); - + { final double da = (2.0f * Math.PI) / LOD; final double dt = 1.0 / LOD; @@ -321,7 +339,7 @@ public class ComponentRenderer { } gl.glEnd(); gl.glBegin(GL.GL_TRIANGLE_STRIP); - + for (int i = 0; i < LOD + 1; i++) { gl.glNormal3d(-Math.cos(da * i), -Math.sin(da * i), -1); gl.glTexCoord2d(i * dt, .9); diff --git a/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java b/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java index 207f397d4..447b7e4c8 100644 --- a/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java +++ b/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java @@ -25,9 +25,6 @@ import javax.swing.event.TreeSelectionListener; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.gui.components.StyledLabel; @@ -54,12 +51,16 @@ 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.startup.Application; import net.sf.openrocket.startup.Preferences; import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.Pair; import net.sf.openrocket.util.Reflection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * A component that contains addition buttons to add different types of rocket components * to a rocket. It enables and disables buttons according to the current selection of a @@ -122,6 +123,8 @@ public class ComponentAddButtons extends JPanel implements Scrollable { new FinButton(EllipticalFinSet.class, trans.get("compaddbuttons.Elliptical")), //// Freeform new FinButton(FreeformFinSet.class, trans.get("compaddbuttons.Freeform")), + //// Freeform + new FinButton(TubeFinSet.class, trans.get("compaddbuttons.Tubefin")), //// Launch lug new FinButton(LaunchLug.class, trans.get("compaddbuttons.Launchlug"))); diff --git a/swing/src/net/sf/openrocket/gui/main/ComponentIcons.java b/swing/src/net/sf/openrocket/gui/main/ComponentIcons.java index e952d59aa..14c9cf9f3 100644 --- a/swing/src/net/sf/openrocket/gui/main/ComponentIcons.java +++ b/swing/src/net/sf/openrocket/gui/main/ComponentIcons.java @@ -26,6 +26,7 @@ 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.startup.Application; @@ -56,6 +57,8 @@ public class ComponentIcons { load("ellipticalfin", trans.get("ComponentIcons.Ellipticalfinset"), EllipticalFinSet.class); //// Freeform fin set load("freeformfin", trans.get("ComponentIcons.Freeformfinset"), FreeformFinSet.class); + //// Tube fin set + load("tubefin", trans.get("ComponentIcons.Tubefinset"), TubeFinSet.class); //// Launch lug load("launchlug", trans.get("ComponentIcons.Launchlug"), LaunchLug.class); //// Inner tube diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/TubeFinSetShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/TubeFinSetShapes.java new file mode 100644 index 000000000..efe413731 --- /dev/null +++ b/swing/src/net/sf/openrocket/gui/rocketfigure/TubeFinSetShapes.java @@ -0,0 +1,70 @@ +package net.sf.openrocket.gui.rocketfigure; + +import net.sf.openrocket.util.Coordinate; +import net.sf.openrocket.util.Transformation; + +import java.awt.Shape; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; + + +public class TubeFinSetShapes extends RocketComponentShapes { + + public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component, + Transformation transformation) { + net.sf.openrocket.rocketcomponent.TubeFinSet finset = (net.sf.openrocket.rocketcomponent.TubeFinSet)component; + + int fins = finset.getFinCount(); + double length = finset.getLength(); + double outerradius = finset.getOuterRadius(); + double bodyradius = finset.getBodyRadius(); + + Coordinate[] start = finset.toAbsolute(new Coordinate(0,0,0)); + + Transformation baseRotation = finset.getBaseRotationTransformation(); + Transformation finRotation = finset.getFinRotationTransformation(); + + // Translate & rotate the coordinates + for (int i=0; i