Make TubeFinSet RingInstanceable

Make the TubeFinSet RingInstanceable. This change updates the rendering
of both the 2D and 3D views to handle the RingInstanceable shapes. This
also updates the DocumentConfig to parse the new XML formats properly.

Signed-off-by: Billy Olsen <billy.olsen@gmail.com>
This commit is contained in:
Billy Olsen 2020-07-19 14:52:25 -07:00
parent 1bb64d45d3
commit 74ec0be340
4 changed files with 137 additions and 38 deletions

View File

@ -294,6 +294,10 @@ class DocumentConfig {
Reflection.findMethod(TubeFinSet.class, "setOuterRadius", double.class), Reflection.findMethod(TubeFinSet.class, "setOuterRadius", double.class),
"auto", "auto",
Reflection.findMethod(TubeFinSet.class, "setOuterRadiusAutomatic", boolean.class))); 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 // InternalComponent - nothing

View File

@ -7,14 +7,16 @@ import java.util.List;
import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.preset.ComponentPreset; import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPreset.Type; 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.AxialMethod;
import net.sf.openrocket.rocketcomponent.position.AxialPositionable; import net.sf.openrocket.rocketcomponent.position.AxialPositionable;
import net.sf.openrocket.rocketcomponent.position.RadiusMethod;
import net.sf.openrocket.startup.Application; import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.Transformation; import net.sf.openrocket.util.Transformation;
public class TubeFinSet extends ExternalComponent implements AxialPositionable { public class TubeFinSet extends ExternalComponent implements RingInstanceable, AxialPositionable {
private static final Translator trans = Application.getTranslator(); private static final Translator trans = Application.getTranslator();
private final static double DEFAULT_RADIUS = 0.025; private final static double DEFAULT_RADIUS = 0.025;
@ -22,18 +24,20 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable {
private boolean autoRadius = true; // Radius chosen automatically based on parent component private boolean autoRadius = true; // Radius chosen automatically based on parent component
private double outerRadius = DEFAULT_RADIUS; private double outerRadius = DEFAULT_RADIUS;
protected double thickness = 0.002; protected double thickness = 0.002;
private AngleMethod angleMethod = AngleMethod.FIXED;
protected int fins = 6; protected RadiusMethod radiusMethod = RadiusMethod.RELATIVE;
/** /**
* Rotation angle of the first fin. Zero corresponds to the positive y-axis. * 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. * 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. * Rotation about the x-axis by 2*PI/fins.
@ -168,7 +172,6 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable {
return fins; return fins;
} }
@Override @Override
public boolean isAfter(){ public boolean isAfter(){
return false; return false;
@ -195,7 +198,7 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable {
* @return The base rotation amount. * @return The base rotation amount.
*/ */
public double getBaseRotation() { public double getBaseRotation() {
return rotation; return getAngleOffset();
} }
public double getFinRotation() { public double getFinRotation() {
@ -207,12 +210,7 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable {
* @param r The base rotation amount. * @param r The base rotation amount.
*/ */
public void setBaseRotation(double r) { public void setBaseRotation(double r) {
r = MathUtil.reduce180(r); setAngleOffset(r);
if (MathUtil.equals(r, rotation))
return;
rotation = r;
baseRotation = Transformation.rotate_x(rotation);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
} }
public Transformation getBaseRotationTransformation() { public Transformation getBaseRotationTransformation() {
@ -327,9 +325,9 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable {
RocketComponent s; RocketComponent s;
s = this.getParent(); s = this.getParent();
double x = this.getPosition().x;
while (s != null) { while (s != null) {
if (s instanceof SymmetricComponent) { if (s instanceof SymmetricComponent) {
double x = this.getPosition().x;
return ((SymmetricComponent) s).getRadius(x); return ((SymmetricComponent) s).getRadius(x);
} }
s = s.getParent(); s = s.getParent();
@ -337,4 +335,113 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable {
return 0; 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
}
} }

View File

@ -318,14 +318,9 @@ public class ComponentRenderer {
gl.glPushMatrix(); gl.glPushMatrix();
gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
gl.glRotated(fs.getBaseRotation() * (180.0 / Math.PI), 1, 0, 0); gl.glRotated(fs.getBaseRotation() * (180.0 / Math.PI), 1, 0, 0);
for( int i = 0; i< fs.getFinCount(); i++ ) { gl.glTranslated(0, fs.getOuterRadius(), 0);
gl.glPushMatrix();
gl.glTranslated(0, fs.getOuterRadius() + fs.getBodyRadius(), 0);
renderTube(gl, which, fs.getOuterRadius(), fs.getInnerRadius(), fs.getLength()); renderTube(gl, which, fs.getOuterRadius(), fs.getInnerRadius(), fs.getLength());
gl.glPopMatrix(); gl.glPopMatrix();
gl.glRotated(360.0 / fs.getFinCount(), 1, 0, 0);
}
gl.glPopMatrix();
} }
private void renderMassObject(GL2 gl, MassObject o) { private void renderMassObject(GL2 gl, MassObject o) {

View File

@ -35,13 +35,10 @@ public class TubeFinSetShapes extends RocketComponentShape {
final double outerRadius = finSet.getOuterRadius(); final double outerRadius = finSet.getOuterRadius();
final double length = finSet.getLength(); final double length = finSet.getLength();
Coordinate[] locations = transformLocations(finSet, transformation); Coordinate[] locations = transformLocations(finSet, transformation);
Transformation finRotation = finSet.getFinRotationTransformation();
Shape[] shapes = new Shape[finSet.getFinCount()]; Shape[] shapes = new Shape[] {
for (int i=0; i < shapes.length; i++) { new Rectangle2D.Double(locations[0].x, (locations[0].y-outerRadius), length, 2*outerRadius)
shapes[i] = new Rectangle2D.Double(locations[0].x, (locations[0].y-outerRadius), length, 2*outerRadius); };
locations = finRotation.transform(locations);
}
return RocketComponentShape.toArray(shapes, component); return RocketComponentShape.toArray(shapes, component);
} }
@ -62,13 +59,10 @@ public class TubeFinSetShapes extends RocketComponentShape {
final double outerRadius = finSet.getOuterRadius(); final double outerRadius = finSet.getOuterRadius();
Coordinate[] locations = transformLocations(finSet, transformation); Coordinate[] locations = transformLocations(finSet, transformation);
Transformation finRotation = finSet.getFinRotationTransformation();
Shape[] shapes = new Shape[finSet.getFinCount()]; Shape[] shapes = new Shape[] {
for (int i=0; i < shapes.length; i++) { new Ellipse2D.Double((locations[0].z - outerRadius), (locations[0].y - outerRadius), (2 * outerRadius), (2 * outerRadius))
shapes[i] = new Ellipse2D.Double((locations[0].z - outerRadius), (locations[0].y - outerRadius), (2 * outerRadius), (2 * outerRadius)); };
locations = finRotation.transform(locations);
}
return RocketComponentShape.toArray(shapes, component); return RocketComponentShape.toArray(shapes, component);
} }
@ -95,13 +89,12 @@ public class TubeFinSetShapes extends RocketComponentShape {
private static Coordinate[] transformLocations(final TubeFinSet finSet, final Transformation transformation) { private static Coordinate[] transformLocations(final TubeFinSet finSet, final Transformation transformation) {
final double outerRadius = finSet.getOuterRadius(); final double outerRadius = finSet.getOuterRadius();
final double bodyRadius = finSet.getBodyRadius(); final double bodyRadius = finSet.getBodyRadius();
Coordinate[] locations = finSet.getComponentLocations(); Coordinate[] locations = finSet.getInstanceLocations();
Transformation baseRotation = finSet.getBaseRotationTransformation();
for (int i=0; i < locations.length; i++) { for (int i=0; i < locations.length; i++) {
Coordinate c = locations[i].add(0, (bodyRadius + outerRadius), 0); Coordinate c = locations[i].setX(0.);
c = transformation.linearTransform(c); c = c.sub(0, (bodyRadius - outerRadius), 0);
c = baseRotation.transform(c); c = transformation.transform(c);
locations[i] = c; locations[i] = c;
} }