1 package net.sf.openrocket.rocketcomponent;
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;
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.
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.
20 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
22 public abstract class RecoveryDevice extends MassObject {
24 public static enum DeployEvent {
25 LAUNCH("Launch (plus NN seconds)") {
27 public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
28 return e.getType() == FlightEvent.Type.LAUNCH;
31 EJECTION("First ejection charge of this stage") {
33 public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
34 if (e.getType() != FlightEvent.Type.EJECTION_CHARGE)
36 RocketComponent charge = e.getSource();
37 return charge.getStageNumber() == source.getStageNumber();
42 public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
43 return e.getType() == FlightEvent.Type.APOGEE;
46 ALTITUDE("Specific altitude during descent") {
47 @SuppressWarnings("unchecked")
49 public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
50 if (e.getType() != FlightEvent.Type.ALTITUDE)
53 double alt = ((RecoveryDevice)source).getDeployAltitude();
54 Pair<Double,Double> altitude = (Pair<Double,Double>)e.getData();
56 return (altitude.getU() >= alt) && (altitude.getV() <= alt);
61 public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
67 private final String description;
69 DeployEvent(String description) {
70 this.description = description;
73 public abstract boolean isActivationEvent(FlightEvent e, RocketComponent source);
76 public String toString() {
83 private DeployEvent deployEvent = DeployEvent.EJECTION;
84 private double deployAltitude = 200;
85 private double deployDelay = 0;
87 private double cd = Parachute.DEFAULT_CD;
88 private boolean cdAutomatic = true;
91 private Material.Surface material;
94 public RecoveryDevice() {
95 this(Prefs.getDefaultComponentMaterial(RecoveryDevice.class, Material.Type.SURFACE));
98 public RecoveryDevice(Material material) {
100 setMaterial(material);
103 public RecoveryDevice(double length, double radius, Material material) {
104 super(length, radius);
105 setMaterial(material);
111 public abstract double getArea();
113 public abstract double getComponentCD(double mach);
117 public double getCD() {
121 public double getCD(double mach) {
123 cd = getComponentCD(mach);
127 public void setCD(double cd) {
128 if (MathUtil.equals(this.cd, cd) && !isCDAutomatic())
131 this.cdAutomatic = false;
132 fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
136 public boolean isCDAutomatic() {
140 public void setCDAutomatic(boolean auto) {
141 if (cdAutomatic == auto)
143 this.cdAutomatic = auto;
144 fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
149 public final Material getMaterial() {
153 public final void setMaterial(Material mat) {
154 if (!(mat instanceof Material.Surface)) {
155 throw new IllegalArgumentException("Attempted to set non-surface material "+mat);
157 if (mat.equals(material))
159 this.material = (Material.Surface)mat;
160 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
166 public DeployEvent getDeployEvent() {
170 public void setDeployEvent(DeployEvent deployEvent) {
171 if (this.deployEvent == deployEvent)
173 this.deployEvent = deployEvent;
174 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
178 public double getDeployAltitude() {
179 return deployAltitude;
182 public void setDeployAltitude(double deployAltitude) {
183 if (MathUtil.equals(this.deployAltitude, deployAltitude))
185 this.deployAltitude = deployAltitude;
186 if (getDeployEvent() == DeployEvent.ALTITUDE)
187 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
189 fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
193 public double getDeployDelay() {
197 public void setDeployDelay(double delay) {
198 delay = MathUtil.max(delay, 0);
199 if (MathUtil.equals(this.deployDelay, delay))
201 this.deployDelay = delay;
202 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
208 public double getComponentMass() {
209 return getArea() * getMaterial().getDensity();