ee8cd22db4aeb7977234aa6632c1c9cbd12b6a0f
[debian/openrocket] / core / src / net / sf / openrocket / file / rocksim / importt / MassObjectHandler.java
1 /*
2  * MassObjectHandler.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.MassComponent;
12 import net.sf.openrocket.rocketcomponent.MassObject;
13 import net.sf.openrocket.rocketcomponent.RocketComponent;
14 import net.sf.openrocket.rocketcomponent.ShockCord;
15 import org.xml.sax.SAXException;
16
17 import java.util.HashMap;
18
19 /**
20  * A SAX handler for Rocksim's MassObject XML type.
21  */
22 class MassObjectHandler extends PositionDependentHandler<MassObject> {
23
24     /** 
25      * The Rocksim Mass length fudge factor.  Rocksim completely exaggerates the length of a mass object to the point
26      * that it looks ridiculous in OpenRocket.  This fudge factor is here merely to get the typical mass object to
27      * render in the OpenRocket UI with it's bounds mostly inside it's parent.  The odd thing about it is that 
28      * Rocksim does not expose the length of a mass object in the UI and actually treats mass objects as point objects -
29      * not 3 or even 2 dimensional.
30      */
31     public static final int MASS_LEN_FUDGE_FACTOR = 100;
32
33     /**
34      * The OpenRocket MassComponent - counterpart to the RS MassObject.
35      */
36     private final MassComponent mass;
37
38     /**
39      * Reference to answer for getComponent().
40      */
41     private MassObject current;
42
43     /**
44      * Parent.
45      */
46     private RocketComponent parent;
47
48     /**
49      * 0 == General, 1 == Shock Cord
50      */
51     private int typeCode = 0;
52
53     /**
54      * Constructor.
55      *l
56      * @param c the parent component
57      * @param warnings  the warning set
58      * 
59      * @throws IllegalArgumentException  thrown if <code>c</code> is null
60      */
61     public MassObjectHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
62         if (c == null) {
63             throw new IllegalArgumentException("The parent component of a mass component may not be null.");
64         }
65         mass = new MassComponent();
66         current = mass;
67         parent = c;
68     }
69
70     @Override
71     public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
72         return PlainTextHandler.INSTANCE;
73     }
74
75     @Override
76     public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
77             throws SAXException {
78         super.closeElement(element, attributes, content, warnings);
79         try {
80             if (RocksimCommonConstants.LEN.equals(element)) {
81                 mass.setLength(Double.parseDouble(content) / (RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH));
82             }
83             if (RocksimCommonConstants.KNOWN_MASS.equals(element)) {
84                 mass.setComponentMass(Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
85             }
86             if (RocksimCommonConstants.KNOWN_CG.equals(element)) {
87                 //Setting the CG of the Mass Object to 0 is important because of the different ways that Rocksim and
88                 //OpenRocket treat mass objects.  Rocksim treats them as points (even though the data file contains a
89                 //length) and because Rocksim sets the CG of the mass object to really be relative to the front of
90                 //the parent.  But that value is already assumed in the position and position value for the component.
91                 //Thus it needs to be set to 0 to say that the mass object's CG is at the point of the mass object.
92                 super.setCG(0); 
93             }
94             if (RocksimCommonConstants.TYPE_CODE.equals(element)) {
95                 typeCode = Integer.parseInt(content);
96             }
97             if (RocksimCommonConstants.MATERIAL.equals(element)) {
98                 setMaterialName(content);
99             }
100         }
101         catch (NumberFormatException nfe) {
102             warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
103         }
104     }
105
106     @Override
107     public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
108         if (typeCode == 0) { //General Mass Object
109             if (isCompatible(parent, MassComponent.class, warnings)) {
110                 parent.addChild(mass);
111             }
112             super.endHandler(element, attributes, content, warnings);
113         }
114         else if (typeCode == 1) { //Shock Cord
115             ShockCord cord = new ShockCord();
116             current = cord;
117             if (isCompatible(parent, ShockCord.class, warnings)) {
118                 parent.addChild(cord);
119             }
120             super.endHandler(element, attributes, content, warnings);
121             cord.setName(mass.getName());
122
123             setOverride(cord, mass.isMassOverridden(), mass.getOverrideMass(), mass.getOverrideCGX());
124
125             cord.setRadialDirection(mass.getRadialDirection());
126             cord.setRadialPosition(mass.getRadialPosition());
127             cord.setRadius(mass.getRadius());
128
129             //Rocksim does not distinguish between total length of the cord and the packed length.  Fudge the
130             //packed length and set the real length.
131             cord.setCordLength(mass.getLength());
132             cord.setLength(cord.getCordLength()/MASS_LEN_FUDGE_FACTOR);
133         }
134     }
135
136     /**
137      * Get the component this handler is working upon.  This changes depending upon the type of mass object.
138      *
139      * @return a component
140      */
141     @Override
142     public MassObject getComponent() {
143         return current;
144     }
145
146     /**
147      * Set the relative position onto the component.  This cannot be done directly because setRelativePosition is not
148      * public in all components.
149      *
150      * @param position the OpenRocket position
151      */
152     public void setRelativePosition(RocketComponent.Position position) {
153         current.setRelativePosition(position);
154     }
155
156     /**
157      * Get the required type of material for this component.  Does not apply to MassComponents, but does apply to Shock Cords.
158      *
159      * @return LINE
160      */
161     @Override
162     public Material.Type getMaterialType() {
163         return Material.Type.LINE;
164     }
165
166 }