create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / file / rocksim / importt / RingHandler.java
1 /*
2  * RingHandler.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.simplesax.ElementHandler;
9 import net.sf.openrocket.file.simplesax.PlainTextHandler;
10 import net.sf.openrocket.material.Material;
11 import net.sf.openrocket.rocketcomponent.Bulkhead;
12 import net.sf.openrocket.rocketcomponent.CenteringRing;
13 import net.sf.openrocket.rocketcomponent.EngineBlock;
14 import net.sf.openrocket.rocketcomponent.RingComponent;
15 import net.sf.openrocket.rocketcomponent.RocketComponent;
16 import net.sf.openrocket.rocketcomponent.TubeCoupler;
17 import org.xml.sax.SAXException;
18
19 import java.util.HashMap;
20
21 /**
22  * A SAX handler for centering rings, tube couplers, and bulkheads.
23  */
24 class RingHandler extends PositionDependentHandler<CenteringRing> {
25
26     /**
27      * The OpenRocket Ring.
28      */
29     private final CenteringRing ring = new CenteringRing();
30
31     /**
32      * The parent component.
33      */
34     private final RocketComponent parent;
35
36     /**
37      * The parsed Rocksim UsageCode.
38      */
39     private int usageCode = 0;
40
41     /**
42      * Constructor.
43      *
44      * @param theParent the parent component
45      * @param warnings  the warning set
46      * @throws IllegalArgumentException thrown if <code>c</code> is null
47      */
48     public RingHandler(RocketComponent theParent, WarningSet warnings) throws IllegalArgumentException {
49         if (theParent == null) {
50             throw new IllegalArgumentException("The parent of a ring may not be null.");
51         }
52         parent = theParent;
53     }
54
55     @Override
56     public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
57         return PlainTextHandler.INSTANCE;
58     }
59
60     @Override
61     public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
62             throws SAXException {
63         super.closeElement(element, attributes, content, warnings);
64
65         try {
66             if (RocksimCommonConstants.OD.equals(element)) {
67                 ring.setOuterRadius(Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
68             }
69             if (RocksimCommonConstants.ID.equals(element)) {
70                 ring.setInnerRadius(Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
71             }
72             if (RocksimCommonConstants.LEN.equals(element)) {
73                 ring.setLength(Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
74             }
75             if (RocksimCommonConstants.MATERIAL.equals(element)) {
76                 setMaterialName(content);
77             }
78             if (RocksimCommonConstants.USAGE_CODE.equals(element)) {
79                 usageCode = Integer.parseInt(content);
80             }
81         } catch (NumberFormatException nfe) {
82             warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
83         }
84     }
85
86     /**
87      * Get the ring component this handler is working upon.
88      *
89      * @return a component
90      */
91     @Override
92     public CenteringRing getComponent() {
93         return ring;
94     }
95
96     /**
97      * This method adds the CenteringRing as a child of the parent rocket component.
98      *
99      * @param warnings the warning set
100      */
101     public void asCenteringRing(WarningSet warnings) {
102
103         if (isCompatible(parent, CenteringRing.class, warnings)) {
104             parent.addChild(ring);
105         }
106     }
107
108     /**
109      * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's Bulkhead.
110      * <p/>
111      * Side Effect Warning: This method adds the resulting Bulkhead as a child of the parent rocket component!
112      *
113      * @param warnings the warning set
114      */
115     public void asBulkhead(WarningSet warnings) {
116
117         Bulkhead result = new Bulkhead();
118
119         copyValues(result);
120
121         if (isCompatible(parent, Bulkhead.class, warnings)) {
122             parent.addChild(result);
123         }
124     }
125
126     /**
127      * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's TubeCoupler.
128      * <p/>
129      * Side Effect Warning: This method adds the resulting TubeCoupler as a child of the parent rocket component!
130      *
131      * @param warnings the warning set
132      */
133     public void asTubeCoupler(WarningSet warnings) {
134
135         TubeCoupler result = new TubeCoupler();
136
137         copyValues(result);
138
139         if (isCompatible(parent, TubeCoupler.class, warnings)) {
140             parent.addChild(result);
141         }
142     }
143
144     /**
145      * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's Engine Block.
146      * <p/>
147      * Side Effect Warning: This method adds the resulting EngineBlock as a child of the parent rocket component!
148      *
149      * @param warnings the warning set
150      */
151     public void asEngineBlock(WarningSet warnings) {
152
153         EngineBlock result = new EngineBlock();
154
155         copyValues(result);
156
157         if (isCompatible(parent, EngineBlock.class, warnings)) {
158             parent.addChild(result);
159         }
160     }
161
162     /**
163      * Copy values from the base ring to the specific component.
164      *
165      * @param result the target to which ring values will be copied
166      */
167     private void copyValues(RingComponent result) {
168         result.setOuterRadius(ring.getOuterRadius());
169         result.setInnerRadius(ring.getInnerRadius());
170         result.setLength(ring.getLength());
171         result.setName(ring.getName());
172         setOverride(result, ring.isOverrideSubcomponentsEnabled(), ring.getOverrideMass(), ring.getOverrideCGX());
173         result.setRelativePosition(ring.getRelativePosition());
174         result.setPositionValue(ring.getPositionValue());
175         result.setMaterial(ring.getMaterial());
176         result.setThickness(result.getThickness());
177     }
178
179     /**
180      * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not
181      * public in all components.
182      *
183      * @param position the OpenRocket position
184      */
185     @Override
186     public void setRelativePosition(RocketComponent.Position position) {
187         ring.setRelativePosition(position);
188     }
189
190     @Override
191     public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
192         super.endHandler(element, attributes, content, warnings);
193
194         // The <Ring> XML element in Rocksim design file is used for many types of components, unfortunately.
195         // Additional subelements are used to indicate the type of the rocket component. When parsing using SAX
196         // this poses a problem because we can't "look ahead" to see what type is being represented at the start
197         // of parsing - something that would be nice to do so that we can instantiate the correct OR component
198         // at the start, then just call setters for the appropriate data.
199
200         // To overcome that, a CenteringRing is instantiated at the start of parsing, it's mutators are called,
201         // and then at the end (this method) converts the CenteringRing to a more appropriate type.  CenteringRing
202         // is generic enough to support the representation of all similar types without loss of data.
203
204         //UsageCode
205         // 0 == Centering Ring
206         // 1 == Bulkhead
207         // 2 == Engine Block
208         // 3 == Sleeve
209         // 4 == Tube Coupler
210
211         if (usageCode == 1) {
212             //Bulkhead
213             asBulkhead(warnings);
214         } else if (usageCode == 2) {
215             asEngineBlock(warnings);
216         } else if (usageCode == 4) {
217             //TubeCoupler
218             asTubeCoupler(warnings);
219         } else {
220             //Default
221             asCenteringRing(warnings);
222         }
223     }
224
225     /**
226      * Get the required type of material for this component.
227      *
228      * @return BULK
229      */
230     @Override
231     public Material.Type getMaterialType() {
232         return Material.Type.BULK;
233     }
234 }