From 88b6ef0edd1624613674ab619f1543feb0f1191c Mon Sep 17 00:00:00 2001 From: rodinia814 Date: Wed, 11 Jul 2012 22:06:23 +0000 Subject: [PATCH] Added inference of Rocksim shock cords to try to be a little more predictive when a Rocksim file uses a buggy shock cord from their component database. git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@886 180e2498-e6e9-4542-8430-84ac67f01cd8 --- .../file/rocksim/importt/BaseHandler.java | 95 ++++++++++------ .../rocksim/importt/MassObjectHandler.java | 101 ++++++++++++------ 2 files changed, 132 insertions(+), 64 deletions(-) diff --git a/core/src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java b/core/src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java index 6302c62a..a9d0bd94 100644 --- a/core/src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java +++ b/core/src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java @@ -18,7 +18,7 @@ import java.util.HashMap; /** * An abstract base class that handles common parsing. All Rocksim component handlers are subclassed from here. * - * @param the specific RocketComponent subtype for which the concrete handler can create + * @param the specific RocketComponent subtype for which the concrete handler can create */ public abstract class BaseHandler extends AbstractElementHandler { @@ -51,10 +51,11 @@ public abstract class BaseHandler extends AbstractEle /** * 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. + * @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 */ @@ -70,7 +71,7 @@ public abstract class BaseHandler extends AbstractEle mass = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS); } if (RocksimCommonConstants.DENSITY.equals(element)) { - density = Math.max(0d, Double.parseDouble(content) ); + 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); @@ -105,13 +106,14 @@ public abstract class BaseHandler extends AbstractEle /** * 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. - * + * 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. + *

* 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) { @@ -119,14 +121,14 @@ public abstract class BaseHandler extends AbstractEle } /** - * 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. + * 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 + * @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) { @@ -139,10 +141,10 @@ public abstract class BaseHandler extends AbstractEle /** * 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 + * @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) { @@ -171,7 +173,7 @@ public abstract class BaseHandler extends AbstractEle /** * 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 + * @param theCG the CG value to really use when overriding CG on the OpenRocket component */ protected void setCG(double theCG) { cg = theCG; @@ -180,35 +182,62 @@ public abstract class BaseHandler extends AbstractEle /** * Set the material name as specified in the Rocksim design file. * - * @param content the material name + * @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 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 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 child, + WarningSet warnings, + boolean suppressWarnings) { if (!parent.isCompatible(child)) { - warnings.add(child.getName() + " can not be attached to " - + parent.getComponentName() + ", ignoring component."); + 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. + * 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 @@ -224,8 +253,8 @@ public abstract class BaseHandler extends AbstractEle * 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()) + * @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 { @@ -243,9 +272,9 @@ public abstract class BaseHandler extends AbstractEle /** * Find a method by name and argument list. * - * @param component the component who's material is to be seta - * @param name the method name - * @param args the class types of the parameters + * @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 */ diff --git a/core/src/net/sf/openrocket/file/rocksim/importt/MassObjectHandler.java b/core/src/net/sf/openrocket/file/rocksim/importt/MassObjectHandler.java index ee8cd22d..2d918af9 100644 --- a/core/src/net/sf/openrocket/file/rocksim/importt/MassObjectHandler.java +++ b/core/src/net/sf/openrocket/file/rocksim/importt/MassObjectHandler.java @@ -5,9 +5,11 @@ package net.sf.openrocket.file.rocksim.importt; import net.sf.openrocket.aerodynamics.WarningSet; import net.sf.openrocket.file.rocksim.RocksimCommonConstants; +import net.sf.openrocket.file.rocksim.RocksimDensityType; import net.sf.openrocket.file.simplesax.ElementHandler; import net.sf.openrocket.file.simplesax.PlainTextHandler; import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.Coaxial; import net.sf.openrocket.rocketcomponent.MassComponent; import net.sf.openrocket.rocketcomponent.MassObject; import net.sf.openrocket.rocketcomponent.RocketComponent; @@ -21,12 +23,12 @@ import java.util.HashMap; */ class MassObjectHandler extends PositionDependentHandler { - /** + /** * The Rocksim Mass length fudge factor. Rocksim completely exaggerates the length of a mass object to the point * that it looks ridiculous in OpenRocket. This fudge factor is here merely to get the typical mass object to - * render in the OpenRocket UI with it's bounds mostly inside it's parent. The odd thing about it is that - * Rocksim does not expose the length of a mass object in the UI and actually treats mass objects as point objects - - * not 3 or even 2 dimensional. + * render in the OpenRocket UI with it's bounds mostly inside it's parent. The odd thing about it is that Rocksim + * does not expose the length of a mass object in the UI and actually treats mass objects as point objects - not 3 + * or even 2 dimensional. */ public static final int MASS_LEN_FUDGE_FACTOR = 100; @@ -51,12 +53,12 @@ class MassObjectHandler extends PositionDependentHandler { private int typeCode = 0; /** - * Constructor. - *l - * @param c the parent component - * @param warnings the warning set - * - * @throws IllegalArgumentException thrown if c is null + * Constructor. l + * + * @param c the parent component + * @param warnings the warning set + * + * @throws IllegalArgumentException thrown if c is null */ public MassObjectHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException { if (c == null) { @@ -89,7 +91,7 @@ class MassObjectHandler extends PositionDependentHandler { //length) and because Rocksim sets the CG of the mass object to really be relative to the front of //the parent. But that value is already assumed in the position and position value for the component. //Thus it needs to be set to 0 to say that the mass object's CG is at the point of the mass object. - super.setCG(0); + super.setCG(0); } if (RocksimCommonConstants.TYPE_CODE.equals(element)) { typeCode = Integer.parseInt(content); @@ -104,32 +106,68 @@ class MassObjectHandler extends PositionDependentHandler { } @Override - public void endHandler(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { - if (typeCode == 0) { //General Mass Object + public void endHandler(String element, HashMap attributes, String content, WarningSet warnings) throws + SAXException { + if (inferAsShockCord(typeCode, warnings)) { //Shock Cord + mapMassObjectAsShockCord(element, attributes, content, warnings); + } + else { // typeCode == 0 General Mass Object if (isCompatible(parent, MassComponent.class, warnings)) { parent.addChild(mass); } super.endHandler(element, attributes, content, warnings); } - else if (typeCode == 1) { //Shock Cord - ShockCord cord = new ShockCord(); - current = cord; - if (isCompatible(parent, ShockCord.class, warnings)) { - parent.addChild(cord); - } - super.endHandler(element, attributes, content, warnings); - cord.setName(mass.getName()); - - setOverride(cord, mass.isMassOverridden(), mass.getOverrideMass(), mass.getOverrideCGX()); + } - cord.setRadialDirection(mass.getRadialDirection()); - cord.setRadialPosition(mass.getRadialPosition()); - cord.setRadius(mass.getRadius()); + /** + * Rocksim does not have a separate entity for Shock Cords. It has to be inferred. Sometimes the typeCode + * indicates it's a shock cord, but most times it does not. This is due to bugs in the Rocksim Component and + * Material databases. Try to infer a shock cord based on it's length and it's material type. It's somewhat + * arbitrary, but if the mass object's length is more than twice the length of it's parent component and it's a LINE + * material, then assume a shock cord. + * + * @param theTypeCode the code from the RKT XML file + * + * @return true if we think it's a shock cord + */ + private boolean inferAsShockCord(int theTypeCode, WarningSet warnings) { + return (theTypeCode == 1 || (mass.getLength() >= 2 * parent.getLength() && RocksimDensityType.ROCKSIM_LINE + .equals(getDensityType()))) && isCompatible(parent, ShockCord.class, warnings, true); + } - //Rocksim does not distinguish between total length of the cord and the packed length. Fudge the - //packed length and set the real length. - cord.setCordLength(mass.getLength()); - cord.setLength(cord.getCordLength()/MASS_LEN_FUDGE_FACTOR); + /** + * If it appears that the mass object is a shock cord, then create an OR shock cord instance. + * + * @param element the element name + * @param attributes the attributes + * @param content the content of the element + * @param warnings the warning set to store warnings in. + * + * @throws org.xml.sax.SAXException not thrown + */ + private void mapMassObjectAsShockCord(final String element, final HashMap attributes, + final String content, final WarningSet warnings) throws SAXException { + ShockCord cord = new ShockCord(); + current = cord; + if (isCompatible(parent, ShockCord.class, warnings)) { + parent.addChild(cord); + } + super.endHandler(element, attributes, content, warnings); + cord.setName(mass.getName()); + + setOverride(cord, mass.isMassOverridden(), mass.getOverrideMass(), mass.getOverrideCGX()); + + cord.setRadialDirection(mass.getRadialDirection()); + cord.setRadialPosition(mass.getRadialPosition()); + cord.setRadius(mass.getRadius()); + + //Rocksim does not distinguish between total length of the cord and the packed length. Fudge the + //packed length and set the real length. + cord.setCordLength(mass.getLength()); + cord.setLength(cord.getCordLength() / MASS_LEN_FUDGE_FACTOR); + if (parent instanceof Coaxial) { + Coaxial parentCoaxial = (Coaxial) parent; + cord.setRadius(parentCoaxial.getInnerRadius()); } } @@ -154,7 +192,8 @@ class MassObjectHandler extends PositionDependentHandler { } /** - * Get the required type of material for this component. Does not apply to MassComponents, but does apply to Shock Cords. + * Get the required type of material for this component. Does not apply to MassComponents, but does apply to Shock + * Cords. * * @return LINE */ -- 2.30.2