1 package net.sf.openrocket.rocketcomponent;
3 import net.sf.openrocket.util.Coordinate;
4 import net.sf.openrocket.util.MathUtil;
6 import java.util.ArrayList;
7 import java.util.Collection;
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();
36 public abstract void setOuterRadius(double r);
39 public abstract double getInnerRadius();
41 public abstract void setInnerRadius(double r);
44 public abstract double getThickness();
45 public abstract void setThickness(double thickness);
48 public final boolean isOuterRadiusAutomatic() {
49 return outerRadiusAutomatic;
52 protected void setOuterRadiusAutomatic(boolean auto) {
53 if (auto == outerRadiusAutomatic)
55 outerRadiusAutomatic = auto;
56 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
60 public final boolean isInnerRadiusAutomatic() {
61 return innerRadiusAutomatic;
64 protected void setInnerRadiusAutomatic(boolean auto) {
65 if (auto == innerRadiusAutomatic)
67 innerRadiusAutomatic = auto;
68 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
74 public final void setLength(double length) {
75 double l = Math.max(length,0);
80 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
85 * Return the radial direction of displacement of the component. Direction 0
86 * is equivalent to the Y-direction.
88 * @return the radial direction.
90 public double getRadialDirection() {
91 return radialDirection;
95 * Set the radial direction of displacement of the component. Direction 0
96 * is equivalent to the Y-direction.
98 * @param dir the radial direction.
100 public void setRadialDirection(double dir) {
101 dir = MathUtil.reduce180(dir);
102 if (radialDirection == dir)
104 radialDirection = dir;
105 shiftY = radialPosition * Math.cos(radialDirection);
106 shiftZ = radialPosition * Math.sin(radialDirection);
107 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
114 * Return the radial position of the component. The position is the distance
115 * of the center of the component from the center of the parent component.
117 * @return the radial position.
119 public double getRadialPosition() {
120 return radialPosition;
124 * Set the radial position of the component. The position is the distance
125 * of the center of the component from the center of the parent component.
127 * @param pos the radial position.
129 public void setRadialPosition(double pos) {
130 pos = Math.max(pos, 0);
131 if (radialPosition == pos)
133 radialPosition = pos;
134 shiftY = radialPosition * Math.cos(radialDirection);
135 shiftZ = radialPosition * Math.sin(radialDirection);
136 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
140 public double getRadialShiftY() {
144 public double getRadialShiftZ() {
148 public void setRadialShift(double y, double z) {
149 radialPosition = Math.hypot(y, z);
150 radialDirection = Math.atan2(z, y);
152 // Re-calculate to ensure consistency
153 shiftY = radialPosition * Math.cos(radialDirection);
154 shiftZ = radialPosition * Math.sin(radialDirection);
155 assert(MathUtil.equals(y, shiftY));
156 assert(MathUtil.equals(z, shiftZ));
158 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
163 * Return the number of times the component is multiplied.
165 public int getClusterCount() {
166 if (this instanceof Clusterable)
167 return ((Clusterable)this).getClusterConfiguration().getClusterCount();
173 * Shift the coordinates according to the radial position and direction.
176 public Coordinate[] shiftCoordinates(Coordinate[] array) {
177 for (int i=0; i < array.length; i++) {
178 array[i] = array[i].add(0, shiftY, shiftZ);
185 public Collection<Coordinate> getComponentBounds() {
186 List<Coordinate> bounds = new ArrayList<Coordinate>();
187 addBound(bounds,0,getOuterRadius());
188 addBound(bounds,length,getOuterRadius());
195 public Coordinate getComponentCG() {
196 return new Coordinate(length/2, 0, 0, getComponentMass());
200 public double getComponentMass() {
201 return ringMass(getOuterRadius(), getInnerRadius(), getLength(),
202 getMaterial().getDensity()) * getClusterCount();
207 public double getLongitudalUnitInertia() {
208 return ringLongitudalUnitInertia(getOuterRadius(), getInnerRadius(), getLength());
212 public double getRotationalUnitInertia() {
213 return ringRotationalUnitInertia(getOuterRadius(), getInnerRadius());
217 * Accept a visitor to this RingComponent in the component hierarchy.
219 * @param theVisitor the visitor that will be called back with a reference to this RingComponent
222 public void accept (final ComponentVisitor theVisitor) {
223 theVisitor.visit(this);