Initial commit
[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         @Override
143         public double getClusterSeparation() {
144                 return 2*getOuterRadius()*clusterScale;
145         }
146         
147         
148         public List<Coordinate> getClusterPoints() {
149                 List<Coordinate> list = new ArrayList<Coordinate>(getClusterCount());
150                 List<Double> points = cluster.getPoints(clusterRotation - getRadialDirection());
151                 double separation = getClusterSeparation();
152                 for (int i=0; i < points.size()/2; i++) {
153                         list.add(new Coordinate(0,points.get(2*i)*separation,points.get(2*i+1)*separation));
154                 }
155                 return list;
156         }
157         
158         
159         @Override
160         public Coordinate[] shiftCoordinates(Coordinate[] array) {
161                 array = super.shiftCoordinates(array);
162                 
163                 int count = getClusterCount();
164                 if (count == 1)
165                         return array;
166
167                 List<Coordinate> points = getClusterPoints();
168                 assert(points.size() == count);
169                 Coordinate[] newArray = new Coordinate[array.length * count];
170                 for (int i=0; i < array.length; i++) {
171                         for (int j=0; j < count; j++) {
172                                 newArray[i*count + j] = array[i].add(points.get(j));
173                         }
174                 }
175                 
176                 return newArray;
177         }
178         
179
180
181
182         ////////////////  Motor mount  /////////////////
183         
184         @Override
185         public boolean isMotorMount() {
186                 return motorMount;
187         }
188
189         @Override
190         public void setMotorMount(boolean mount) {
191                 if (motorMount == mount)
192                         return;
193                 motorMount = mount;
194                 fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
195         }
196         
197         @Override
198         public Motor getMotor(String id) {
199                 return motors.get(id);
200         }
201
202         @Override
203         public void setMotor(String id, Motor motor) {
204                 Motor current = motors.get(id);
205                 if ((motor == null && current == null) ||
206                                 (motor != null && motor.equals(current)))
207                         return;
208                 motors.put(id, motor);
209                 fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
210         }
211
212         @Override
213         public double getMotorDelay(String id) {
214                 Double delay = ejectionDelays.get(id);
215                 if (delay == null)
216                         return Motor.PLUGGED;
217                 return delay;
218         }
219
220         @Override
221         public void setMotorDelay(String id, double delay) {
222                 ejectionDelays.put(id, delay);
223                 fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
224         }
225         
226         @Override
227         public int getMotorCount() {
228                 return getClusterCount();
229         }
230         
231         @Override
232         public double getMotorMountDiameter() {
233                 return getInnerRadius()*2;
234         }
235
236         @Override
237         public IgnitionEvent getIgnitionEvent() {
238                 return ignitionEvent;
239         }
240
241         @Override
242         public void setIgnitionEvent(IgnitionEvent event) {
243                 if (ignitionEvent == event)
244                         return;
245                 ignitionEvent = event;
246                 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
247         }
248
249         
250         @Override
251         public double getIgnitionDelay() {
252                 return ignitionDelay;
253         }
254
255         @Override
256         public void setIgnitionDelay(double delay) {
257                 if (MathUtil.equals(delay, ignitionDelay))
258                         return;
259                 ignitionDelay = delay;
260                 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
261         }
262
263         
264         @Override
265         public double getMotorOverhang() {
266                 return overhang;
267         }
268         
269         @Override
270         public void setMotorOverhang(double overhang) {
271                 if (MathUtil.equals(this.overhang, overhang))
272                         return;
273                 this.overhang = overhang;
274                 fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
275         }
276 }