package net.sf.openrocket.rocketcomponent;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.MathUtil;
/**
* RecoveryDevice is a class representing devices that slow down descent.
* Recovery devices report that they have no aerodynamic effect, since they
* are within the rocket during ascent.
* <p>
* A recovery device includes a surface material of which it is made of.
* The mass of the component is calculated based on the material and the
* area of the device from {@link #getArea()}. {@link #getComponentMass()}
* may be overridden if additional mass needs to be included.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public abstract class RecoveryDevice extends MassObject implements FlightConfigurableComponent {
private double cd = Parachute.DEFAULT_CD;
private boolean cdAutomatic = true;
private Material.Surface material;
private FlightConfigurationImpl<DeploymentConfiguration> deploymentConfigurations;
public RecoveryDevice() {
this.deploymentConfigurations = new FlightConfigurationImpl<DeploymentConfiguration>(this, ComponentChangeEvent.EVENT_CHANGE, new DeploymentConfiguration());
setMaterial(Application.getPreferences().getDefaultComponentMaterial(RecoveryDevice.class, Material.Type.SURFACE));
}
public abstract double getArea();
public abstract double getComponentCD(double mach);
public double getCD() {
return getCD(0);
}
public double getCD(double mach) {
if (cdAutomatic)
cd = getComponentCD(mach);
return cd;
}
public void setCD(double cd) {
if (MathUtil.equals(this.cd, cd) && !isCDAutomatic())
return;
this.cd = cd;
this.cdAutomatic = false;
fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
}
public boolean isCDAutomatic() {
return cdAutomatic;
}
public void setCDAutomatic(boolean auto) {
if (cdAutomatic == auto)
return;
this.cdAutomatic = auto;
fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
}
public final Material getMaterial() {
return material;
}
public final void setMaterial(Material mat) {
if (!(mat instanceof Material.Surface)) {
throw new IllegalArgumentException("Attempted to set non-surface material " + mat);
}
if (mat.equals(material))
return;
this.material = (Material.Surface) mat;
clearPreset();
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
}
public FlightConfiguration<DeploymentConfiguration> getDeploymentConfiguration() {
return deploymentConfigurations;
}
@Override
public void cloneFlightConfiguration(String oldConfigId, String newConfigId) {
deploymentConfigurations.cloneFlightConfiguration(oldConfigId, newConfigId);
}
@Override
public double getComponentMass() {
return getArea() * getMaterial().getDensity();
}
@Override
protected void loadFromPreset(ComponentPreset preset) {
if (preset.has(ComponentPreset.MATERIAL)) {
Material m = preset.get(ComponentPreset.MATERIAL);
this.material = (Material.Surface) m;
}
super.loadFromPreset(preset);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
@Override
protected RocketComponent copyWithOriginalID() {
RecoveryDevice copy = (RecoveryDevice) super.copyWithOriginalID();
copy.deploymentConfigurations = new FlightConfigurationImpl<DeploymentConfiguration>(deploymentConfigurations,
copy, ComponentChangeEvent.EVENT_CHANGE);
return copy;
}
}