updates for 0.9.3
[debian/openrocket] / src / net / sf / openrocket / rocketcomponent / InnerTube.java
1 package net.sf.openrocket.rocketcomponent;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6
7 import net.sf.openrocket.util.Coordinate;
8 import net.sf.openrocket.util.MathUtil;
9
10
11 /**
12  * This class defines an inner tube that can be used as a motor mount.  The component
13  * may also be clustered.
14  * 
15  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
16  */
17 public class InnerTube extends ThicknessRingComponent 
18 implements Clusterable, RadialParent, MotorMount {
19
20         private ClusterConfiguration cluster = ClusterConfiguration.SINGLE;
21         private double clusterScale = 1.0;
22         private double clusterRotation = 0.0;
23         
24         
25         private boolean motorMount = false;
26         private HashMap<String, Double> ejectionDelays = new HashMap<String, Double>();
27         private HashMap<String, Motor> motors = new HashMap<String, Motor>();
28         private IgnitionEvent ignitionEvent = IgnitionEvent.AUTOMATIC;
29         private double ignitionDelay = 0;
30         private double overhang = 0;
31
32         
33         /**
34          * Main constructor.
35          */
36         public InnerTube() {
37                 // A-C motor size:
38                 this.setOuterRadius(0.019/2);
39                 this.setInnerRadius(0.018/2);
40                 this.setLength(0.070);
41         }
42         
43         
44         @Override
45         public double getInnerRadius(double x) {
46                 return getInnerRadius();
47         }
48
49
50         @Override
51         public double getOuterRadius(double x) {
52                 return getOuterRadius();
53         }
54         
55
56         @Override
57         public String getComponentName() {
58                 return "Inner Tube";
59         }
60
61         /**
62          * Allow all InternalComponents to be added to this component.
63          */
64         @Override
65         public boolean isCompatible(Class<? extends RocketComponent> type) {
66                 return InternalComponent.class.isAssignableFrom(type);
67         }
68
69         
70         
71         /////////////  Cluster methods  //////////////
72         
73         /**
74          * Get the current cluster configuration.
75          * @return  The current cluster configuration.
76          */
77         public ClusterConfiguration getClusterConfiguration() {
78                 return cluster;
79         }
80         
81         /**
82          * Set the current cluster configuration.
83          * @param cluster  The cluster configuration.
84          */
85         public void setClusterConfiguration(ClusterConfiguration cluster) {
86                 this.cluster = cluster;
87                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
88         }
89
90         /**
91          * Return the number of tubes in the cluster.
92          * @return Number of tubes in the current cluster.
93          */
94         @Override
95         public int getClusterCount() {
96                 return cluster.getClusterCount();
97         }
98         
99         /**
100          * Get the cluster scaling.  A value of 1.0 indicates that the tubes are packed
101          * touching each other, larger values separate the tubes and smaller values
102          * pack inside each other.
103          */
104         public double getClusterScale() {
105                 return clusterScale;
106         }
107
108         /**
109          * Set the cluster scaling.
110          * @see #getClusterScale()
111          */
112         public void setClusterScale(double scale) {
113                 scale = Math.max(scale,0);
114                 if (MathUtil.equals(clusterScale, scale))
115                         return;
116                 clusterScale = scale;
117                 fireComponentChangeEvent(new ComponentChangeEvent(this,ComponentChangeEvent.MASS_CHANGE));
118         }
119         
120         
121
122         /**
123          * @return the clusterRotation
124          */
125         public double getClusterRotation() {
126                 return clusterRotation;
127         }
128
129
130         /**
131          * @param rotation the clusterRotation to set
132          */
133         public void setClusterRotation(double rotation) {
134                 rotation = MathUtil.reduce180(rotation);
135                 if (clusterRotation == rotation)
136                         return;
137                 this.clusterRotation = rotation;
138                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
139         }
140
141
142         /**
143          * Return the distance between the closest two cluster inner tube center points.
144          * This is equivalent to the cluster scale multiplied by the tube diameter.
145          */
146         @Override
147         public double getClusterSeparation() {
148                 return 2*getOuterRadius()*clusterScale;
149         }
150         
151         
152         public List<Coordinate> getClusterPoints() {
153                 List<Coordinate> list = new ArrayList<Coordinate>(getClusterCount());
154                 List<Double> points = cluster.getPoints(clusterRotation - getRadialDirection());
155                 double separation = getClusterSeparation();
156                 for (int i=0; i < points.size()/2; i++) {
157                         list.add(new Coordinate(0,points.get(2*i)*separation,points.get(2*i+1)*separation));
158                 }
159                 return list;
160         }
161         
162         
163         @Override
164         public Coordinate[] shiftCoordinates(Coordinate[] array) {
165                 array = super.shiftCoordinates(array);
166                 
167                 int count = getClusterCount();
168                 if (count == 1)
169                         return array;
170
171                 List<Coordinate> points = getClusterPoints();
172                 assert(points.size() == count);
173                 Coordinate[] newArray = new Coordinate[array.length * count];
174                 for (int i=0; i < array.length; i++) {
175                         for (int j=0; j < count; j++) {
176                                 newArray[i*count + j] = array[i].add(points.get(j));
177                         }
178                 }
179                 
180                 return newArray;
181         }
182         
183
184
185
186         ////////////////  Motor mount  /////////////////
187         
188         @Override
189         public boolean isMotorMount() {
190                 return motorMount;
191         }
192
193         @Override
194         public void setMotorMount(boolean mount) {
195                 if (motorMount == mount)
196                         return;
197                 motorMount = mount;
198                 fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
199         }
200         
201         @Override
202         public Motor getMotor(String id) {
203                 return motors.get(id);
204         }
205
206         @Override
207         public void setMotor(String id, Motor motor) {
208                 Motor current = motors.get(id);
209                 if ((motor == null && current == null) ||
210                                 (motor != null && motor.equals(current)))
211                         return;
212                 motors.put(id, motor);
213                 fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
214         }
215
216         @Override
217         public double getMotorDelay(String id) {
218                 Double delay = ejectionDelays.get(id);
219                 if (delay == null)
220                         return Motor.PLUGGED;
221                 return delay;
222         }
223
224         @Override
225         public void setMotorDelay(String id, double delay) {
226                 ejectionDelays.put(id, delay);
227                 fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
228         }
229         
230         @Override
231         public int getMotorCount() {
232                 return getClusterCount();
233         }
234         
235         @Override
236         public double getMotorMountDiameter() {
237                 return getInnerRadius()*2;
238         }
239
240         @Override
241         public IgnitionEvent getIgnitionEvent() {
242                 return ignitionEvent;
243         }
244
245         @Override
246         public void setIgnitionEvent(IgnitionEvent event) {
247                 if (ignitionEvent == event)
248                         return;
249                 ignitionEvent = event;
250                 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
251         }
252
253         
254         @Override
255         public double getIgnitionDelay() {
256                 return ignitionDelay;
257         }
258
259         @Override
260         public void setIgnitionDelay(double delay) {
261                 if (MathUtil.equals(delay, ignitionDelay))
262                         return;
263                 ignitionDelay = delay;
264                 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
265         }
266
267         
268         @Override
269         public double getMotorOverhang() {
270                 return overhang;
271         }
272         
273         @Override
274         public void setMotorOverhang(double overhang) {
275                 if (MathUtil.equals(this.overhang, overhang))
276                         return;
277                 this.overhang = overhang;
278                 fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
279         }
280         
281         
282         
283         /*
284          * (non-Javadoc)
285          * Copy the motor and ejection delay HashMaps.
286          * 
287          * @see rocketcomponent.RocketComponent#copy()
288          */
289         @SuppressWarnings("unchecked")
290         @Override
291         public RocketComponent copy() {
292                 RocketComponent c = super.copy();
293                 ((InnerTube)c).motors = (HashMap<String,Motor>) motors.clone();
294                 ((InnerTube)c).ejectionDelays = (HashMap<String,Double>) ejectionDelays.clone();
295                 return c;
296         }
297
298 }