[resolves #323] Major patch to improve rendering of instanced+rotated components
- introduced interfaces for different types of positionable components: -- AnglePositionable -- AxialPositionable -- RadiusPositionable - RingInstanceable now includes these other interfaces, making explicit the expectations of any implementing subclass. - RingInstanceable now indicates its angles as an array instead of returning angles one-at-a-time -- commit includes updates to match this new API - Added getAssembly() method to RocketComponent, to simplify instancing code
This commit is contained in:
parent
f469ee9586
commit
c36ce2eae4
@ -4,8 +4,12 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.material.Material;
|
||||
import net.sf.openrocket.rocketcomponent.position.AxialPositionable;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.ArrayUtils;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
@ -13,8 +17,9 @@ import net.sf.openrocket.util.MathUtil;
|
||||
import net.sf.openrocket.util.Transformation;
|
||||
|
||||
|
||||
public abstract class FinSet extends ExternalComponent {
|
||||
public abstract class FinSet extends ExternalComponent implements RingInstanceable, AxialPositionable {
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
private static final Logger log = LoggerFactory.getLogger(FinSet.class);
|
||||
|
||||
|
||||
/**
|
||||
@ -77,18 +82,12 @@ public abstract class FinSet extends ExternalComponent {
|
||||
/**
|
||||
* Rotation about the x-axis by 2*PI/fins.
|
||||
*/
|
||||
protected Transformation finRotation = Transformation.rotate_x(2 * Math.PI / fins);
|
||||
protected Transformation finRotation = Transformation.IDENTITY;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
protected double baseRotationValue = 0;
|
||||
|
||||
/**
|
||||
* Cant angle of fins.
|
||||
@ -182,7 +181,7 @@ public abstract class FinSet extends ExternalComponent {
|
||||
* @return The base rotation amount.
|
||||
*/
|
||||
public double getBaseRotation() {
|
||||
return rotation;
|
||||
return getAngularOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -190,20 +189,9 @@ public abstract class FinSet extends ExternalComponent {
|
||||
* @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);
|
||||
setAngularOffset(r);
|
||||
}
|
||||
|
||||
public Transformation getBaseRotationTransformation() {
|
||||
return baseRotation;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public double getCantAngle() {
|
||||
return cantAngle;
|
||||
}
|
||||
@ -431,16 +419,10 @@ public abstract class FinSet extends ExternalComponent {
|
||||
|
||||
double mass = getFinMass();
|
||||
double filletMass = getFilletMass();
|
||||
double filletCenter = length / 2;
|
||||
|
||||
double newCGx = (filletCenter * filletMass + finCGx * mass) / (filletMass + mass);
|
||||
|
||||
// FilletRadius/5 is a good estimate for where the vertical centroid of the fillet
|
||||
// is. Finding the actual position is very involved and won't make a huge difference.
|
||||
double newCGy = (filletRadius / 5 * filletMass + finCGy * mass) / (filletMass + mass);
|
||||
|
||||
if (fins == 1) {
|
||||
return baseRotation.transform(
|
||||
Transformation rotation = Transformation.rotate_x( getAngularOffset());
|
||||
return rotation.transform(
|
||||
new Coordinate(finCGx, finCGy + getBodyRadius(), 0, (filletMass + mass)));
|
||||
} else {
|
||||
return new Coordinate(finCGx, 0, 0, (filletMass + mass));
|
||||
@ -640,32 +622,32 @@ public abstract class FinSet extends ExternalComponent {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the 2d-coordinate bound (x,y) to the collection for both z-components and for
|
||||
* all fin rotations.
|
||||
*/
|
||||
private void addFinBound(Collection<Coordinate> set, double x, double y) {
|
||||
Coordinate c;
|
||||
int i;
|
||||
|
||||
c = new Coordinate(x, y, thickness / 2);
|
||||
c = baseRotation.transform(c);
|
||||
set.add(c);
|
||||
for (i = 1; i < fins; i++) {
|
||||
c = finRotation.transform(c);
|
||||
set.add(c);
|
||||
}
|
||||
|
||||
c = new Coordinate(x, y, -thickness / 2);
|
||||
c = baseRotation.transform(c);
|
||||
set.add(c);
|
||||
for (i = 1; i < fins; i++) {
|
||||
c = finRotation.transform(c);
|
||||
set.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * Adds the 2d-coordinate bound (x,y) to the collection for both z-components and for
|
||||
// * all fin rotations.
|
||||
// */
|
||||
// private void addFinBound(Collection<Coordinate> set, double x, double y) {
|
||||
// Coordinate c;
|
||||
// int i;
|
||||
//
|
||||
// c = new Coordinate(x, y, thickness / 2);
|
||||
// c = baseRotation.transform(c);
|
||||
// set.add(c);
|
||||
// for (i = 1; i < fins; i++) {
|
||||
// c = finRotation.transform(c);
|
||||
// set.add(c);
|
||||
// }
|
||||
//
|
||||
// c = new Coordinate(x, y, -thickness / 2);
|
||||
// c = baseRotation.transform(c);
|
||||
// set.add(c);
|
||||
// for (i = 1; i < fins; i++) {
|
||||
// c = finRotation.transform(c);
|
||||
// set.add(c);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
@Override
|
||||
public void componentChanged(ComponentChangeEvent e) {
|
||||
@ -763,6 +745,89 @@ public abstract class FinSet extends ExternalComponent {
|
||||
return points;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getAngularOffset() {
|
||||
ComponentAssembly stage = this.getAssembly();
|
||||
if( PodSet.class.isAssignableFrom( stage.getClass() )){
|
||||
PodSet assembly= (PodSet)stage;
|
||||
return assembly.getAngularOffset() + baseRotationValue;
|
||||
}else if( ParallelStage.class.isAssignableFrom( stage.getClass())){
|
||||
ParallelStage assembly = (ParallelStage)stage;
|
||||
log.debug("detected p-stage with position: "+assembly.getAngularOffset());
|
||||
return assembly.getAngularOffset() + baseRotationValue;
|
||||
}
|
||||
|
||||
return baseRotationValue;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setAngularOffset(double angle) {
|
||||
angle = MathUtil.reduce180(angle);
|
||||
if (MathUtil.equals(angle, baseRotationValue))
|
||||
return;
|
||||
baseRotationValue = angle;
|
||||
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getInstanceAngleIncrement(){
|
||||
return ( 2*Math.PI / getFinCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public double[] getInstanceAngles(){
|
||||
final double baseAngle = getAngularOffset();
|
||||
final double incrAngle = getInstanceAngleIncrement();
|
||||
|
||||
double[] result = new double[ getFinCount()];
|
||||
for( int i=0; i<getFinCount(); ++i){
|
||||
result[i] = baseAngle + incrAngle*i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getAxialPositionMethod( ){
|
||||
return getRelativePositionMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAxialPositionMethod( Position newMethod ){
|
||||
setRelativePosition( newMethod );
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getRadialOffset() {
|
||||
return getBodyRadius();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAutoRadialOffset() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRadialOffset(double radius) {
|
||||
// no-op. Not allowed for fins
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInstanceCount(int newCount) {
|
||||
setFinCount(newCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInstanceCount() {
|
||||
return getFinCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPatternName() {
|
||||
return (getInstanceCount() + "-ring");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@ -777,8 +842,7 @@ public abstract class FinSet extends ExternalComponent {
|
||||
FinSet src = (FinSet) c;
|
||||
this.fins = src.fins;
|
||||
this.finRotation = src.finRotation;
|
||||
this.rotation = src.rotation;
|
||||
this.baseRotation = src.baseRotation;
|
||||
this.baseRotationValue = src.baseRotationValue;
|
||||
this.cantAngle = src.cantAngle;
|
||||
this.cantRotation = src.cantRotation;
|
||||
this.thickness = src.thickness;
|
||||
|
@ -135,20 +135,32 @@ public class ParallelStage extends AxialStage implements FlightConfigurableCompo
|
||||
|
||||
Coordinate center = Coordinate.ZERO;
|
||||
Coordinate[] toReturn = new Coordinate[this.instanceCount];
|
||||
final double[] angles = getInstanceAngles();
|
||||
for (int instanceNumber = 0; instanceNumber < this.instanceCount; instanceNumber++) {
|
||||
final double curAngle = getInstanceAngle( instanceNumber);
|
||||
final double curY = this.radialPosition_m * Math.cos(curAngle);
|
||||
final double curZ = this.radialPosition_m * Math.sin(curAngle);
|
||||
final double curY = this.radialPosition_m * Math.cos(angles[instanceNumber]);
|
||||
final double curZ = this.radialPosition_m * Math.sin(angles[instanceNumber]);
|
||||
toReturn[instanceNumber] = center.add(0, curY, curZ );
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getInstanceAngleIncrement(){
|
||||
return this.angularSeparation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getInstanceAngle( final int instanceNumber){
|
||||
return this.angularPosition_rad + ( instanceNumber * this.angularSeparation);
|
||||
public double[] getInstanceAngles(){
|
||||
final double baseAngle = getAngularOffset();
|
||||
final double incrAngle = getInstanceAngleIncrement();
|
||||
|
||||
double[] result = new double[ getInstanceCount()];
|
||||
for( int i=0; i<getInstanceCount(); ++i){
|
||||
result[i] = baseAngle + incrAngle*i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,10 +83,10 @@ public class PodSet extends ComponentAssembly implements RingInstanceable {
|
||||
|
||||
Coordinate center = Coordinate.ZERO;
|
||||
Coordinate[] toReturn = new Coordinate[this.instanceCount];
|
||||
final double[] angles = getInstanceAngles();
|
||||
for (int instanceNumber = 0; instanceNumber < this.instanceCount; instanceNumber++) {
|
||||
final double curAngle = getInstanceAngle( instanceNumber);
|
||||
final double curY = this.radialPosition_m * Math.cos(curAngle);
|
||||
final double curZ = this.radialPosition_m * Math.sin(curAngle);
|
||||
final double curY = this.radialPosition_m * Math.cos(angles[instanceNumber]);
|
||||
final double curZ = this.radialPosition_m * Math.sin(angles[instanceNumber]);
|
||||
toReturn[instanceNumber] = center.add(0, curY, curZ );
|
||||
}
|
||||
|
||||
@ -94,8 +94,21 @@ public class PodSet extends ComponentAssembly implements RingInstanceable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getInstanceAngle( final int instanceNumber){
|
||||
return this.angularPosition_rad + ( instanceNumber * this.angularSeparation);
|
||||
public double getInstanceAngleIncrement(){
|
||||
return angularSeparation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double[] getInstanceAngles(){
|
||||
final double baseAngle = getAngularOffset();
|
||||
final double incrAngle = getInstanceAngleIncrement();
|
||||
|
||||
double[] result = new double[ getInstanceCount()];
|
||||
for( int i=0; i<getInstanceCount(); ++i){
|
||||
result[i] = baseAngle + incrAngle*i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,17 +1,25 @@
|
||||
package net.sf.openrocket.rocketcomponent;
|
||||
|
||||
public interface RingInstanceable extends Instanceable {
|
||||
import net.sf.openrocket.rocketcomponent.position.AnglePositionable;
|
||||
import net.sf.openrocket.rocketcomponent.position.RadiusPositionable;
|
||||
|
||||
public interface RingInstanceable extends Instanceable, AnglePositionable, RadiusPositionable {
|
||||
|
||||
@Override
|
||||
public double getAngularOffset();
|
||||
|
||||
public double getInstanceAngle( final int instanceNumber);
|
||||
|
||||
public double getRadialOffset();
|
||||
|
||||
public boolean getAutoRadialOffset();
|
||||
|
||||
@Override
|
||||
public void setAngularOffset(final double angle);
|
||||
|
||||
public double getInstanceAngleIncrement();
|
||||
|
||||
public double[] getInstanceAngles();
|
||||
|
||||
|
||||
@Override
|
||||
public double getRadialOffset();
|
||||
@Override
|
||||
public boolean getAutoRadialOffset();
|
||||
@Override
|
||||
public void setRadialOffset(final double radius);
|
||||
|
||||
}
|
||||
|
@ -72,6 +72,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Position[] getAxialOptions(){
|
||||
return new Position[]{ TOP, MIDDLE, BOTTOM, ABSOLUTE};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return title;
|
||||
@ -1627,6 +1631,25 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
throw new IllegalStateException("getStage() called on hierarchy without an AxialStage.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first component assembly component that this component belongs to.
|
||||
*
|
||||
* @return The Stage component this component belongs to.
|
||||
* @throws IllegalStateException if we cannot find an AxialStage above <code>this</code>
|
||||
*/
|
||||
public final ComponentAssembly getAssembly() {
|
||||
checkState();
|
||||
|
||||
RocketComponent curComponent = this;
|
||||
while ( null != curComponent ) {
|
||||
if( ComponentAssembly.class.isAssignableFrom( curComponent.getClass()))
|
||||
return (ComponentAssembly) curComponent;
|
||||
curComponent = curComponent.parent;
|
||||
}
|
||||
throw new IllegalStateException("getAssembly() called on hierarchy without a ComponentAssembly.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the stage number of the stage this component belongs to. The stages
|
||||
* are numbered from zero upwards.
|
||||
|
@ -0,0 +1,11 @@
|
||||
package net.sf.openrocket.rocketcomponent.position;
|
||||
|
||||
public interface AnglePositionable {
|
||||
|
||||
public double getAngularOffset();
|
||||
|
||||
public void setAngularOffset(final double angle);
|
||||
|
||||
// public Position getAnglePositionMethod( );
|
||||
// public void setAnglePositionMethod( Position newMethod );
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package net.sf.openrocket.rocketcomponent.position;
|
||||
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent.Position;
|
||||
|
||||
public interface AxialPositionable {
|
||||
|
||||
public double getAxialOffset();
|
||||
|
||||
public void setAxialOffset(final double newAxialOffset);
|
||||
|
||||
public Position getAxialPositionMethod( );
|
||||
|
||||
public void setAxialPositionMethod( Position newMethod );
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package net.sf.openrocket.rocketcomponent.position;
|
||||
|
||||
public interface RadiusPositionable {
|
||||
|
||||
public double getRadialOffset();
|
||||
public boolean getAutoRadialOffset();
|
||||
public void setRadialOffset(final double radius);
|
||||
|
||||
}
|
@ -21,7 +21,7 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
|
||||
int finCount = finset.getFinCount();
|
||||
Transformation cantRotation = finset.getCantRotation();
|
||||
Transformation baseRotation = finset.getBaseRotationTransformation(); // rotation about x-axis
|
||||
Transformation baseRotation = Transformation.rotate_x(finset.getAngularOffset()); // rotation about x-axis
|
||||
Transformation finRotation = finset.getFinRotationTransformation();
|
||||
|
||||
Coordinate finSetFront = componentAbsoluteLocation;
|
||||
@ -96,7 +96,7 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
double thickness = finset.getThickness();
|
||||
double height = finset.getSpan();
|
||||
Coordinate compCenter = location;
|
||||
Transformation baseRotation = finset.getBaseRotationTransformation();
|
||||
Transformation baseRotation = Transformation.rotate_x( finset.getAngularOffset());
|
||||
Transformation finRotation = finset.getFinRotationTransformation();
|
||||
|
||||
|
||||
@ -146,7 +146,7 @@ public class FinSetShapes extends RocketComponentShape {
|
||||
double radius = finset.getBodyRadius();
|
||||
double thickness = finset.getThickness();
|
||||
|
||||
Transformation baseRotation = finset.getBaseRotationTransformation();
|
||||
Transformation baseRotation = Transformation.rotate_x( finset.getAngularOffset());
|
||||
Transformation finRotation = finset.getFinRotationTransformation();
|
||||
Transformation cantRotation = finset.getCantRotation();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user