1 package net.sf.openrocket.rocketcomponent;
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 import net.sf.openrocket.util.Prefs;
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.
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.
22 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
24 public abstract class RecoveryDevice extends MassObject {
25 private static final Translator trans = Application.getTranslator();
27 public static enum DeployEvent {
28 //// Launch (plus NN seconds)
29 LAUNCH(trans.get("RecoveryDevice.DeployEvent.LAUNCH")) {
31 public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
32 return e.getType() == FlightEvent.Type.LAUNCH;
35 //// First ejection charge of this stage
36 EJECTION(trans.get("RecoveryDevice.DeployEvent.EJECTION")) {
38 public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
39 if (e.getType() != FlightEvent.Type.EJECTION_CHARGE)
41 RocketComponent charge = e.getSource();
42 return charge.getStageNumber() == source.getStageNumber();
46 APOGEE(trans.get("RecoveryDevice.DeployEvent.APOGEE")) {
48 public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
49 return e.getType() == FlightEvent.Type.APOGEE;
52 //// Specific altitude during descent
53 ALTITUDE(trans.get("RecoveryDevice.DeployEvent.ALTITUDE")) {
54 @SuppressWarnings("unchecked")
56 public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
57 if (e.getType() != FlightEvent.Type.ALTITUDE)
60 double alt = ((RecoveryDevice)source).getDeployAltitude();
61 Pair<Double,Double> altitude = (Pair<Double,Double>)e.getData();
63 return (altitude.getU() >= alt) && (altitude.getV() <= alt);
67 NEVER(trans.get("RecoveryDevice.DeployEvent.NEVER")) {
69 public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
75 private final String description;
77 DeployEvent(String description) {
78 this.description = description;
81 public abstract boolean isActivationEvent(FlightEvent e, RocketComponent source);
84 public String toString() {
91 private DeployEvent deployEvent = DeployEvent.EJECTION;
92 private double deployAltitude = 200;
93 private double deployDelay = 0;
95 private double cd = Parachute.DEFAULT_CD;
96 private boolean cdAutomatic = true;
99 private Material.Surface material;
102 public RecoveryDevice() {
103 this(Prefs.getDefaultComponentMaterial(RecoveryDevice.class, Material.Type.SURFACE));
106 public RecoveryDevice(Material material) {
108 setMaterial(material);
111 public RecoveryDevice(double length, double radius, Material material) {
112 super(length, radius);
113 setMaterial(material);
119 public abstract double getArea();
121 public abstract double getComponentCD(double mach);
125 public double getCD() {
129 public double getCD(double mach) {
131 cd = getComponentCD(mach);
135 public void setCD(double cd) {
136 if (MathUtil.equals(this.cd, cd) && !isCDAutomatic())
139 this.cdAutomatic = false;
140 fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
144 public boolean isCDAutomatic() {
148 public void setCDAutomatic(boolean auto) {
149 if (cdAutomatic == auto)
151 this.cdAutomatic = auto;
152 fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
157 public final Material getMaterial() {
161 public final void setMaterial(Material mat) {
162 if (!(mat instanceof Material.Surface)) {
163 throw new IllegalArgumentException("Attempted to set non-surface material "+mat);
165 if (mat.equals(material))
167 this.material = (Material.Surface)mat;
168 fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
174 public DeployEvent getDeployEvent() {
178 public void setDeployEvent(DeployEvent deployEvent) {
179 if (this.deployEvent == deployEvent)
181 this.deployEvent = deployEvent;
182 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
186 public double getDeployAltitude() {
187 return deployAltitude;
190 public void setDeployAltitude(double deployAltitude) {
191 if (MathUtil.equals(this.deployAltitude, deployAltitude))
193 this.deployAltitude = deployAltitude;
194 if (getDeployEvent() == DeployEvent.ALTITUDE)
195 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
197 fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
201 public double getDeployDelay() {
205 public void setDeployDelay(double delay) {
206 delay = MathUtil.max(delay, 0);
207 if (MathUtil.equals(this.deployDelay, delay))
209 this.deployDelay = delay;
210 fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
216 public double getComponentMass() {
217 return getArea() * getMaterial().getDensity();