Updated Spanish translations
[debian/openrocket] / src / net / sf / openrocket / rocketcomponent / BodyTube.java
1 package net.sf.openrocket.rocketcomponent;
2
3 import net.sf.openrocket.l10n.Translator;
4 import net.sf.openrocket.motor.Motor;
5 import net.sf.openrocket.startup.Application;
6 import net.sf.openrocket.util.Coordinate;
7 import net.sf.openrocket.util.MathUtil;
8
9 import java.util.ArrayList;
10 import java.util.Collection;
11 import java.util.HashMap;
12
13
14 /**
15  * Rocket body tube component.  Has only two parameters, a radius and length.
16  * 
17  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
18  */
19
20 public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial {
21         private static final Translator trans = Application.getTranslator();
22
23         private double radius = 0;
24         private boolean autoRadius = false; // Radius chosen automatically based on parent component
25         
26         // When changing the inner radius, thickness is modified
27         
28         private boolean motorMount = false;
29         private HashMap<String, Double> ejectionDelays = new HashMap<String, Double>();
30         private HashMap<String, Motor> motors = new HashMap<String, Motor>();
31         private IgnitionEvent ignitionEvent = IgnitionEvent.AUTOMATIC;
32         private double ignitionDelay = 0;
33         private double overhang = 0;
34         
35         
36
37         public BodyTube() {
38                 super();
39                 this.length = 8 * DEFAULT_RADIUS;
40                 this.radius = DEFAULT_RADIUS;
41                 this.autoRadius = true;
42         }
43         
44         public BodyTube(double length, double radius) {
45                 super();
46                 this.radius = Math.max(radius, 0);
47                 this.length = Math.max(length, 0);
48         }
49         
50         
51         public BodyTube(double length, double radius, boolean filled) {
52                 this(length, radius);
53                 this.filled = filled;
54         }
55         
56         public BodyTube(double length, double radius, double thickness) {
57                 this(length, radius);
58                 this.filled = false;
59                 this.thickness = thickness;
60         }
61         
62         
63         /************  Get/set component parameter methods ************/
64         
65         /**
66          * Return the outer radius of the body tube.
67      * 
68      * @return  the outside radius of the tube
69          */
70     @Override
71         public double getOuterRadius () {
72                 if (autoRadius) {
73                         // Return auto radius from front or rear
74                         double r = -1;
75                         SymmetricComponent c = this.getPreviousSymmetricComponent();
76                         if (c != null) {
77                                 r = c.getFrontAutoRadius();
78                         }
79                         if (r < 0) {
80                                 c = this.getNextSymmetricComponent();
81                                 if (c != null) {
82                                         r = c.getRearAutoRadius();
83                                 }
84                         }
85                         if (r < 0)
86                                 r = DEFAULT_RADIUS;
87                         return r;
88                 }
89                 return radius;
90         }
91         
92         
93         /**
94          * Set the outer radius of the body tube.  If the radius is less than the wall thickness,
95          * the wall thickness is decreased accordingly of the value of the radius.
96          * This method sets the automatic radius off.
97      * 
98      * @param radius  the outside radius in standard units
99          */
100     @Override
101         public void setOuterRadius (double radius) {
102                 if ((this.radius == radius) && (autoRadius == false))
103                         return;
104                 
105                 this.autoRadius = false;
106                 this.radius = Math.max(radius, 0);
107                 
108                 if (this.thickness > this.radius)
109                         this.thickness = this.radius;
110                 fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
111         }
112         
113         
114         /**
115          * Returns whether the radius is selected automatically or not.
116          * Returns false also in case automatic radius selection is not possible.
117          */
118         public boolean isRadiusAutomatic() {
119                 return autoRadius;
120         }
121         
122         /**
123          * Sets whether the radius is selected automatically or not.  
124          */
125         public void setRadiusAutomatic(boolean auto) {
126                 if (autoRadius == auto)
127                         return;
128                 
129                 autoRadius = auto;
130                 fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
131         }
132         
133         
134         @Override
135         public double getAftRadius() {  return getOuterRadius(); }
136         @Override
137         public double getForeRadius() { return getOuterRadius(); }
138         @Override
139         public boolean isAftRadiusAutomatic() {
140                 return isRadiusAutomatic();
141         }
142         
143         @Override
144         public boolean isForeRadiusAutomatic() {
145                 return isRadiusAutomatic();
146         }
147         
148         
149
150         @Override
151         protected double getFrontAutoRadius() {
152                 if (isRadiusAutomatic()) {
153                         // Search for previous SymmetricComponent
154                         SymmetricComponent c = this.getPreviousSymmetricComponent();
155                         if (c != null) {
156                                 return c.getFrontAutoRadius();
157                         } else {
158                                 return -1;
159                         }
160                 }
161                 return getOuterRadius();
162         }
163         
164         @Override
165         protected double getRearAutoRadius() {
166                 if (isRadiusAutomatic()) {
167                         // Search for next SymmetricComponent
168                         SymmetricComponent c = this.getNextSymmetricComponent();
169                         if (c != null) {
170                                 return c.getRearAutoRadius();
171                         } else {
172                                 return -1;
173                         }
174                 }
175                 return getOuterRadius();
176         }
177         
178         
179
180
181         
182         
183         
184         
185     @Override   
186         public double getInnerRadius() {
187                 if (filled)
188                         return 0;
189                 return Math.max(getOuterRadius()-thickness, 0);
190         }
191         
192     @Override
193         public void setInnerRadius(double r) {
194                 setThickness(getOuterRadius()-r);
195         }
196         
197         
198
199
200         /**
201          * Return the component name.
202          */
203         @Override
204         public String getComponentName() {
205                 //// Body tube
206                 return trans.get("BodyTube.BodyTube");
207         }
208
209     /**
210      * Accept a visitor to this BodyTube in the component hierarchy.
211      * 
212      * @param theVisitor  the visitor that will be called back with a reference to this BodyTube
213      */
214     @Override 
215     public void accept (final ComponentVisitor theVisitor) {
216         theVisitor.visit(this);
217     }
218
219
220         /************ Component calculations ***********/
221         
222         // From SymmetricComponent
223         /**
224          * Returns the outer radius at the position x.  This returns the same value as getOuterRadius().
225          */
226         @Override
227         public double getRadius(double x) {
228                 return getOuterRadius();
229         }
230         
231         /**
232          * Returns the inner radius at the position x.  If the tube is filled, returns always zero.
233          */
234         @Override
235         public double getInnerRadius(double x) {
236                 if (filled)
237                         return 0.0;
238                 else
239                         return Math.max(getOuterRadius()-thickness,0);
240         }
241         
242         
243         /**
244          * Returns the body tube's center of gravity.
245          */
246         @Override
247         public Coordinate getComponentCG() {
248                 return new Coordinate(length / 2, 0, 0, getComponentMass());
249         }
250         
251         /**
252          * Returns the body tube's volume.
253          */
254         @Override
255         public double getComponentVolume() {
256                 double r = getOuterRadius();
257                 if (filled)
258                         return getFilledVolume(r, length);
259                 else
260                         return getFilledVolume(r, length) - getFilledVolume(getInnerRadius(0), length);
261         }
262         
263         
264         @Override
265         public double getLongitudinalUnitInertia() {
266                 // 1/12 * (3 * (r1^2 + r2^2) + h^2)
267                 return (3 * (MathUtil.pow2(getInnerRadius())) + MathUtil.pow2(getOuterRadius()) +
268                                 MathUtil.pow2(getLength())) / 12;
269         }
270         
271         @Override
272         public double getRotationalUnitInertia() {
273                 // 1/2 * (r1^2 + r2^2)
274                 return (MathUtil.pow2(getInnerRadius()) + MathUtil.pow2(getOuterRadius()))/2;
275         }
276         
277         
278
279
280         /**
281          * Helper function for cylinder volume.
282          */
283         private static double getFilledVolume(double r, double l) {
284                 return Math.PI * r * r * l;
285         }
286         
287         
288         /**
289          * Adds bounding coordinates to the given set.  The body tube will fit within the
290          * convex hull of the points.
291          * 
292          * Currently the points are simply a rectangular box around the body tube.
293          */
294         @Override
295         public Collection<Coordinate> getComponentBounds() {
296                 Collection<Coordinate> bounds = new ArrayList<Coordinate>(8);
297                 double r = getOuterRadius();
298                 addBound(bounds, 0, r);
299                 addBound(bounds, length, r);
300                 return bounds;
301         }
302         
303         
304
305         /**
306          * Check whether the given type can be added to this component.  BodyTubes allow any
307          * InternalComponents or ExternalComponents, excluding BodyComponents, to be added.
308          * 
309          * @param type  The RocketComponent class type to add.
310          * @return      Whether such a component can be added.
311          */
312         @Override
313         public boolean isCompatible(Class<? extends RocketComponent> type) {
314                 if (InternalComponent.class.isAssignableFrom(type))
315                         return true;
316                 if (ExternalComponent.class.isAssignableFrom(type) &&
317                                 !BodyComponent.class.isAssignableFrom(type))
318                         return true;
319                 return false;
320         }
321         
322         ////////////////  Motor mount  /////////////////
323         
324         @Override
325         public boolean isMotorMount() {
326                 return motorMount;
327         }
328         
329         @Override
330         public void setMotorMount(boolean mount) {
331                 if (motorMount == mount)
332                         return;
333                 motorMount = mount;
334                 fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
335         }
336         
337         @Override
338         public Motor getMotor(String id) {
339                 if (id == null)
340                         return null;
341                 
342                 // Check whether the id is valid for the current rocket
343                 RocketComponent root = this.getRoot();
344                 if (!(root instanceof Rocket))
345                         return null;
346                 if (!((Rocket) root).isMotorConfigurationID(id))
347                         return null;
348                 
349                 return motors.get(id);
350         }
351         
352         @Override
353         public void setMotor(String id, Motor motor) {
354                 if (id == null) {
355                         if (motor != null) {
356                                 throw new IllegalArgumentException("Cannot set non-null motor for id null");
357                         }
358                 }
359                 Motor current = motors.get(id);
360                 if ((motor == null && current == null) ||
361                                 (motor != null && motor.equals(current)))
362                         return;
363                 motors.put(id, motor);
364                 fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
365         }
366         
367         @Override
368         public double getMotorDelay(String id) {
369                 Double delay = ejectionDelays.get(id);
370                 if (delay == null)
371                         return Motor.PLUGGED;
372                 return delay;
373         }
374         
375         @Override
376         public void setMotorDelay(String id, double delay) {
377                 ejectionDelays.put(id, delay);
378                 fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
379         }
380         
381         @Override
382         public int getMotorCount() {
383                 return 1;
384         }
385         
386         @Override
387         public double getMotorMountDiameter() {
388                 return getInnerRadius() * 2;
389         }
390         
391         @Override
392         public IgnitionEvent getIgnitionEvent() {
393                 return ignitionEvent;
394         }
395         
396         @Override
397         public void setIgnitionEvent(IgnitionEvent event) {
398                 if (ignitionEvent == event)
399                         return;
400                 ignitionEvent = event;
401                 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
402         }
403         
404         
405         @Override
406         public double getIgnitionDelay() {
407                 return ignitionDelay;
408         }
409         
410         @Override
411         public void setIgnitionDelay(double delay) {
412                 if (MathUtil.equals(delay, ignitionDelay))
413                         return;
414                 ignitionDelay = delay;
415                 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
416         }
417         
418         
419         @Override
420         public double getMotorOverhang() {
421                 return overhang;
422         }
423         
424         @Override
425         public void setMotorOverhang(double overhang) {
426                 if (MathUtil.equals(this.overhang, overhang))
427                         return;
428                 this.overhang = overhang;
429                 fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
430         }
431         
432         
433         @Override
434         public Coordinate getMotorPosition(String id) {
435                 Motor motor = motors.get(id);
436                 if (motor == null) {
437                         throw new IllegalArgumentException("No motor with id " + id + " defined.");
438                 }
439                 
440                 return new Coordinate(this.getLength() - motor.getLength() + this.getMotorOverhang());
441         }
442         
443         
444
445
446         /*
447          * (non-Javadoc)
448          * Copy the motor and ejection delay HashMaps.
449          * 
450          * @see rocketcomponent.RocketComponent#copy()
451          */
452         @SuppressWarnings("unchecked")
453         @Override
454         protected RocketComponent copyWithOriginalID() {
455                 RocketComponent c = super.copyWithOriginalID();
456                 ((BodyTube) c).motors = (HashMap<String, Motor>) motors.clone();
457                 ((BodyTube) c).ejectionDelays = (HashMap<String, Double>) ejectionDelays.clone();
458                 return c;
459         }
460 }