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 3dd43b81b..d29068f6c 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java @@ -294,6 +294,10 @@ class DocumentConfig { Reflection.findMethod(TubeFinSet.class, "setOuterRadius", double.class), "auto", Reflection.findMethod(TubeFinSet.class, "setOuterRadiusAutomatic", boolean.class))); + setters.put("TubeFinSet:instancecount", new IntSetter( + Reflection.findMethod(TubeFinSet.class, "setInstanceCount", int.class))); + setters.put("TubeFinSet:angleoffset", new AnglePositionSetter() ); + setters.put("TubeFinSet:radiusoffset", new RadiusPositionSetter() ); // InternalComponent - nothing diff --git a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java index aa9ad73ab..936a6d584 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java @@ -7,14 +7,17 @@ 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.rocketcomponent.position.AngleMethod; import net.sf.openrocket.rocketcomponent.position.AxialMethod; import net.sf.openrocket.rocketcomponent.position.AxialPositionable; +import net.sf.openrocket.rocketcomponent.position.RadiusMethod; import net.sf.openrocket.startup.Application; +import net.sf.openrocket.util.BoundingBox; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.Transformation; -public class TubeFinSet extends ExternalComponent implements AxialPositionable { +public class TubeFinSet extends ExternalComponent implements AxialPositionable, BoxBounded, RingInstanceable { private static final Translator trans = Application.getTranslator(); private final static double DEFAULT_RADIUS = 0.025; @@ -22,18 +25,20 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable { 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; + private AngleMethod angleMethod = AngleMethod.FIXED; + protected RadiusMethod radiusMethod = RadiusMethod.RELATIVE; /** * Rotation angle of the first fin. Zero corresponds to the positive y-axis. */ - protected double rotation = 0; + private double firstFinOffsetRadians = 0; + + protected int fins = 6; /** * Rotation about the x-axis by angle this.rotation. */ - protected Transformation baseRotation = Transformation.rotate_x(rotation); + protected Transformation baseRotation = Transformation.IDENTITY; // initially, rotate by 0 radians. /** * Rotation about the x-axis by 2*PI/fins. @@ -64,7 +69,7 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable { } /** - * Return the outer radius of the body tube. + * Return the outer radius of the tube-fin * * @return the outside radius of the tube */ @@ -100,7 +105,7 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable { } /** - * Set the outer radius of the body tube. If the radius is less than the wall thickness, + * Set the outer radius of the tube-fin. 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. * @@ -167,7 +172,6 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable { public int getFinCount() { return fins; } - @Override public boolean isAfter(){ @@ -195,7 +199,7 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable { * @return The base rotation amount. */ public double getBaseRotation() { - return rotation; + return getAngleOffset(); } public double getFinRotation() { @@ -207,12 +211,7 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable { * @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); + setAngleOffset(r); } public Transformation getBaseRotationTransformation() { @@ -316,6 +315,14 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable { return bounds; } + @Override + public BoundingBox getInstanceBoundingBox() { + BoundingBox box = new BoundingBox(); + box.update(new Coordinate(0, -outerRadius, -outerRadius)); + box.update(new Coordinate(length, outerRadius, outerRadius)); + return box; + } + /** * 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 @@ -327,9 +334,9 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable { RocketComponent s; s = this.getParent(); + double x = this.getPosition().x; while (s != null) { if (s instanceof SymmetricComponent) { - double x = this.getPosition().x; return ((SymmetricComponent) s).getRadius(x); } s = s.getParent(); @@ -337,4 +344,113 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable { return 0; } + @Override + public int getInstanceCount() { + return getFinCount(); + } + + @Override + public void setInstanceCount(int newCount) { + setFinCount(newCount); + } + + @Override + public String getPatternName() { + return (this.getInstanceCount() + "-tubefin-ring"); + } + + @Override + public double getBoundingRadius() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public void setRadius(RadiusMethod method, double radius) { + // TODO Auto-generated method stub + + } + + @Override + public void setAngleOffset(double angleRadians) { + final double reducedAngle = MathUtil.reducePI(angleRadians); + if (MathUtil.equals(reducedAngle, firstFinOffsetRadians)) + return; + firstFinOffsetRadians = reducedAngle; + + if (MathUtil.equals(this.firstFinOffsetRadians, 0)) { + baseRotation = Transformation.IDENTITY; + } else { + baseRotation = Transformation.rotate_x(firstFinOffsetRadians); + } + + fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); + } + + @Override + public AngleMethod getAngleMethod() { + return this.angleMethod; + } + + @Override + public double getAngleOffset() { + return this.firstFinOffsetRadians; + } + + @Override + public void setAngleMethod(AngleMethod newAngleMethod) { + mutex.verify(); + this.angleMethod = newAngleMethod; + fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); + } + + @Override + public double getInstanceAngleIncrement() { + return ( 2*Math.PI / getFinCount()); + } + + @Override + public double[] getInstanceAngles() { + final double angleIncrementRadians = getInstanceAngleIncrement(); + + double[] result = new double[getFinCount()]; + for (int finNumber=0; finNumber < getFinCount(); ++finNumber) { + double additionalOffset = angleIncrementRadians * finNumber; + result[finNumber] = MathUtil.reduce2PI(firstFinOffsetRadians + additionalOffset); + } + + return result; + } + + @Override + public Coordinate[] getInstanceOffsets() { + checkState(); + + final double bodyRadius = this.getBodyRadius(); + + // already includes the base rotation + final double[] angles = getInstanceAngles(); + + Coordinate[] toReturn = new Coordinate[this.fins]; + for (int instanceNumber = 0; instanceNumber < this.fins; instanceNumber++) { + final Coordinate raw = new Coordinate( 0, bodyRadius, 0); + final Coordinate rotated = Transformation.getAxialRotation(angles[instanceNumber]).transform(raw); + toReturn[instanceNumber] = rotated; + } + + return toReturn; + } + + @Override + public void setRadiusOffset(double radius) { + // TODO Auto-generated method stub + + } + + @Override + public void setRadiusMethod(RadiusMethod method) { + // TODO Auto-generated method stub + + } + } 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 b725988b6..e239701b6 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/geometry/ComponentRenderer.java @@ -317,15 +317,8 @@ public class ComponentRenderer { 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.glTranslated(0, fs.getOuterRadius(), 0); + renderTube(gl, which, fs.getOuterRadius(), fs.getInnerRadius(), fs.getLength()); gl.glPopMatrix(); } diff --git a/swing/src/net/sf/openrocket/gui/rocketfigure/TubeFinSetShapes.java b/swing/src/net/sf/openrocket/gui/rocketfigure/TubeFinSetShapes.java index f3eb9e8d3..60d17b31d 100644 --- a/swing/src/net/sf/openrocket/gui/rocketfigure/TubeFinSetShapes.java +++ b/swing/src/net/sf/openrocket/gui/rocketfigure/TubeFinSetShapes.java @@ -10,72 +10,55 @@ import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Transformation; +/** + * The TubeFinSetShapes is used for retrieving shapes of the TubeFins on a + * Rocket from multiple view points. The returned shapes will be translated + * and transformed to the correct locations for rendering the rocket in the + * 2D view space. + */ public class TubeFinSetShapes extends RocketComponentShape { + /** + * Returns an array of RocketcomponentShapes that describe the shape of + * the TubeFinSet when viewed from the side of the rocket. TubeFins will + * appear as a Rectangle from the side view + * + * @param component the TubeFinSet to get the shapes for + * @param transformation the transformation to apply to the shapes + * @return an array of RocketComponentShapes that are used to draw the TubeFinSet from the side. + */ public static RocketComponentShape[] getShapesSide( final RocketComponent component, final Transformation transformation) { + final TubeFinSet finSet = (TubeFinSet) component; + final double outerRadius = finSet.getOuterRadius(); + final double length = finSet.getLength(); + final Coordinate location = transformation.transform(new Coordinate(0, outerRadius, 0)); - TubeFinSet finset = (net.sf.openrocket.rocketcomponent.TubeFinSet)component; - - int fins = finset.getFinCount(); - double length = finset.getLength(); - double outerRadius = finset.getOuterRadius(); - double bodyRadius = finset.getBodyRadius(); - // old version - Oct, 19 2015 - //Coordinate[] instanceOffsets = new Coordinate[]{ transformation.transform( componentAbsoluteLocation )}; - //instanceOffsets = component.shiftCoordinates(instanceOffsets); + final Shape[] shapes = new Shape[] { + new Rectangle2D.Double(location.x, (location.y-outerRadius), length, 2*outerRadius) + }; - // new version - Coordinate[] start = transformation.transform( component.getLocations()); - - Transformation baseRotation = finset.getBaseRotationTransformation(); - Transformation finRotation = finset.getFinRotationTransformation(); - - // Translate & rotate the coordinates - for (int i=0; i