create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / rocketcomponent / RecoveryDevice.java
1 package net.sf.openrocket.rocketcomponent;
2
3 import net.sf.openrocket.l10n.Translator;
4 import net.sf.openrocket.material.Material;
5 import net.sf.openrocket.preset.ComponentPreset;
6 import net.sf.openrocket.simulation.FlightEvent;
7 import net.sf.openrocket.startup.Application;
8 import net.sf.openrocket.util.MathUtil;
9 import net.sf.openrocket.util.Pair;
10
11
12 /**
13  * RecoveryDevice is a class representing devices that slow down descent.
14  * Recovery devices report that they have no aerodynamic effect, since they
15  * are within the rocket during ascent.
16  * <p>
17  * A recovery device includes a surface material of which it is made of.
18  * The mass of the component is calculated based on the material and the
19  * area of the device from {@link #getArea()}.  {@link #getComponentMass()}
20  * may be overridden if additional mass needs to be included.
21  * 
22  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
23  */
24 public abstract class RecoveryDevice extends MassObject {
25         private static final Translator trans = Application.getTranslator();
26         
27         public static enum DeployEvent {
28                 LAUNCH(trans.get("RecoveryDevice.DeployEvent.LAUNCH")) {
29                         @Override
30                         public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
31                                 return e.getType() == FlightEvent.Type.LAUNCH;
32                         }
33                 },
34                 EJECTION(trans.get("RecoveryDevice.DeployEvent.EJECTION")) {
35                         @Override
36                         public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
37                                 if (e.getType() != FlightEvent.Type.EJECTION_CHARGE)
38                                         return false;
39                                 RocketComponent charge = e.getSource();
40                                 return charge.getStageNumber() == source.getStageNumber();
41                         }
42                 },
43                 APOGEE(trans.get("RecoveryDevice.DeployEvent.APOGEE")) {
44                         @Override
45                         public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
46                                 return e.getType() == FlightEvent.Type.APOGEE;
47                         }
48                 },
49                 ALTITUDE(trans.get("RecoveryDevice.DeployEvent.ALTITUDE")) {
50                         @SuppressWarnings("unchecked")
51                         @Override
52                         public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
53                                 if (e.getType() != FlightEvent.Type.ALTITUDE)
54                                         return false;
55                                 
56                                 double alt = ((RecoveryDevice) source).getDeployAltitude();
57                                 Pair<Double, Double> altitude = (Pair<Double, Double>) e.getData();
58                                 
59                                 return (altitude.getU() >= alt) && (altitude.getV() <= alt);
60                         }
61                 },
62                 LOWER_STAGE_SEPARATION(trans.get("RecoveryDevice.DeployEvent.LOWER_STAGE_SEPARATION")) {
63                         @Override
64                         public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
65                                 if (e.getType() != FlightEvent.Type.STAGE_SEPARATION)
66                                         return false;
67                                 
68                                 int separation = e.getSource().getStageNumber();
69                                 int current = source.getStageNumber();
70                                 return (current + 1 == separation);
71                         }
72                 },
73                 NEVER(trans.get("RecoveryDevice.DeployEvent.NEVER")) {
74                         @Override
75                         public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
76                                 return false;
77                         }
78                 };
79                 
80                 private final String description;
81                 
82                 DeployEvent(String description) {
83                         this.description = description;
84                 }
85                 
86                 public abstract boolean isActivationEvent(FlightEvent e, RocketComponent source);
87                 
88                 @Override
89                 public String toString() {
90                         return description;
91                 }
92                 
93         }
94         
95         
96         private DeployEvent deployEvent = DeployEvent.EJECTION;
97         private double deployAltitude = 200;
98         private double deployDelay = 0;
99         
100         private double cd = Parachute.DEFAULT_CD;
101         private boolean cdAutomatic = true;
102         
103         
104         private Material.Surface material;
105         
106         
107         public RecoveryDevice() {
108                 this(Application.getPreferences().getDefaultComponentMaterial(RecoveryDevice.class, Material.Type.SURFACE));
109         }
110         
111         public RecoveryDevice(Material material) {
112                 super();
113                 setMaterial(material);
114         }
115         
116         public RecoveryDevice(double length, double radius, Material material) {
117                 super(length, radius);
118                 setMaterial(material);
119         }
120         
121         
122         
123         
124         public abstract double getArea();
125         
126         public abstract double getComponentCD(double mach);
127         
128         
129         
130         public double getCD() {
131                 return getCD(0);
132         }
133         
134         public double getCD(double mach) {
135                 if (cdAutomatic)
136                         cd = getComponentCD(mach);
137                 return cd;
138         }
139         
140         public void setCD(double cd) {
141                 if (MathUtil.equals(this.cd, cd) && !isCDAutomatic())
142                         return;
143                 this.cd = cd;
144                 this.cdAutomatic = false;
145                 fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
146         }
147         
148         
149         public boolean isCDAutomatic() {
150                 return cdAutomatic;
151         }
152         
153         public void setCDAutomatic(boolean auto) {
154                 if (cdAutomatic == auto)
155                         return;
156                 this.cdAutomatic = auto;
157                 fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
158         }
159         
160         
161         
162         public final Material getMaterial() {
163                 return material;
164         }
165         
166         public final void setMaterial(Material mat) {
167                 if (!(mat instanceof Material.Surface)) {
168                         throw new IllegalArgumentException("Attempted to set non-surface material " + mat);
169                 }
170                 if (mat.equals(material))
171                         return;
172                 this.material = (Material.Surface) mat;
173                 clearPreset();
174                 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
175         }
176         
177         
178         
179         
180         public DeployEvent getDeployEvent() {
181                 return deployEvent;
182         }
183         
184         public void setDeployEvent(DeployEvent deployEvent) {
185                 if (this.deployEvent == deployEvent)
186                         return;
187                 this.deployEvent = deployEvent;
188                 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
189         }
190         
191         
192         public double getDeployAltitude() {
193                 return deployAltitude;
194         }
195         
196         public void setDeployAltitude(double deployAltitude) {
197                 if (MathUtil.equals(this.deployAltitude, deployAltitude))
198                         return;
199                 this.deployAltitude = deployAltitude;
200                 if (getDeployEvent() == DeployEvent.ALTITUDE)
201                         fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
202                 else
203                         fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
204         }
205         
206         
207         public double getDeployDelay() {
208                 return deployDelay;
209         }
210         
211         public void setDeployDelay(double delay) {
212                 delay = MathUtil.max(delay, 0);
213                 if (MathUtil.equals(this.deployDelay, delay))
214                         return;
215                 this.deployDelay = delay;
216                 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
217         }
218         
219         
220         
221         @Override
222         public double getComponentMass() {
223                 return getArea() * getMaterial().getDensity();
224         }
225
226         @Override
227         protected void loadFromPreset(ComponentPreset preset) {
228                 if ( preset.has(ComponentPreset.MATERIAL)) {
229                         Material m = preset.get(ComponentPreset.MATERIAL);
230                         this.material = (Material.Surface)m;
231                 }
232                 super.loadFromPreset(preset);
233                 fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
234
235         }
236
237 }