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