public static final double DEFAULT_RADIUS = 0.025;
public static final double DEFAULT_THICKNESS = 0.002;
- private static final int DIVISIONS = 100; // No. of divisions when integrating
+ private static final int DIVISIONS = 100; // No. of divisions when integrating
protected boolean filled = false;
protected double thickness = DEFAULT_THICKNESS;
-
+
// Cached data, default values signify not calculated
private double wetArea = -1;
private double planArea = -1;
private double planCenter = -1;
private double volume = -1;
private double fullVolume = -1;
- private double longitudalInertia = -1;
+ private double longitudinalInertia = -1;
private double rotationalInertia = -1;
private Coordinate cg = null;
-
+
public SymmetricComponent() {
super();
}
-
+
/**
* Return the component radius at position x.
* the component.
*/
public abstract double getRadius(double x);
+
+ @Override
public abstract double getInnerRadius(double x);
-
+
public abstract double getForeRadius();
+
public abstract boolean isForeRadiusAutomatic();
+
public abstract double getAftRadius();
+
public abstract boolean isAftRadiusAutomatic();
// Implement the Radial interface:
+ @Override
public final double getOuterRadius(double x) {
return getRadius(x);
}
}
-
+
/**
* Return the component wall thickness.
*/
public double getThickness() {
if (filled)
- return Math.max(getForeRadius(),getAftRadius());
- return Math.min(thickness,Math.max(getForeRadius(),getAftRadius()));
+ return Math.max(getForeRadius(), getAftRadius());
+ return Math.min(thickness, Math.max(getForeRadius(), getAftRadius()));
}
public void setThickness(double thickness) {
if ((this.thickness == thickness) && !filled)
return;
- this.thickness = MathUtil.clamp(thickness,0,Math.max(getForeRadius(),getAftRadius()));
+ this.thickness = MathUtil.clamp(thickness, 0, Math.max(getForeRadius(), getAftRadius()));
filled = false;
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
}
-
+
/**
* Returns whether the component is set as filled. If it is set filled, then the
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
}
-
+
/**
* Adds component bounds at a number of points between 0...length.
*/
@Override
public Collection<Coordinate> getComponentBounds() {
List<Coordinate> list = new ArrayList<Coordinate>(20);
- for (int n=0; n<=5; n++) {
- double x = n*length/5;
+ for (int n = 0; n <= 5; n++) {
+ double x = n * length / 5;
double r = getRadius(x);
- addBound(list,x,r);
+ addBound(list, x, r);
}
return list;
}
-
+
/**
* Calculate volume of the component by integrating over the length of the component.
* The method caches the result, so subsequent calls are instant. Subclasses may
@Override
- public double getLongitudalUnitInertia() {
- if (longitudalInertia < 0) {
- if (getComponentVolume() > 0.0000001) // == 0.1cm^3
+ public double getLongitudinalUnitInertia() {
+ if (longitudinalInertia < 0) {
+ if (getComponentVolume() > 0.0000001) // == 0.1cm^3
integrateInertiaVolume();
else
integrateInertiaSurface();
}
- return longitudalInertia;
+ return longitudinalInertia;
}
* Performs integration over the length of the component and updates the cached variables.
*/
private void integrate() {
- double x,r1,r2;
+ double x, r1, r2;
double cgx;
// Check length > 0
return;
}
-
+
// Integrate for volume, CG, wetted area and planform area
- final double l = length/DIVISIONS;
- final double pil = Math.PI*l; // PI * l
- final double pil3 = Math.PI*l/3; // PI * l/3
+ final double l = length / DIVISIONS;
+ final double pil = Math.PI * l; // PI * l
+ final double pil3 = Math.PI * l / 3; // PI * l/3
r1 = getRadius(0);
x = 0;
wetArea = 0;
volume = 0;
cgx = 0;
- for (int n=1; n<=DIVISIONS; n++) {
+ for (int n = 1; n <= DIVISIONS; n++) {
/*
* r1 and r2 are the two radii
* x is the position of r1
* hyp is the length of the hypotenuse from r1 to r2
* height if the y-axis height of the component if not filled
*/
+
+ r2 = getRadius(x + l);
+ final double hyp = MathUtil.hypot(r2 - r1, l);
- r2 = getRadius(x+l);
- final double hyp = MathUtil.hypot(r2-r1, l);
-
-
+
// Volume differential elements
final double dV;
final double dFullV;
- dFullV = pil3*(r1*r1 + r1*r2 + r2*r2);
- if (filled || r1<thickness || r2<thickness) {
+ dFullV = pil3 * (r1 * r1 + r1 * r2 + r2 * r2);
+ if (filled || r1 < thickness || r2 < thickness) {
// Filled piece
dV = dFullV;
} else {
// Hollow piece
- final double height = thickness*hyp/l;
- dV = pil*height*(r1+r2-height);
+ final double height = thickness * hyp / l;
+ dV = MathUtil.max(pil * height * (r1 + r2 - height), 0);
}
-
+
// Add to the volume-related components
volume += dV;
fullVolume += dFullV;
- cgx += (x+l/2)*dV;
+ cgx += (x + l / 2) * dV;
// Wetted area ( * PI at the end)
- wetArea += hyp*(r1+r2);
+ wetArea += hyp * (r1 + r2);
// Planform area & center
- final double p = l*(r1+r2);
+ final double p = l * (r1 + r2);
planArea += p;
- planCenter += (x+l/2)*p;
+ planCenter += (x + l / 2) * p;
// Update for next iteration
r1 = r2;
if (planArea > 0)
planCenter /= planArea;
- if (volume == 0) {
- cg = Coordinate.NUL;
+ if (volume < 0.0000000001) { // 0.1 mm^3
+ volume = 0;
+ cg = new Coordinate(length / 2, 0, 0, 0);
} else {
// getComponentMass is safe now
- cg = new Coordinate(cgx/volume,0,0,getComponentMass());
+ // Use super.getComponentMass() to ensure only the transition shape mass
+ // is used, not the shoulders
+ cg = new Coordinate(cgx / volume, 0, 0, super.getComponentMass());
}
}
/**
- * Integrate the longitudal and rotational inertia based on component volume.
+ * Integrate the longitudinal and rotational inertia based on component volume.
* This method may be used only if the total volume is zero.
*/
private void integrateInertiaVolume() {
double x, r1, r2;
-
- final double l = length/DIVISIONS;
- final double pil = Math.PI*l; // PI * l
- final double pil3 = Math.PI*l/3; // PI * l/3
-
+
+ final double l = length / DIVISIONS;
+ final double pil = Math.PI * l; // PI * l
+ final double pil3 = Math.PI * l / 3; // PI * l/3
+
r1 = getRadius(0);
x = 0;
- longitudalInertia = 0;
+ longitudinalInertia = 0;
rotationalInertia = 0;
double volume = 0;
- for (int n=1; n<=DIVISIONS; n++) {
+ for (int n = 1; n <= DIVISIONS; n++) {
/*
* r1 and r2 are the two radii, outer is their average
* x is the position of r1
* hyp is the length of the hypotenuse from r1 to r2
* height if the y-axis height of the component if not filled
*/
- r2 = getRadius(x+l);
- final double outer = (r1 + r2)/2;
-
+ r2 = getRadius(x + l);
+ final double outer = (r1 + r2) / 2;
+
// Volume differential elements
final double inner;
final double dV;
- if (filled || r1<thickness || r2<thickness) {
+ if (filled || r1 < thickness || r2 < thickness) {
inner = 0;
- dV = pil3*(r1*r1 + r1*r2 + r2*r2);
+ dV = pil3 * (r1 * r1 + r1 * r2 + r2 * r2);
} else {
- final double hyp = MathUtil.hypot(r2-r1, l);
- final double height = thickness*hyp/l;
- dV = pil*height*(r1+r2-height);
- inner = Math.max(outer-height, 0);
+ final double hyp = MathUtil.hypot(r2 - r1, l);
+ final double height = thickness * hyp / l;
+ dV = pil * height * (r1 + r2 - height);
+ inner = Math.max(outer - height, 0);
}
- rotationalInertia += dV * (pow2(outer) + pow2(inner))/2;
- longitudalInertia += dV * ((3 * (pow2(outer) + pow2(inner)) + pow2(l))/12
- + pow2(x+l/2));
+ rotationalInertia += dV * (pow2(outer) + pow2(inner)) / 2;
+ longitudinalInertia += dV * ((3 * (pow2(outer) + pow2(inner)) + pow2(l)) / 12
+ + pow2(x + l / 2));
volume += dV;
x += l;
}
- if (MathUtil.equals(volume,0)) {
+ if (MathUtil.equals(volume, 0)) {
integrateInertiaSurface();
return;
}
rotationalInertia /= volume;
- longitudalInertia /= volume;
-
- // Shift longitudal inertia to CG
- longitudalInertia = Math.max(longitudalInertia - pow2(getComponentCG().x), 0);
+ longitudinalInertia /= volume;
+
+ // Shift longitudinal inertia to CG
+ longitudinalInertia = Math.max(longitudinalInertia - pow2(getComponentCG().x), 0);
}
/**
- * Integrate the longitudal and rotational inertia based on component surface area.
+ * Integrate the longitudinal and rotational inertia based on component surface area.
* This method may be used only if the total volume is zero.
*/
private void integrateInertiaSurface() {
double x, r1, r2;
-
- final double l = length/DIVISIONS;
-
+
+ final double l = length / DIVISIONS;
+
r1 = getRadius(0);
+ System.out.println(r1);
x = 0;
- longitudalInertia = 0;
+
+ longitudinalInertia = 0;
rotationalInertia = 0;
double surface = 0;
- for (int n=1; n<=DIVISIONS; n++) {
+ for (int n = 1; n <= DIVISIONS; n++) {
/*
* r1 and r2 are the two radii, outer is their average
* x is the position of r1
* hyp is the length of the hypotenuse from r1 to r2
* height if the y-axis height of the component if not filled
*/
- r2 = getRadius(x+l);
- final double hyp = MathUtil.hypot(r2-r1, l);
- final double outer = (r1 + r2)/2;
+ r2 = getRadius(x + l);
+ final double hyp = MathUtil.hypot(r2 - r1, l);
+ final double outer = (r1 + r2) / 2;
+
+ final double dS = hyp * (r1 + r2) * Math.PI;
- final double dS = hyp * (r1+r2) * Math.PI;
-
rotationalInertia += dS * pow2(outer);
- longitudalInertia += dS * ((6 * pow2(outer) + pow2(l))/12 + pow2(x+l/2));
+ longitudinalInertia += dS * ((6 * pow2(outer) + pow2(l)) / 12 + pow2(x + l / 2));
surface += dS;
r1 = r2;
x += l;
}
-
+
if (MathUtil.equals(surface, 0)) {
- longitudalInertia = 0;
+ longitudinalInertia = 0;
rotationalInertia = 0;
return;
}
- longitudalInertia /= surface;
+ longitudinalInertia /= surface;
rotationalInertia /= surface;
- // Shift longitudal inertia to CG
- longitudalInertia = Math.max(longitudalInertia - pow2(getComponentCG().x), 0);
+ // Shift longitudinal inertia to CG
+ longitudinalInertia = Math.max(longitudinalInertia - pow2(getComponentCG().x), 0);
}
-
-
+
+
/**
* Invalidates the cached volume and CG information.
*/
planCenter = -1;
volume = -1;
fullVolume = -1;
- longitudalInertia = -1;
+ longitudinalInertia = -1;
rotationalInertia = -1;
cg = null;
}
}
-
+
/////////// Auto radius helper methods
-
+
/**
* Returns the automatic radius for this component towards the
* front of the rocket. The automatics will not search towards the
* match was not found.
*/
protected abstract double getFrontAutoRadius();
-
+
/**
* Returns the automatic radius for this component towards the
* end of the rocket. The automatics will not search towards the
protected abstract double getRearAutoRadius();
-
+
/**
* Return the previous symmetric component, or null if none exists.
* NOTE: This method currently assumes that there are no external
RocketComponent c;
for (c = this.getPreviousComponent(); c != null; c = c.getPreviousComponent()) {
if (c instanceof SymmetricComponent) {
- return (SymmetricComponent)c;
+ return (SymmetricComponent) c;
}
if (!(c instanceof Stage) &&
- (c.relativePosition == RocketComponent.Position.AFTER))
- return null; // Bad component type as "parent"
+ (c.relativePosition == RocketComponent.Position.AFTER))
+ return null; // Bad component type as "parent"
}
return null;
}
RocketComponent c;
for (c = this.getNextComponent(); c != null; c = c.getNextComponent()) {
if (c instanceof SymmetricComponent) {
- return (SymmetricComponent)c;
+ return (SymmetricComponent) c;
}
if (!(c instanceof Stage) &&
- (c.relativePosition == RocketComponent.Position.AFTER))
- return null; // Bad component type as "parent"
+ (c.relativePosition == RocketComponent.Position.AFTER))
+ return null; // Bad component type as "parent"
}
return null;
}