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),
"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

View File

@ -7,14 +7,16 @@ 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.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 RingInstanceable, AxialPositionable {
private static final Translator trans = Application.getTranslator();
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 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.
@ -167,7 +171,6 @@ public class TubeFinSet extends ExternalComponent implements AxialPositionable {
public int getFinCount() {
return fins;
}
@Override
public boolean isAfter(){
@ -195,7 +198,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 +210,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() {
@ -327,9 +325,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 +335,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
}
}

View File

@ -318,13 +318,8 @@ public class ComponentRenderer {
gl.glPushMatrix();
gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
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();
}

View File

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