create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / rocketcomponent / RingComponent.java
1 package net.sf.openrocket.rocketcomponent;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.List;
6
7 import net.sf.openrocket.util.Coordinate;
8 import net.sf.openrocket.util.MathUtil;
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         
36         @Override
37         public abstract void setOuterRadius(double r);
38         
39         @Override
40         public abstract double getInnerRadius();
41         
42         @Override
43         public abstract void setInnerRadius(double r);
44         
45         @Override
46         public abstract double getThickness();
47         
48         public abstract void setThickness(double thickness);
49         
50         
51         public final boolean isOuterRadiusAutomatic() {
52                 return outerRadiusAutomatic;
53         }
54         
55         // Setter is protected, subclasses may make it public
56         protected void setOuterRadiusAutomatic(boolean auto) {
57                 if (auto == outerRadiusAutomatic)
58                         return;
59                 outerRadiusAutomatic = auto;
60                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
61         }
62         
63         
64         public final boolean isInnerRadiusAutomatic() {
65                 return innerRadiusAutomatic;
66         }
67         
68         // Setter is protected, subclasses may make it public
69         protected void setInnerRadiusAutomatic(boolean auto) {
70                 if (auto == innerRadiusAutomatic)
71                         return;
72                 innerRadiusAutomatic = auto;
73                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
74         }
75         
76         
77
78
79         public final void setLength(double length) {
80                 double l = Math.max(length, 0);
81                 if (this.length == l)
82                         return;
83                 
84                 this.length = l;
85                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
86         }
87         
88         
89         /**
90          * Return the radial direction of displacement of the component.  Direction 0
91          * is equivalent to the Y-direction.
92          *
93          * @return  the radial direction.
94          */
95         public double getRadialDirection() {
96                 return radialDirection;
97         }
98         
99         /**
100          * Set the radial direction of displacement of the component.  Direction 0
101          * is equivalent to the Y-direction.
102          *
103          * @param dir  the radial direction.
104          */
105         public void setRadialDirection(double dir) {
106                 dir = MathUtil.reduce180(dir);
107                 if (radialDirection == dir)
108                         return;
109                 radialDirection = dir;
110                 shiftY = radialPosition * Math.cos(radialDirection);
111                 shiftZ = radialPosition * Math.sin(radialDirection);
112                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
113         }
114         
115         
116
117
118         /**
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.
121          *
122          * @return  the radial position.
123          */
124         public double getRadialPosition() {
125                 return radialPosition;
126         }
127         
128         /**
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.
131          *
132          * @param pos  the radial position.
133          */
134         public void setRadialPosition(double pos) {
135                 pos = Math.max(pos, 0);
136                 if (radialPosition == pos)
137                         return;
138                 radialPosition = pos;
139                 shiftY = radialPosition * Math.cos(radialDirection);
140                 shiftZ = radialPosition * Math.sin(radialDirection);
141                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
142         }
143         
144         
145         public double getRadialShiftY() {
146                 return shiftY;
147         }
148         
149         public double getRadialShiftZ() {
150                 return shiftZ;
151         }
152         
153         public void setRadialShift(double y, double z) {
154                 radialPosition = Math.hypot(y, z);
155                 radialDirection = Math.atan2(z, y);
156                 
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));
162                 
163                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
164         }
165         
166         
167         /**
168          * Return the number of times the component is multiplied.
169          */
170         public int getClusterCount() {
171                 if (this instanceof Clusterable)
172                         return ((Clusterable) this).getClusterConfiguration().getClusterCount();
173                 return 1;
174         }
175         
176         
177         /**
178          * Shift the coordinates according to the radial position and direction.
179          */
180         @Override
181         public Coordinate[] shiftCoordinates(Coordinate[] array) {
182                 for (int i = 0; i < array.length; i++) {
183                         array[i] = array[i].add(0, shiftY, shiftZ);
184                 }
185                 return array;
186         }
187         
188         
189         @Override
190         public Collection<Coordinate> getComponentBounds() {
191                 List<Coordinate> bounds = new ArrayList<Coordinate>();
192                 addBound(bounds, 0, getOuterRadius());
193                 addBound(bounds, length, getOuterRadius());
194                 return bounds;
195         }
196         
197         
198
199         @Override
200         public Coordinate getComponentCG() {
201                 return new Coordinate(length / 2, 0, 0, getComponentMass());
202         }
203         
204         @Override
205         public double getComponentMass() {
206                 return ringMass(getOuterRadius(), getInnerRadius(), getLength(),
207                                 getMaterial().getDensity()) * getClusterCount();
208         }
209         
210         
211         @Override
212         public double getLongitudinalUnitInertia() {
213                 return ringLongitudinalUnitInertia(getOuterRadius(), getInnerRadius(), getLength());
214         }
215         
216         @Override
217         public double getRotationalUnitInertia() {
218                 return ringRotationalUnitInertia(getOuterRadius(), getInnerRadius());
219         }
220         
221 }