4 package net.sf.openrocket.file.rocksim.importt;
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;
19 import java.util.HashMap;
22 * A SAX handler for centering rings, tube couplers, and bulkheads.
24 class RingHandler extends PositionDependentHandler<CenteringRing> {
27 * The OpenRocket Ring.
29 private final CenteringRing ring = new CenteringRing();
32 * The parent component.
34 private final RocketComponent parent;
37 * The parsed Rocksim UsageCode.
39 private int usageCode = 0;
44 * @param theParent the parent component
45 * @param warnings the warning set
46 * @throws IllegalArgumentException thrown if <code>c</code> is null
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.");
56 public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
57 return PlainTextHandler.INSTANCE;
61 public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
63 super.closeElement(element, attributes, content, warnings);
66 if (RocksimCommonConstants.OD.equals(element)) {
67 ring.setOuterRadius(Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
69 if (RocksimCommonConstants.ID.equals(element)) {
70 ring.setInnerRadius(Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_RADIUS);
72 if (RocksimCommonConstants.LEN.equals(element)) {
73 ring.setLength(Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
75 if (RocksimCommonConstants.MATERIAL.equals(element)) {
76 setMaterialName(content);
78 if (RocksimCommonConstants.USAGE_CODE.equals(element)) {
79 usageCode = Integer.parseInt(content);
81 } catch (NumberFormatException nfe) {
82 warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number.");
87 * Get the ring component this handler is working upon.
92 public CenteringRing getComponent() {
97 * This method adds the CenteringRing as a child of the parent rocket component.
99 * @param warnings the warning set
101 public void asCenteringRing(WarningSet warnings) {
103 if (isCompatible(parent, CenteringRing.class, warnings)) {
104 parent.addChild(ring);
109 * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's Bulkhead.
111 * Side Effect Warning: This method adds the resulting Bulkhead as a child of the parent rocket component!
113 * @param warnings the warning set
115 public void asBulkhead(WarningSet warnings) {
117 Bulkhead result = new Bulkhead();
121 if (isCompatible(parent, Bulkhead.class, warnings)) {
122 parent.addChild(result);
127 * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's TubeCoupler.
129 * Side Effect Warning: This method adds the resulting TubeCoupler as a child of the parent rocket component!
131 * @param warnings the warning set
133 public void asTubeCoupler(WarningSet warnings) {
135 TubeCoupler result = new TubeCoupler();
139 if (isCompatible(parent, TubeCoupler.class, warnings)) {
140 parent.addChild(result);
145 * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's Engine Block.
147 * Side Effect Warning: This method adds the resulting EngineBlock as a child of the parent rocket component!
149 * @param warnings the warning set
151 public void asEngineBlock(WarningSet warnings) {
153 EngineBlock result = new EngineBlock();
157 if (isCompatible(parent, EngineBlock.class, warnings)) {
158 parent.addChild(result);
163 * Copy values from the base ring to the specific component.
165 * @param result the target to which ring values will be copied
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());
180 * Set the relative position onto the component. This cannot be done directly because setRelativePosition is not
181 * public in all components.
183 * @param position the OpenRocket position
186 public void setRelativePosition(RocketComponent.Position position) {
187 ring.setRelativePosition(position);
191 public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
192 super.endHandler(element, attributes, content, warnings);
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.
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.
205 // 0 == Centering Ring
211 if (usageCode == 1) {
213 asBulkhead(warnings);
214 } else if (usageCode == 2) {
215 asEngineBlock(warnings);
216 } else if (usageCode == 4) {
218 asTubeCoupler(warnings);
221 asCenteringRing(warnings);
226 * Get the required type of material for this component.
231 public Material.Type getMaterialType() {
232 return Material.Type.BULK;