233457c25e8929637e37919e680afff27c07bcee
[debian/openrocket] / src / net / sf / openrocket / rocketcomponent / RingComponent.java
1 package net.sf.openrocket.rocketcomponent;
2
3 import net.sf.openrocket.util.Coordinate;
4 import net.sf.openrocket.util.MathUtil;
5
6 import java.util.ArrayList;
7 import java.util.Collection;
8 import java.util.List;
9
10
11 /**
12  * An inner component that consists of a hollow cylindrical component.  This can be
13  * an inner tube, tube coupler, centering ring, bulkhead etc.
14  *
15  * The properties include the inner and outer radii, length and radial position.
16  *
17  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
18  */
19 public abstract class RingComponent extends StructuralComponent implements Coaxial {
20
21         protected boolean outerRadiusAutomatic = false;
22         protected boolean innerRadiusAutomatic = false;
23
24
25         private double radialDirection = 0;
26         private double radialPosition = 0;
27
28         private double shiftY = 0;
29         private double shiftZ = 0;
30
31
32
33     @Override
34         public abstract double getOuterRadius();
35     @Override
36         public abstract void setOuterRadius(double r);
37
38     @Override
39         public abstract double getInnerRadius();
40     @Override
41         public abstract void setInnerRadius(double r);
42
43     @Override
44         public abstract double getThickness();
45         public abstract void setThickness(double thickness);
46
47
48         public final boolean isOuterRadiusAutomatic() {
49                 return outerRadiusAutomatic;
50         }
51
52         protected void setOuterRadiusAutomatic(boolean auto) {
53                 if (auto == outerRadiusAutomatic)
54                         return;
55                 outerRadiusAutomatic = auto;
56                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
57         }
58
59
60         public final boolean isInnerRadiusAutomatic() {
61                 return innerRadiusAutomatic;
62         }
63
64         protected void setInnerRadiusAutomatic(boolean auto) {
65                 if (auto == innerRadiusAutomatic)
66                         return;
67                 innerRadiusAutomatic = auto;
68                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
69         }
70
71
72
73
74         public final void setLength(double length) {
75                 double l = Math.max(length,0);
76                 if (this.length == l)
77                         return;
78
79                 this.length = l;
80                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
81         }
82
83
84         /**
85          * Return the radial direction of displacement of the component.  Direction 0
86          * is equivalent to the Y-direction.
87          *
88          * @return  the radial direction.
89          */
90         public double getRadialDirection() {
91                 return radialDirection;
92         }
93
94         /**
95          * Set the radial direction of displacement of the component.  Direction 0
96          * is equivalent to the Y-direction.
97          *
98          * @param dir  the radial direction.
99          */
100         public void setRadialDirection(double dir) {
101                 dir = MathUtil.reduce180(dir);
102                 if (radialDirection == dir)
103                         return;
104                 radialDirection = dir;
105                 shiftY = radialPosition * Math.cos(radialDirection);
106                 shiftZ = radialPosition * Math.sin(radialDirection);
107                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
108         }
109
110
111
112
113         /**
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.
116          *
117          * @return  the radial position.
118          */
119         public double getRadialPosition() {
120                 return radialPosition;
121         }
122
123         /**
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.
126          *
127          * @param pos  the radial position.
128          */
129         public void setRadialPosition(double pos) {
130                 pos = Math.max(pos, 0);
131                 if (radialPosition == pos)
132                         return;
133                 radialPosition = pos;
134                 shiftY = radialPosition * Math.cos(radialDirection);
135                 shiftZ = radialPosition * Math.sin(radialDirection);
136                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
137         }
138
139
140         public double getRadialShiftY() {
141                 return shiftY;
142         }
143
144         public double getRadialShiftZ() {
145                 return shiftZ;
146         }
147
148         public void setRadialShift(double y, double z) {
149                 radialPosition = Math.hypot(y, z);
150                 radialDirection = Math.atan2(z, y);
151
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));
157
158                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
159         }
160
161
162         /**
163          * Return the number of times the component is multiplied.
164          */
165         public int getClusterCount() {
166                 if (this instanceof Clusterable)
167                         return ((Clusterable)this).getClusterConfiguration().getClusterCount();
168                 return 1;
169         }
170
171
172         /**
173          * Shift the coordinates according to the radial position and direction.
174          */
175         @Override
176         public Coordinate[] shiftCoordinates(Coordinate[] array) {
177                 for (int i=0; i < array.length; i++) {
178                         array[i] = array[i].add(0, shiftY, shiftZ);
179                 }
180                 return array;
181         }
182
183
184         @Override
185         public Collection<Coordinate> getComponentBounds() {
186                 List<Coordinate> bounds = new ArrayList<Coordinate>();
187                 addBound(bounds,0,getOuterRadius());
188                 addBound(bounds,length,getOuterRadius());
189                 return bounds;
190         }
191
192
193
194         @Override
195         public Coordinate getComponentCG() {
196                 return new Coordinate(length/2, 0, 0, getComponentMass());
197         }
198
199         @Override
200         public double getComponentMass() {
201                 return ringMass(getOuterRadius(), getInnerRadius(), getLength(),
202                                 getMaterial().getDensity()) * getClusterCount();
203         }
204
205
206         @Override
207         public double getLongitudinalUnitInertia() {
208                 return ringLongitudinalUnitInertia(getOuterRadius(), getInnerRadius(), getLength());
209         }
210
211         @Override
212         public double getRotationalUnitInertia() {
213                 return ringRotationalUnitInertia(getOuterRadius(), getInnerRadius());
214         }
215
216 }