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:
parent
c8f7665177
commit
960555c108
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user