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.
This commit is contained in:
Doug Pedrick 2012-07-11 22:06:23 +00:00
parent c8f7665177
commit 960555c108
2 changed files with 131 additions and 63 deletions

View File

@ -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 <C> the specific RocketComponent subtype for which the concrete handler can create
* @param <C> the specific RocketComponent subtype for which the concrete handler can create
*/
public abstract class BaseHandler<C extends RocketComponent> extends AbstractElementHandler {
@ -51,10 +51,11 @@ public abstract class BaseHandler<C extends RocketComponent> 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<C extends RocketComponent> 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<C extends RocketComponent> 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.
* <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) {
@ -119,14 +121,14 @@ public abstract class BaseHandler<C extends RocketComponent> 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<C extends RocketComponent> 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<C extends RocketComponent> 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<C extends RocketComponent> 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<? 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)) {
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<C extends RocketComponent> 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<C extends RocketComponent> 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
*/

View File

@ -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<MassObject> {
/**
/**
* 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<MassObject> {
private int typeCode = 0;
/**
* Constructor.
*l
* @param c the parent component
* @param warnings the warning set
*
* @throws IllegalArgumentException thrown if <code>c</code> is null
* Constructor. l
*
* @param c the parent component
* @param warnings the warning set
*
* @throws IllegalArgumentException thrown if <code>c</code> is null
*/
public MassObjectHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
if (c == null) {
@ -89,7 +91,7 @@ class MassObjectHandler extends PositionDependentHandler<MassObject> {
//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<MassObject> {
}
@Override
public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
if (typeCode == 0) { //General Mass Object
public void endHandler(String element, HashMap<String, String> 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());
/**
* 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);
}
cord.setRadialDirection(mass.getRadialDirection());
cord.setRadialPosition(mass.getRadialPosition());
cord.setRadius(mass.getRadius());
/**
* 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<String, String> 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());
//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);
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<MassObject> {
}
/**
* 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
*/