Material localization support
[debian/openrocket] / core / src / net / sf / openrocket / file / rocksim / importt / BaseHandler.java
index b87664a881f4e47bfdb6d8da96d163b702a52adb..35296d415ea2e868d31aea12ccc57a0c9aafe990 100644 (file)
@@ -3,17 +3,19 @@
  */
 package net.sf.openrocket.file.rocksim.importt;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
 import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.database.Databases;
 import net.sf.openrocket.file.rocksim.RocksimCommonConstants;
 import net.sf.openrocket.file.rocksim.RocksimDensityType;
 import net.sf.openrocket.file.simplesax.AbstractElementHandler;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.xml.sax.SAXException;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.HashMap;
+import org.xml.sax.SAXException;
 
 /**
  * An abstract base class that handles common parsing.  All Rocksim component handlers are subclassed from here.
@@ -21,271 +23,266 @@ import java.util.HashMap;
  * @param <C> the specific RocketComponent subtype for which the concrete handler can create
  */
 public abstract class BaseHandler<C extends RocketComponent> extends AbstractElementHandler {
-
-    /**
-     * Prepend rocksim materials.
-     */
-    public static final String ROCKSIM_MATERIAL_PREFIX = "RS: ";
-    /**
-     * The overridden mass.
-     */
-    private Double mass = 0d;
-    /**
-     * The overridden Cg.
-     */
-    private Double cg = 0d;
-    /**
-     * The density of the material in the component.
-     */
-    private Double density = 0d;
-    /**
-     * The internal Rocksim density type.
-     */
-    private RocksimDensityType densityType = RocksimDensityType.ROCKSIM_BULK;
-
-    /**
-     * The material name.
-     */
-    private String materialName = "";
-
-    /**
-     * The SAX method called when the closing element tag is reached.
-     *
-     * @param element    the element name.
-     * @param attributes attributes of the element.
-     * @param content    the textual content of the element.
-     * @param warnings   the warning set to store warnings in.
-     *
-     * @throws SAXException
-     */
-
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        final C component = getComponent();
-        try {
-            if (RocksimCommonConstants.NAME.equals(element)) {
-                component.setName(content);
-            }
-            if (RocksimCommonConstants.KNOWN_MASS.equals(element)) {
-                mass = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
-            }
-            if (RocksimCommonConstants.DENSITY.equals(element)) {
-                density = Math.max(0d, Double.parseDouble(content));
-            }
-            if (RocksimCommonConstants.KNOWN_CG.equals(element)) {
-                cg = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
-            }
-            if (RocksimCommonConstants.USE_KNOWN_CG.equals(element)) {  //Rocksim sets UseKnownCG to true to control the override of both cg and mass
-                boolean override = "1".equals(content);
-                setOverride(component, override, mass, cg);
-            }
-            if (RocksimCommonConstants.DENSITY_TYPE.equals(element)) {
-                densityType = RocksimDensityType.fromCode(Integer.parseInt(content));
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        /* Because of the order of XML elements in Rocksim, not all information is known at the time it really needs
-           to be acted upon.  So we keep temporary instance variables to be used here at the end of the parsing.
-         */
-        density = computeDensity(densityType, density);
-        RocketComponent component = getComponent();
-        updateComponentMaterial(component, materialName, getMaterialType(), density);
-    }
-
-    /**
-     * Compute the density.  Rocksim does strange things with densities.  For some streamer material it's in cubic,
-     * rather than square, units.  In those cases it needs to be converted to an appropriate SURFACE material density.
-     * Some G10 fiberglass materials are in cubic units, other G10 fiberglass is in square units.  And due to a Rocksim
-     * bug, some densities are 0 when they clearly should not be.
-     * <p/>
-     * This may be overridden for specific component density computations.
-     *
-     * @param type       the rocksim density
-     * @param rawDensity the density as specified in the Rocksim design file
-     *
-     * @return a value in OpenRocket SURFACE density units
-     */
-    protected double computeDensity(RocksimDensityType type, double rawDensity) {
-        return rawDensity / type.asOpenRocket();
-    }
-
-    /**
-     * If the Rocksim component does not override the mass, then create a Material based upon the density defined for
-     * that component.  This *should* result in a consistent representation of Cg between Rocksim and OpenRocket.
-     *
-     * @param component       the component
-     * @param type            the type of the material
-     * @param density         the density in g/cm^3
-     * @param definedMaterial the material that is currently defined on the component; used only to get the name as it
-     *                        appears in Rocksim
-     */
-    public static void updateComponentMaterial(RocketComponent component, String definedMaterial, Material.Type type,
-                                               double density) {
-        if (definedMaterial != null) {
-            Material custom = createCustomMaterial(type, definedMaterial, density);
-            setMaterial(component, custom);
-        }
-    }
-
-    /**
-     * Override the mass and Cg of the component.
-     *
-     * @param component the component
-     * @param override  true if any override should happen
-     * @param mass      the override mass
-     * @param cg        the override cg
-     */
-    public static void setOverride(RocketComponent component, boolean override, double mass, double cg) {
-        if (override) {
-            component.setCGOverridden(override);
-            component.setMassOverridden(override);
-            component.setOverrideSubcomponents(false); //Rocksim does not support this type of override
-            component.setOverrideMass(mass);
-            component.setOverrideCGX(cg);
-        }
-    }
-
-    /**
-     * Get the component this handler is working upon.
-     *
-     * @return a component
-     */
-    protected abstract C getComponent();
-
-    /**
-     * Get the required type of material for this component.
-     *
-     * @return the required material type
-     */
-    protected abstract Material.Type getMaterialType();
-
-    /**
-     * Some CG positions in Rocksim do not correspond to the CG position reference in OpenRocket.
-     *
-     * @param theCG the CG value to really use when overriding CG on the OpenRocket component
-     */
-    protected void setCG(double theCG) {
-        cg = theCG;
-    }
-
-    /**
-     * Set the material name as specified in the Rocksim design file.
-     *
-     * @param content the material name
-     */
-    protected void setMaterialName(String content) {
-        materialName = content;
-    }
-
-    /**
-     * Get the Rocksim enum of the component's density type.
-     *
-     * @return a Rocksim density type
-     */
-    protected RocksimDensityType getDensityType() {
-        return densityType;
-    }
-
-    /**
-     * Add child to parent only if the child is compatible.  Otherwise add to warning set.
-     *
-     * @param parent   the parent component
-     * @param child    the child component
-     * @param warnings the warning set
-     *
-     * @return true if the child is compatible with parent
-     */
-    protected static boolean isCompatible(RocketComponent parent, Class<? extends RocketComponent> child, WarningSet warnings) {
-        return isCompatible(parent, child, warnings, false);
-    }
-
-    /**
-     * Add child to parent only if the child is compatible.  Otherwise add to warning set.
-     *
-     * @param parent   the parent component
-     * @param child    the child component
-     * @param warnings the warning set
-     * @param suppressWarnings suppress warnings, just return the boolean
-     *
-     * @return true if the child is compatible with parent
-     */
-    protected static boolean isCompatible(RocketComponent parent, Class<? extends RocketComponent> child,
-                                          WarningSet warnings,
-                                          boolean suppressWarnings) {
-        if (!parent.isCompatible(child)) {
-            if (!suppressWarnings) {
-                warnings.add(child.getName() + " can not be attached to "
-                        + parent.getComponentName() + ", ignoring component.");
-            }
-            return false;
-        }
-        else {
-            return true;
-        }
-    }
-
-    /**
-     * Create a custom material based on the density.  The name of the material is prepended with 'RS: ' to indicate it
-     * came from a RockSim material.
-     *
-     * @param type    the type of the material
-     * @param name    the name of the component
-     * @param density the density
-     *
-     * @return a Material instance
-     */
-    public static Material createCustomMaterial(Material.Type type, String name, double density) {
-        return Material.newUserMaterial(type, ROCKSIM_MATERIAL_PREFIX + name, density);
-    }
-
-    /**
-     * Set the material onto an instance of RocketComponent.  This is done because only some subtypes of RocketComponent
-     * have the setMaterial method.  Unfortunately the supertype cannot be used.
-     *
-     * @param component the component who's material is to be set
-     * @param material  the material to be set on the component (defined by getComponent())
-     */
-    private static void setMaterial(RocketComponent component, Material material) {
-        try {
-            final Method method = getMethod(component, "setMaterial", new Class[]{Material.class});
-            if (method != null) {
-                method.invoke(component, material);
-            }
-        }
-        catch (IllegalAccessException ignored) {
-        }
-        catch (InvocationTargetException ignored) {
-        }
-    }
-
-    /**
-     * Find a method by name and argument list.
-     *
-     * @param component the component who's material is to be set
-     * @param name      the method name
-     * @param args      the class types of the parameters
-     *
-     * @return the Method instance, or null
-     */
-    private static Method getMethod(RocketComponent component, String name, Class[] args) {
-        Method method = null;
-        try {
-            method = component.getClass().getMethod(name, args);
-        }
-        catch (NoSuchMethodException ignored) {
-        }
-        return method;
-    }
-
+       
+       /**
+        * Prepend rocksim materials.
+        */
+       public static final String ROCKSIM_MATERIAL_PREFIX = "RS: ";
+       /**
+        * The overridden mass.
+        */
+       private Double mass = 0d;
+       /**
+        * The overridden Cg.
+        */
+       private Double cg = 0d;
+       /**
+        * The density of the material in the component.
+        */
+       private Double density = 0d;
+       /**
+        * The internal Rocksim density type.
+        */
+       private RocksimDensityType densityType = RocksimDensityType.ROCKSIM_BULK;
+       
+       /**
+        * The material name.
+        */
+       private String materialName = "";
+       
+       /**
+        * The SAX method called when the closing element tag is reached.
+        *
+        * @param element    the element name.
+        * @param attributes attributes of the element.
+        * @param content    the textual content of the element.
+        * @param warnings   the warning set to store warnings in.
+        *
+        * @throws SAXException
+        */
+       
+       @Override
+       public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+                       throws SAXException {
+               final C component = getComponent();
+               try {
+                       if (RocksimCommonConstants.NAME.equals(element)) {
+                               component.setName(content);
+                       }
+                       if (RocksimCommonConstants.KNOWN_MASS.equals(element)) {
+                               mass = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
+                       }
+                       if (RocksimCommonConstants.DENSITY.equals(element)) {
+                               density = Math.max(0d, Double.parseDouble(content));
+                       }
+                       if (RocksimCommonConstants.KNOWN_CG.equals(element)) {
+                               cg = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+                       }
+                       if (RocksimCommonConstants.USE_KNOWN_CG.equals(element)) { //Rocksim sets UseKnownCG to true to control the override of both cg and mass
+                               boolean override = "1".equals(content);
+                               setOverride(component, override, mass, cg);
+                       }
+                       if (RocksimCommonConstants.DENSITY_TYPE.equals(element)) {
+                               densityType = RocksimDensityType.fromCode(Integer.parseInt(content));
+                       }
+               } catch (NumberFormatException nfe) {
+                       warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+               }
+       }
+       
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+                       throws SAXException {
+               /* Because of the order of XML elements in Rocksim, not all information is known at the time it really needs
+                  to be acted upon.  So we keep temporary instance variables to be used here at the end of the parsing.
+                */
+               density = computeDensity(densityType, density);
+               RocketComponent component = getComponent();
+               updateComponentMaterial(component, materialName, getMaterialType(), density);
+       }
+       
+       /**
+        * Compute the density.  Rocksim does strange things with densities.  For some streamer material it's in cubic,
+        * rather than square, units.  In those cases it needs to be converted to an appropriate SURFACE material density.
+        * Some G10 fiberglass materials are in cubic units, other G10 fiberglass is in square units.  And due to a Rocksim
+        * bug, some densities are 0 when they clearly should not be.
+        * <p/>
+        * This may be overridden for specific component density computations.
+        *
+        * @param type       the rocksim density
+        * @param rawDensity the density as specified in the Rocksim design file
+        *
+        * @return a value in OpenRocket SURFACE density units
+        */
+       protected double computeDensity(RocksimDensityType type, double rawDensity) {
+               return rawDensity / type.asOpenRocket();
+       }
+       
+       /**
+        * If the Rocksim component does not override the mass, then create a Material based upon the density defined for
+        * that component.  This *should* result in a consistent representation of Cg between Rocksim and OpenRocket.
+        *
+        * @param component       the component
+        * @param type            the type of the material
+        * @param density         the density in g/cm^3
+        * @param definedMaterial the material that is currently defined on the component; used only to get the name as it
+        *                        appears in Rocksim
+        */
+       public static void updateComponentMaterial(RocketComponent component, String definedMaterial, Material.Type type,
+                       double density) {
+               if (definedMaterial != null) {
+                       Material custom = createCustomMaterial(type, definedMaterial, density);
+                       setMaterial(component, custom);
+               }
+       }
+       
+       /**
+        * Override the mass and Cg of the component.
+        *
+        * @param component the component
+        * @param override  true if any override should happen
+        * @param mass      the override mass
+        * @param cg        the override cg
+        */
+       public static void setOverride(RocketComponent component, boolean override, double mass, double cg) {
+               if (override) {
+                       component.setCGOverridden(override);
+                       component.setMassOverridden(override);
+                       component.setOverrideSubcomponents(false); //Rocksim does not support this type of override
+                       component.setOverrideMass(mass);
+                       component.setOverrideCGX(cg);
+               }
+       }
+       
+       /**
+        * Get the component this handler is working upon.
+        *
+        * @return a component
+        */
+       protected abstract C getComponent();
+       
+       /**
+        * Get the required type of material for this component.
+        *
+        * @return the required material type
+        */
+       protected abstract Material.Type getMaterialType();
+       
+       /**
+        * Some CG positions in Rocksim do not correspond to the CG position reference in OpenRocket.
+        *
+        * @param theCG the CG value to really use when overriding CG on the OpenRocket component
+        */
+       protected void setCG(double theCG) {
+               cg = theCG;
+       }
+       
+       /**
+        * Set the material name as specified in the Rocksim design file.
+        *
+        * @param content the material name
+        */
+       protected void setMaterialName(String content) {
+               materialName = content;
+       }
+       
+       /**
+        * Get the Rocksim enum of the component's density type.
+        *
+        * @return a Rocksim density type
+        */
+       protected RocksimDensityType getDensityType() {
+               return densityType;
+       }
+       
+       /**
+        * Add child to parent only if the child is compatible.  Otherwise add to warning set.
+        *
+        * @param parent   the parent component
+        * @param child    the child component
+        * @param warnings the warning set
+        *
+        * @return true if the child is compatible with parent
+        */
+       protected static boolean isCompatible(RocketComponent parent, Class<? extends RocketComponent> child, WarningSet warnings) {
+               return isCompatible(parent, child, warnings, false);
+       }
+       
+       /**
+        * Add child to parent only if the child is compatible.  Otherwise add to warning set.
+        *
+        * @param parent   the parent component
+        * @param child    the child component
+        * @param warnings the warning set
+        * @param suppressWarnings suppress warnings, just return the boolean
+        *
+        * @return true if the child is compatible with parent
+        */
+       protected static boolean isCompatible(RocketComponent parent, Class<? extends RocketComponent> child,
+                       WarningSet warnings,
+                       boolean suppressWarnings) {
+               if (!parent.isCompatible(child)) {
+                       if (!suppressWarnings) {
+                               warnings.add(child.getName() + " can not be attached to "
+                                               + parent.getComponentName() + ", ignoring component.");
+                       }
+                       return false;
+               }
+               else {
+                       return true;
+               }
+       }
+       
+       /**
+        * Create a custom material based on the density.
+        *
+        * @param type    the type of the material
+        * @param name    the name of the component
+        * @param density the density
+        *
+        * @return a Material instance
+        */
+       public static Material createCustomMaterial(Material.Type type, String name, double density) {
+               return Databases.findMaterial(type, name, density);
+       }
+       
+       /**
+        * Set the material onto an instance of RocketComponent.  This is done because only some subtypes of RocketComponent
+        * have the setMaterial method.  Unfortunately the supertype cannot be used.
+        *
+        * @param component the component who's material is to be set
+        * @param material  the material to be set on the component (defined by getComponent())
+        */
+       private static void setMaterial(RocketComponent component, Material material) {
+               try {
+                       final Method method = getMethod(component, "setMaterial", new Class[] { Material.class });
+                       if (method != null) {
+                               method.invoke(component, material);
+                       }
+               } catch (IllegalAccessException ignored) {
+               } catch (InvocationTargetException ignored) {
+               }
+       }
+       
+       /**
+        * Find a method by name and argument list.
+        *
+        * @param component the component who's material is to be set
+        * @param name      the method name
+        * @param args      the class types of the parameters
+        *
+        * @return the Method instance, or null
+        */
+       private static Method getMethod(RocketComponent component, String name, Class[] args) {
+               Method method = null;
+               try {
+                       method = component.getClass().getMethod(name, args);
+               } catch (NoSuchMethodException ignored) {
+               }
+               return method;
+       }
+       
 }