1 package net.sf.openrocket.rocketcomponent;
3 import java.util.ArrayList;
4 import java.util.Collection;
7 import net.sf.openrocket.util.Coordinate;
8 import net.sf.openrocket.util.MathUtil;
12 * An inner component that consists of a hollow cylindrical component. This can be
13 * an inner tube, tube coupler, centering ring, bulkhead etc.
15 * The properties include the inner and outer radii, length and radial position.
17 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
19 public abstract class RingComponent extends StructuralComponent implements Coaxial {
21 protected boolean outerRadiusAutomatic = false;
22 protected boolean innerRadiusAutomatic = false;
25 private double radialDirection = 0;
26 private double radialPosition = 0;
28 private double shiftY = 0;
29 private double shiftZ = 0;
34 public abstract double getOuterRadius();
37 public abstract void setOuterRadius(double r);
40 public abstract double getInnerRadius();
43 public abstract void setInnerRadius(double r);
46 public abstract double getThickness();
48 public abstract void setThickness(double thickness);
51 public final boolean isOuterRadiusAutomatic() {
52 return outerRadiusAutomatic;
55 // Setter is protected, subclasses may make it public
56 protected void setOuterRadiusAutomatic(boolean auto) {
57 if (auto == outerRadiusAutomatic)
59 outerRadiusAutomatic = auto;
60 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
64 public final boolean isInnerRadiusAutomatic() {
65 return innerRadiusAutomatic;
68 // Setter is protected, subclasses may make it public
69 protected void setInnerRadiusAutomatic(boolean auto) {
70 if (auto == innerRadiusAutomatic)
72 innerRadiusAutomatic = auto;
73 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
79 public final void setLength(double length) {
80 double l = Math.max(length, 0);
85 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
90 * Return the radial direction of displacement of the component. Direction 0
91 * is equivalent to the Y-direction.
93 * @return the radial direction.
95 public double getRadialDirection() {
96 return radialDirection;
100 * Set the radial direction of displacement of the component. Direction 0
101 * is equivalent to the Y-direction.
103 * @param dir the radial direction.
105 public void setRadialDirection(double dir) {
106 dir = MathUtil.reduce180(dir);
107 if (radialDirection == dir)
109 radialDirection = dir;
110 shiftY = radialPosition * Math.cos(radialDirection);
111 shiftZ = radialPosition * Math.sin(radialDirection);
112 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
119 * Return the radial position of the component. The position is the distance
120 * of the center of the component from the center of the parent component.
122 * @return the radial position.
124 public double getRadialPosition() {
125 return radialPosition;
129 * Set the radial position of the component. The position is the distance
130 * of the center of the component from the center of the parent component.
132 * @param pos the radial position.
134 public void setRadialPosition(double pos) {
135 pos = Math.max(pos, 0);
136 if (radialPosition == pos)
138 radialPosition = pos;
139 shiftY = radialPosition * Math.cos(radialDirection);
140 shiftZ = radialPosition * Math.sin(radialDirection);
141 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
145 public double getRadialShiftY() {
149 public double getRadialShiftZ() {
153 public void setRadialShift(double y, double z) {
154 radialPosition = Math.hypot(y, z);
155 radialDirection = Math.atan2(z, y);
157 // Re-calculate to ensure consistency
158 shiftY = radialPosition * Math.cos(radialDirection);
159 shiftZ = radialPosition * Math.sin(radialDirection);
160 assert (MathUtil.equals(y, shiftY));
161 assert (MathUtil.equals(z, shiftZ));
163 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
168 * Return the number of times the component is multiplied.
170 public int getClusterCount() {
171 if (this instanceof Clusterable)
172 return ((Clusterable) this).getClusterConfiguration().getClusterCount();
178 * Shift the coordinates according to the radial position and direction.
181 public Coordinate[] shiftCoordinates(Coordinate[] array) {
182 for (int i = 0; i < array.length; i++) {
183 array[i] = array[i].add(0, shiftY, shiftZ);
190 public Collection<Coordinate> getComponentBounds() {
191 List<Coordinate> bounds = new ArrayList<Coordinate>();
192 addBound(bounds, 0, getOuterRadius());
193 addBound(bounds, length, getOuterRadius());
200 public Coordinate getComponentCG() {
201 return new Coordinate(length / 2, 0, 0, getComponentMass());
205 public double getComponentMass() {
206 return ringMass(getOuterRadius(), getInnerRadius(), getLength(),
207 getMaterial().getDensity()) * getClusterCount();
212 public double getLongitudinalUnitInertia() {
213 return ringLongitudinalUnitInertia(getOuterRadius(), getInnerRadius(), getLength());
217 public double getRotationalUnitInertia() {
218 return ringRotationalUnitInertia(getOuterRadius(), getInnerRadius());