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