package net.sf.openrocket.rocketcomponent; import java.util.ArrayList; import java.util.Collection; import java.util.List; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; /** * An inner component that consists of a hollow cylindrical component. This can be * an inner tube, tube coupler, centering ring, bulkhead etc. * * The properties include the inner and outer radii, length and radial position. * * @author Sampo Niskanen <sampo.niskanen@iki.fi> */ public abstract class RingComponent extends StructuralComponent implements Coaxial { protected boolean outerRadiusAutomatic = false; protected boolean innerRadiusAutomatic = false; private double radialDirection = 0; private double radialPosition = 0; private double shiftY = 0; private double shiftZ = 0; @Override public abstract double getOuterRadius(); @Override public abstract void setOuterRadius(double r); @Override public abstract double getInnerRadius(); @Override public abstract void setInnerRadius(double r); @Override public abstract double getThickness(); public abstract void setThickness(double thickness); public final boolean isOuterRadiusAutomatic() { return outerRadiusAutomatic; } // Setter is protected, subclasses may make it public protected void setOuterRadiusAutomatic(boolean auto) { if (auto == outerRadiusAutomatic) return; outerRadiusAutomatic = auto; fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); } public final boolean isInnerRadiusAutomatic() { return innerRadiusAutomatic; } // Setter is protected, subclasses may make it public protected void setInnerRadiusAutomatic(boolean auto) { if (auto == innerRadiusAutomatic) return; innerRadiusAutomatic = auto; fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); } public final void setLength(double length) { double l = Math.max(length, 0); if (this.length == l) return; this.length = l; fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); } /** * Return the radial direction of displacement of the component. Direction 0 * is equivalent to the Y-direction. * * @return the radial direction. */ public double getRadialDirection() { return radialDirection; } /** * Set the radial direction of displacement of the component. Direction 0 * is equivalent to the Y-direction. * * @param dir the radial direction. */ public void setRadialDirection(double dir) { dir = MathUtil.reduce180(dir); if (radialDirection == dir) return; radialDirection = dir; shiftY = radialPosition * Math.cos(radialDirection); shiftZ = radialPosition * Math.sin(radialDirection); fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); } /** * Return the radial position of the component. The position is the distance * of the center of the component from the center of the parent component. * * @return the radial position. */ public double getRadialPosition() { return radialPosition; } /** * Set the radial position of the component. The position is the distance * of the center of the component from the center of the parent component. * * @param pos the radial position. */ public void setRadialPosition(double pos) { pos = Math.max(pos, 0); if (radialPosition == pos) return; radialPosition = pos; shiftY = radialPosition * Math.cos(radialDirection); shiftZ = radialPosition * Math.sin(radialDirection); fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); } public double getRadialShiftY() { return shiftY; } public double getRadialShiftZ() { return shiftZ; } public void setRadialShift(double y, double z) { radialPosition = Math.hypot(y, z); radialDirection = Math.atan2(z, y); // Re-calculate to ensure consistency shiftY = radialPosition * Math.cos(radialDirection); shiftZ = radialPosition * Math.sin(radialDirection); assert (MathUtil.equals(y, shiftY)); assert (MathUtil.equals(z, shiftZ)); fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); } /** * Return the number of times the component is multiplied. */ public int getClusterCount() { if (this instanceof Clusterable) return ((Clusterable) this).getClusterConfiguration().getClusterCount(); return 1; } /** * Shift the coordinates according to the radial position and direction. */ @Override public Coordinate[] shiftCoordinates(Coordinate[] array) { for (int i = 0; i < array.length; i++) { array[i] = array[i].add(0, shiftY, shiftZ); } return array; } @Override public Collection<Coordinate> getComponentBounds() { List<Coordinate> bounds = new ArrayList<Coordinate>(); addBound(bounds, 0, getOuterRadius()); addBound(bounds, length, getOuterRadius()); return bounds; } @Override public Coordinate getComponentCG() { return new Coordinate(length / 2, 0, 0, getComponentMass()); } @Override public double getComponentMass() { return ringMass(getOuterRadius(), getInnerRadius(), getLength(), getMaterial().getDensity()) * getClusterCount(); } @Override public double getLongitudinalUnitInertia() { return ringLongitudinalUnitInertia(getOuterRadius(), getInnerRadius(), getLength()); } @Override public double getRotationalUnitInertia() { return ringRotationalUnitInertia(getOuterRadius(), getInnerRadius()); } }