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