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