package net.sf.openrocket.rocketcomponent;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil;
import java.util.ArrayList;
import java.util.List;
/**
* A set of trapezoidal fins. The root and tip chords are perpendicular to the rocket
* base line, while the leading and aft edges may be slanted.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class TrapezoidFinSet extends FinSet {
private static final Translator trans = Application.getTranslator();
public static final double MAX_SWEEP_ANGLE = (89 * Math.PI / 180.0);
/*
* sweep tipChord
* | |___________
* | / |
* | / |
* | / | height
* / |
* __________/________________|_____________
* length
* == rootChord
*/
// rootChord == length
private double tipChord = 0;
private double height = 0;
private double sweep = 0;
public TrapezoidFinSet() {
this(3, 0.05, 0.05, 0.025, 0.03);
}
// TODO: HIGH: height=0 -> CP = NaN
public TrapezoidFinSet(int fins, double rootChord, double tipChord, double sweep,
double height) {
super();
this.setFinCount(fins);
this.length = rootChord;
this.tipChord = tipChord;
this.sweep = sweep;
this.height = height;
}
public void setFinShape(double rootChord, double tipChord, double sweep, double height,
double thickness) {
if (this.length == rootChord && this.tipChord == tipChord && this.sweep == sweep &&
this.height == height && this.thickness == thickness)
return;
this.length = rootChord;
this.tipChord = tipChord;
this.sweep = sweep;
this.height = height;
this.thickness = thickness;
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
public double getRootChord() {
return length;
}
public void setRootChord(double r) {
if (length == r)
return;
length = Math.max(r, 0);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
public double getTipChord() {
return tipChord;
}
public void setTipChord(double r) {
if (tipChord == r)
return;
tipChord = Math.max(r, 0);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
/**
* Get the sweep length.
*/
public double getSweep() {
return sweep;
}
/**
* Set the sweep length.
*/
public void setSweep(double r) {
if (sweep == r)
return;
sweep = r;
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
/**
* Get the sweep angle. This is calculated from the true sweep and height, and is not
* stored separately.
*/
public double getSweepAngle() {
if (height == 0) {
if (sweep > 0)
return Math.PI / 2;
if (sweep < 0)
return -Math.PI / 2;
return 0;
}
return Math.atan(sweep / height);
}
/**
* Sets the sweep by the sweep angle. The sweep is calculated and set by this method,
* and the angle itself is not stored.
*/
public void setSweepAngle(double r) {
if (r > MAX_SWEEP_ANGLE)
r = MAX_SWEEP_ANGLE;
if (r < -MAX_SWEEP_ANGLE)
r = -MAX_SWEEP_ANGLE;
double mySweep = Math.tan(r) * height;
if (Double.isNaN(mySweep) || Double.isInfinite(mySweep))
return;
setSweep(mySweep);
}
public double getHeight() {
return height;
}
public void setHeight(double r) {
if (height == r)
return;
height = Math.max(r, 0);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
/**
* Returns the geometry of a trapezoidal fin.
*/
@Override
public Coordinate[] getFinPoints() {
List<Coordinate> list = new ArrayList<Coordinate>(4);
list.add(Coordinate.NUL);
list.add(new Coordinate(sweep, height));
if (tipChord > 0.0001) {
list.add(new Coordinate(sweep + tipChord, height));
}
list.add(new Coordinate(MathUtil.max(length, 0.0001), 0));
return list.toArray(new Coordinate[list.size()]);
}
/**
* Returns the span of a trapezoidal fin.
*/
@Override
public double getSpan() {
return height;
}
@Override
public String getComponentName() {
//// Trapezoidal fin set
return trans.get("TrapezoidFinSet.TrapezoidFinSet");
}
}