create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / file / rocksim / importt / NoseConeHandler.java
1 /*
2  * NoseConeHandler.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.RocksimFinishCode;
9 import net.sf.openrocket.file.rocksim.RocksimNoseConeCode;
10 import net.sf.openrocket.file.simplesax.ElementHandler;
11 import net.sf.openrocket.file.simplesax.PlainTextHandler;
12 import net.sf.openrocket.material.Material;
13 import net.sf.openrocket.rocketcomponent.NoseCone;
14 import net.sf.openrocket.rocketcomponent.RocketComponent;
15 import net.sf.openrocket.rocketcomponent.Transition;
16 import org.xml.sax.SAXException;
17
18 import java.util.HashMap;
19
20 /**
21  * The SAX nose cone handler for Rocksim NoseCones.
22  */
23 class NoseConeHandler extends BaseHandler<NoseCone> {
24
25     /**
26      * The OpenRocket NoseCone.
27      */
28     private final NoseCone noseCone = new NoseCone();
29
30     /**
31      * The wall thickness.  Used for hollow nose cones.  
32      */
33     private double thickness = 0d;
34     
35     /**
36      * Constructor.
37      *
38      * @param c the parent component to the nosecone
39      * @param warnings  the warning set
40      * 
41      * @throws IllegalArgumentException thrown if <code>c</code> is null
42      */
43     public NoseConeHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
44         if (c == null) {
45             throw new IllegalArgumentException("The parent component of a nose cone may not be null.");
46         }
47         if (isCompatible(c, NoseCone.class, warnings)) {
48             c.addChild(noseCone);
49             noseCone.setAftRadiusAutomatic(false);
50         }
51     }
52
53     @Override
54     public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
55         //Nose cones in Rocksim may have attached parts - namely Mass Objects - as children.
56         if (RocksimCommonConstants.ATTACHED_PARTS.equals(element)) {
57             return new AttachedPartsHandler(noseCone);
58         }
59         return PlainTextHandler.INSTANCE;
60     }
61
62     @Override
63     public void closeElement(String element, HashMap<String, String> attributes,
64                              String content, WarningSet warnings) throws SAXException {
65         super.closeElement(element, attributes, content, warnings);
66
67         try {
68             if (RocksimCommonConstants.SHAPE_CODE.equals(element)) {
69                 noseCone.setType(RocksimNoseConeCode.fromCode(Integer.parseInt(content)).asOpenRocket());
70             }
71             if (RocksimCommonConstants.LEN.equals(element)) {
72                 noseCone.setLength(Math.max(0, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH));
73             }
74             if (RocksimCommonConstants.BASE_DIA.equals(element)) {
75                 noseCone.setAftRadius(Math.max(0, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS));
76             }
77             if (RocksimCommonConstants.WALL_THICKNESS.equals(element)) {
78                 thickness = Math.max(0, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
79             }
80             if (RocksimCommonConstants.SHOULDER_OD.equals(element)) {
81                 noseCone.setAftShoulderRadius(Math.max(0, Double.parseDouble(
82                         content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS));
83             }
84             if (RocksimCommonConstants.SHOULDER_LEN.equals(element)) {
85                 noseCone.setAftShoulderLength(Math.max(0, Double.parseDouble(
86                         content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH));
87             }
88             if (RocksimCommonConstants.SHAPE_PARAMETER.equals(element)) {
89                 //The Rocksim ShapeParameter only applies to certain shapes, although it is included
90                 //in the design file for all nose cones.  Applying it when it should not be causes oddities so 
91                 //a check is made for the allowable shapes.
92                 if (Transition.Shape.POWER.equals(noseCone.getType()) ||
93                     Transition.Shape.HAACK.equals(noseCone.getType()) ||
94                     Transition.Shape.PARABOLIC.equals(noseCone.getType())) {
95                     noseCone.setShapeParameter(Double.parseDouble(content));
96                 }
97             }
98             if (RocksimCommonConstants.CONSTRUCTION_TYPE.equals(element)) {
99                 int typeCode = Integer.parseInt(content);
100                 if (typeCode == 0) {
101                     //SOLID
102                     noseCone.setFilled(true);
103                 }
104                 else if (typeCode == 1) {
105                     //HOLLOW
106                     noseCone.setFilled(false);
107                 }
108             }
109             if (RocksimCommonConstants.FINISH_CODE.equals(element)) {
110                 noseCone.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket());
111             }
112             if (RocksimCommonConstants.MATERIAL.equals(element)) {
113                 setMaterialName(content);
114             }
115         }
116         catch (NumberFormatException nfe) {
117             warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
118         }
119     }
120
121     @Override
122     public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
123             throws SAXException {
124         super.endHandler(element, attributes, content, warnings);
125         
126         if (noseCone.isFilled()) {
127             noseCone.setAftShoulderThickness(noseCone.getAftShoulderRadius());                    
128         }
129         else {
130             noseCone.setThickness(thickness);
131             noseCone.setAftShoulderThickness(thickness);
132         }
133     }
134     
135     /**
136      * Get the nose cone component this handler is working upon.
137      *
138      * @return a nose cone component
139      */
140     @Override
141     public NoseCone getComponent() {
142         return noseCone;
143     }
144
145     /**
146      * Get the required type of material for this component.
147      *
148      * @return BULK
149      */
150     public Material.Type getMaterialType() {
151         return Material.Type.BULK;
152     }
153
154 }