package net.sf.openrocket.rocketcomponent;
import java.util.ArrayList;
import java.util.Collection;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPreset.Type;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil;
public class LaunchLug extends ExternalComponent implements Coaxial {
private static final Translator trans = Application.getTranslator();
private double radius;
private double thickness;
private double radialDirection = 0;
/* These are calculated when the component is first attached to any Rocket */
private double shiftY, shiftZ;
public LaunchLug() {
super(Position.MIDDLE);
radius = 0.01 / 2;
thickness = 0.001;
length = 0.03;
}
@Override
public double getOuterRadius() {
return radius;
}
@Override
public void setOuterRadius(double radius) {
if (MathUtil.equals(this.radius, radius))
return;
this.radius = radius;
this.thickness = Math.min(this.thickness, this.radius);
clearPreset();
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
@Override
public double getInnerRadius() {
return radius - thickness;
}
@Override
public void setInnerRadius(double innerRadius) {
setOuterRadius(innerRadius + thickness);
}
@Override
public double getThickness() {
return thickness;
}
public void setThickness(double thickness) {
if (MathUtil.equals(this.thickness, thickness))
return;
this.thickness = MathUtil.clamp(thickness, 0, radius);
clearPreset();
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
public double getRadialDirection() {
return radialDirection;
}
public void setRadialDirection(double direction) {
direction = MathUtil.reduce180(direction);
if (MathUtil.equals(this.radialDirection, direction))
return;
this.radialDirection = direction;
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
public void setLength(double length) {
if (MathUtil.equals(this.length, length))
return;
this.length = length;
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
@Override
public void setRelativePosition(RocketComponent.Position position) {
super.setRelativePosition(position);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
@Override
public void setPositionValue(double value) {
super.setPositionValue(value);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
@Override
protected void loadFromPreset(ComponentPreset preset) {
if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
double outerDiameter = preset.get(ComponentPreset.OUTER_DIAMETER);
this.radius = outerDiameter / 2.0;
if (preset.has(ComponentPreset.INNER_DIAMETER)) {
double innerDiameter = preset.get(ComponentPreset.INNER_DIAMETER);
this.thickness = (outerDiameter - innerDiameter) / 2.0;
}
}
super.loadFromPreset(preset);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
@Override
public Type getPresetType() {
return ComponentPreset.Type.LAUNCH_LUG;
}
@Override
public Coordinate[] shiftCoordinates(Coordinate[] array) {
array = super.shiftCoordinates(array);
for (int i = 0; i < array.length; i++) {
array[i] = array[i].add(0, shiftY, shiftZ);
}
return array;
}
@Override
public void componentChanged(ComponentChangeEvent e) {
super.componentChanged(e);
/*
* shiftY and shiftZ must be computed here since calculating them
* in shiftCoordinates() would cause an infinite loop due to .toRelative
*/
RocketComponent body;
double parentRadius;
for (body = this.getParent(); body != null; body = body.getParent()) {
if (body instanceof SymmetricComponent)
break;
}
if (body == null) {
parentRadius = 0;
} else {
SymmetricComponent s = (SymmetricComponent) body;
double x1, x2;
x1 = this.toRelative(Coordinate.NUL, body)[0].x;
x2 = this.toRelative(new Coordinate(length, 0, 0), body)[0].x;
x1 = MathUtil.clamp(x1, 0, body.getLength());
x2 = MathUtil.clamp(x2, 0, body.getLength());
parentRadius = Math.max(s.getRadius(x1), s.getRadius(x2));
}
shiftY = Math.cos(radialDirection) * (parentRadius + radius);
shiftZ = Math.sin(radialDirection) * (parentRadius + radius);
// System.out.println("Computed shift: y="+shiftY+" z="+shiftZ);
}
@Override
public double getComponentVolume() {
return length * Math.PI * (MathUtil.pow2(radius) - MathUtil.pow2(radius - thickness));
}
@Override
public Collection<Coordinate> getComponentBounds() {
ArrayList<Coordinate> set = new ArrayList<Coordinate>();
addBound(set, 0, radius);
addBound(set, length, radius);
return set;
}
@Override
public Coordinate getComponentCG() {
return new Coordinate(length / 2, 0, 0, getComponentMass());
}
@Override
public String getComponentName() {
//// Launch lug
return trans.get("LaunchLug.Launchlug");
}
@Override
public double getLongitudinalUnitInertia() {
// 1/12 * (3 * (r2^2 + r1^2) + h^2)
return (3 * (MathUtil.pow2(getOuterRadius()) + MathUtil.pow2(getInnerRadius())) + MathUtil.pow2(getLength())) / 12;
}
@Override
public double getRotationalUnitInertia() {
// 1/2 * (r1^2 + r2^2)
return (MathUtil.pow2(getInnerRadius()) + MathUtil.pow2(getOuterRadius())) / 2;
}
@Override
public boolean allowsChildren() {
return false;
}
@Override
public boolean isCompatible(Class<? extends RocketComponent> type) {
// Allow nothing to be attached to a LaunchLug
return false;
}
}