package net.sf.openrocket.rocketcomponent;
import static net.sf.openrocket.util.MathUtil.pow2;
import java.util.ArrayList;
import java.util.Collection;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil;
/**
* A MassObject is an internal component that can a specific weight, but not necessarily a strictly bound shape. It is
* represented as a homogeneous cylinder and drawn in the rocket figure with rounded corners.
* <p/>
* Subclasses of this class need only implement the {@link #getComponentMass()}, {@link #getComponentName()} and {@link
* #isCompatible(RocketComponent)} methods.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public abstract class MassObject extends InternalComponent {
private double radius;
private double radialPosition;
private double radialDirection;
private double shiftY = 0;
private double shiftZ = 0;
public MassObject() {
this(0.025, 0.0125);
}
public MassObject(double length, double radius) {
super();
this.length = length;
this.radius = radius;
this.setRelativePosition(Position.TOP);
this.setPositionValue(0.0);
}
public void setLength(double length) {
length = Math.max(length, 0);
if (MathUtil.equals(this.length, length)) {
return;
}
this.length = length;
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
}
public final double getRadius() {
return radius;
}
public final void setRadius(double radius) {
radius = Math.max(radius, 0);
if (MathUtil.equals(this.radius, radius)) {
return;
}
this.radius = radius;
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
}
public final double getRadialPosition() {
return radialPosition;
}
public final void setRadialPosition(double radialPosition) {
radialPosition = Math.max(radialPosition, 0);
if (MathUtil.equals(this.radialPosition, radialPosition)) {
return;
}
this.radialPosition = radialPosition;
shiftY = radialPosition * Math.cos(radialDirection);
shiftZ = radialPosition * Math.sin(radialDirection);
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
}
public final double getRadialDirection() {
return radialDirection;
}
public final void setRadialDirection(double radialDirection) {
radialDirection = MathUtil.reduce180(radialDirection);
if (MathUtil.equals(this.radialDirection, radialDirection)) {
return;
}
this.radialDirection = radialDirection;
shiftY = radialPosition * Math.cos(radialDirection);
shiftZ = radialPosition * Math.sin(radialDirection);
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
}
/**
* Shift the coordinates according to the radial position and direction.
*/
@Override
public final Coordinate[] shiftCoordinates(Coordinate[] array) {
for (int i = 0; i < array.length; i++) {
array[i] = array[i].add(0, shiftY, shiftZ);
}
return array;
}
@Override
public final Coordinate getComponentCG() {
return new Coordinate(length / 2, shiftY, shiftZ, getComponentMass());
}
@Override
public final double getLongitudinalUnitInertia() {
return (3 * pow2(radius) + pow2(length)) / 12;
}
@Override
public final double getRotationalUnitInertia() {
return pow2(radius) / 2;
}
@Override
public final Collection<Coordinate> getComponentBounds() {
Collection<Coordinate> c = new ArrayList<Coordinate>();
addBound(c, 0, radius);
addBound(c, length, radius);
return c;
}
}