create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / file / rocksim / importt / RecoveryDeviceHandler.java
1 /*
2  * RecoveryDeviceHandler.java
3  */
4 package net.sf.openrocket.file.rocksim.importt;
5
6 import net.sf.openrocket.aerodynamics.WarningSet;
7 import net.sf.openrocket.file.rocksim.RocksimCommonConstants;
8 import net.sf.openrocket.file.rocksim.RocksimDensityType;
9 import net.sf.openrocket.material.Material;
10 import net.sf.openrocket.rocketcomponent.RecoveryDevice;
11 import net.sf.openrocket.rocketcomponent.RocketComponent;
12 import org.xml.sax.SAXException;
13
14 import java.util.HashMap;
15
16 /**
17  * A handler specific to streamers and parachutes.  This is done because Rocksim allows any type of material to be
18  * used as a recovery device, which causes oddities with respect to densities.  Density computation is overridden
19  * here to try to correctly compute a material's density in OpenRocket units.
20  *
21  * @param <C>  either a Streamer or Parachute
22  */
23 public abstract class RecoveryDeviceHandler<C extends RecoveryDevice> extends PositionDependentHandler<C> {
24
25     /**
26      * The thickness.  Not used by every component, and some component handlers may parse it for their own purposes.
27      */
28     private double thickness = 0d;
29     /**
30      * The Rocksim calculated mass.  Used only when not overridden and when Rocksim says density == 0 (Rocksim bug).
31      */
32     private Double calcMass = 0d;
33
34     /**
35      * {@inheritDoc}
36      */
37     @Override
38     public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
39             throws SAXException {
40         super.closeElement(element, attributes, content, warnings);
41
42         try {
43             if (RocksimCommonConstants.THICKNESS.equals(element)) {
44                 thickness = Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH;
45             }
46             if (RocksimCommonConstants.CALC_MASS.equals(element)) {
47                 calcMass = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
48             }
49         }
50         catch (NumberFormatException nfe) {
51             warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
52         }
53     }
54
55
56     /**
57      * Compute the density.  Rocksim does strange things with densities.  For some streamer material it's in cubic,
58      * rather than square, units.  In those cases it needs to be converted to an appropriate SURFACE material density.
59      *
60      * @param type       the rocksim density
61      * @param rawDensity the density as specified in the Rocksim design file
62      * @return a value in OpenRocket SURFACE density units
63      */
64     protected double computeDensity(RocksimDensityType type, double rawDensity) {
65
66         double result;
67
68         if (rawDensity > 0d) {
69             //ROCKSIM_SURFACE is a square area density; compute normally
70             //ROCKSIM_LINE is a single length dimension (kg/m) but Rocksim ignores thickness for this type and treats
71             //it like a SURFACE.
72             if (RocksimDensityType.ROCKSIM_SURFACE.equals(type) || RocksimDensityType.ROCKSIM_LINE.equals(type)) {
73                 result = rawDensity / RocksimDensityType.ROCKSIM_SURFACE.asOpenRocket();
74             }
75             //ROCKSIM_BULK is a cubic area density; multiple by thickness to make per square area; the result, when
76             //multiplied by the area will then equal Rocksim's computed mass.
77             else {
78                 result = (rawDensity / type.asOpenRocket()) * thickness;
79             }
80         }
81         else {
82             result = calcMass / getComponent().getArea();
83             //A Rocksim bug on streamers/parachutes results in a 0 density at times.  When that is detected, try
84             //to compute an approximate density from Rocksim's computed mass.
85             if (RocksimDensityType.ROCKSIM_BULK.equals(type)) {
86                 //ROCKSIM_BULK is a cubic area density; multiple by thickness to make per square area
87                 result *= thickness;
88             }
89         }
90         return result;
91     }
92
93     /**
94      * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not
95      * public in all components.
96      *
97      * @param position the OpenRocket position
98      */
99     @Override
100     public void setRelativePosition(RocketComponent.Position position) {
101         getComponent().setRelativePosition(position);
102     }
103
104     /**
105      * Get the required type of material for this component.  This is the OpenRocket type, which does NOT always
106      * correspond to Rocksim.  Some streamer material is defined as BULK in the Rocksim file.  In those cases
107      * it is adjusted in this handler.
108      *
109      * @return SURFACE
110      */
111     @Override
112     public Material.Type getMaterialType() {
113         return Material.Type.SURFACE;
114     }
115
116 }