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