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.
|
* 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 {
|
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.
|
* The SAX method called when the closing element tag is reached.
|
||||||
*
|
*
|
||||||
* @param element the element name.
|
* @param element the element name.
|
||||||
* @param attributes attributes of the element.
|
* @param attributes attributes of the element.
|
||||||
* @param content the textual content of the element.
|
* @param content the textual content of the element.
|
||||||
* @param warnings the warning set to store warnings in.
|
* @param warnings the warning set to store warnings in.
|
||||||
|
*
|
||||||
* @throws SAXException
|
* @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);
|
mass = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
|
||||||
}
|
}
|
||||||
if (RocksimCommonConstants.DENSITY.equals(element)) {
|
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)) {
|
if (RocksimCommonConstants.KNOWN_CG.equals(element)) {
|
||||||
cg = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
|
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,
|
* 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.
|
* 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
|
* Some G10 fiberglass materials are in cubic units, other G10 fiberglass is in square units. And due to a Rocksim
|
||||||
* Rocksim bug, some densities are 0 when they clearly should not be.
|
* bug, some densities are 0 when they clearly should not be.
|
||||||
*
|
* <p/>
|
||||||
* This may be overridden for specific component density computations.
|
* This may be overridden for specific component density computations.
|
||||||
*
|
*
|
||||||
* @param type the rocksim density
|
* @param type the rocksim density
|
||||||
* @param rawDensity the density as specified in the Rocksim design file
|
* @param rawDensity the density as specified in the Rocksim design file
|
||||||
|
*
|
||||||
* @return a value in OpenRocket SURFACE density units
|
* @return a value in OpenRocket SURFACE density units
|
||||||
*/
|
*/
|
||||||
protected double computeDensity(RocksimDensityType type, double rawDensity) {
|
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
|
* If the Rocksim component does not override the mass, then create a Material based upon the density defined for
|
||||||
* for that component. This *should* result in a consistent representation of Cg between Rocksim and OpenRocket.
|
* that component. This *should* result in a consistent representation of Cg between Rocksim and OpenRocket.
|
||||||
*
|
*
|
||||||
* @param component the component
|
* @param component the component
|
||||||
* @param type the type of the material
|
* @param type the type of the material
|
||||||
* @param density the density in g/cm^3
|
* @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
|
* @param definedMaterial the material that is currently defined on the component; used only to get the name as it
|
||||||
* as it appears in Rocksim
|
* appears in Rocksim
|
||||||
*/
|
*/
|
||||||
public static void updateComponentMaterial(RocketComponent component, String definedMaterial, Material.Type type,
|
public static void updateComponentMaterial(RocketComponent component, String definedMaterial, Material.Type type,
|
||||||
double density) {
|
double density) {
|
||||||
@ -139,10 +141,10 @@ public abstract class BaseHandler<C extends RocketComponent> extends AbstractEle
|
|||||||
/**
|
/**
|
||||||
* Override the mass and Cg of the component.
|
* Override the mass and Cg of the component.
|
||||||
*
|
*
|
||||||
* @param component the component
|
* @param component the component
|
||||||
* @param override true if any override should happen
|
* @param override true if any override should happen
|
||||||
* @param mass the override mass
|
* @param mass the override mass
|
||||||
* @param cg the override cg
|
* @param cg the override cg
|
||||||
*/
|
*/
|
||||||
public static void setOverride(RocketComponent component, boolean override, double mass, double cg) {
|
public static void setOverride(RocketComponent component, boolean override, double mass, double cg) {
|
||||||
if (override) {
|
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.
|
* 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) {
|
protected void setCG(double theCG) {
|
||||||
cg = 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.
|
* 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) {
|
protected void setMaterialName(String content) {
|
||||||
materialName = 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.
|
* Add child to parent only if the child is compatible. Otherwise add to warning set.
|
||||||
*
|
*
|
||||||
* @param parent the parent component
|
* @param parent the parent component
|
||||||
* @param child the child component
|
* @param child the child component
|
||||||
* @param warnings the warning set
|
* @param warnings the warning set
|
||||||
*
|
*
|
||||||
* @return true if the child is compatible with parent
|
* @return true if the child is compatible with parent
|
||||||
*/
|
*/
|
||||||
protected static boolean isCompatible(RocketComponent parent, Class<? extends RocketComponent> child, WarningSet warnings) {
|
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 (!parent.isCompatible(child)) {
|
||||||
warnings.add(child.getName() + " can not be attached to "
|
if (!suppressWarnings) {
|
||||||
+ parent.getComponentName() + ", ignoring component.");
|
warnings.add(child.getName() + " can not be attached to "
|
||||||
|
+ parent.getComponentName() + ", ignoring component.");
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a custom material based on the density. The name of the material is prepended with 'RS: ' to
|
* Create a custom material based on the density. The name of the material is prepended with 'RS: ' to indicate it
|
||||||
* indicate it came from a RockSim material.
|
* came from a RockSim material.
|
||||||
*
|
*
|
||||||
* @param type the type of the material
|
* @param type the type of the material
|
||||||
* @param name the name of the component
|
* @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
|
* 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.
|
* have the setMaterial method. Unfortunately the supertype cannot be used.
|
||||||
*
|
*
|
||||||
* @param component the component who's material is to be set
|
* @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 material the material to be set on the component (defined by getComponent())
|
||||||
*/
|
*/
|
||||||
private static void setMaterial(RocketComponent component, Material material) {
|
private static void setMaterial(RocketComponent component, Material material) {
|
||||||
try {
|
try {
|
||||||
@ -243,9 +272,9 @@ public abstract class BaseHandler<C extends RocketComponent> extends AbstractEle
|
|||||||
/**
|
/**
|
||||||
* Find a method by name and argument list.
|
* Find a method by name and argument list.
|
||||||
*
|
*
|
||||||
* @param component the component who's material is to be seta
|
* @param component the component who's material is to be set
|
||||||
* @param name the method name
|
* @param name the method name
|
||||||
* @param args the class types of the parameters
|
* @param args the class types of the parameters
|
||||||
*
|
*
|
||||||
* @return the Method instance, or null
|
* @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.aerodynamics.WarningSet;
|
||||||
import net.sf.openrocket.file.rocksim.RocksimCommonConstants;
|
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.ElementHandler;
|
||||||
import net.sf.openrocket.file.simplesax.PlainTextHandler;
|
import net.sf.openrocket.file.simplesax.PlainTextHandler;
|
||||||
import net.sf.openrocket.material.Material;
|
import net.sf.openrocket.material.Material;
|
||||||
|
import net.sf.openrocket.rocketcomponent.Coaxial;
|
||||||
import net.sf.openrocket.rocketcomponent.MassComponent;
|
import net.sf.openrocket.rocketcomponent.MassComponent;
|
||||||
import net.sf.openrocket.rocketcomponent.MassObject;
|
import net.sf.openrocket.rocketcomponent.MassObject;
|
||||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
@ -21,12 +23,12 @@ import java.util.HashMap;
|
|||||||
*/
|
*/
|
||||||
class MassObjectHandler extends PositionDependentHandler<MassObject> {
|
class MassObjectHandler extends PositionDependentHandler<MassObject> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Rocksim Mass length fudge factor. Rocksim completely exaggerates the length of a mass object to the point
|
* 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
|
* 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
|
* render in the OpenRocket UI with it's bounds mostly inside it's parent. The odd thing about it is that Rocksim
|
||||||
* Rocksim does not expose the length of a mass object in the UI and actually treats mass objects as point objects -
|
* does not expose the length of a mass object in the UI and actually treats mass objects as point objects - not 3
|
||||||
* not 3 or even 2 dimensional.
|
* or even 2 dimensional.
|
||||||
*/
|
*/
|
||||||
public static final int MASS_LEN_FUDGE_FACTOR = 100;
|
public static final int MASS_LEN_FUDGE_FACTOR = 100;
|
||||||
|
|
||||||
@ -51,12 +53,12 @@ class MassObjectHandler extends PositionDependentHandler<MassObject> {
|
|||||||
private int typeCode = 0;
|
private int typeCode = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor. l
|
||||||
*l
|
*
|
||||||
* @param c the parent component
|
* @param c the parent component
|
||||||
* @param warnings the warning set
|
* @param warnings the warning set
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException thrown if <code>c</code> is null
|
* @throws IllegalArgumentException thrown if <code>c</code> is null
|
||||||
*/
|
*/
|
||||||
public MassObjectHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
|
public MassObjectHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
|
||||||
if (c == null) {
|
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
|
//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.
|
//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.
|
//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)) {
|
if (RocksimCommonConstants.TYPE_CODE.equals(element)) {
|
||||||
typeCode = Integer.parseInt(content);
|
typeCode = Integer.parseInt(content);
|
||||||
@ -104,32 +106,68 @@ class MassObjectHandler extends PositionDependentHandler<MassObject> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
|
public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws
|
||||||
if (typeCode == 0) { //General Mass Object
|
SAXException {
|
||||||
|
if (inferAsShockCord(typeCode, warnings)) { //Shock Cord
|
||||||
|
mapMassObjectAsShockCord(element, attributes, content, warnings);
|
||||||
|
}
|
||||||
|
else { // typeCode == 0 General Mass Object
|
||||||
if (isCompatible(parent, MassComponent.class, warnings)) {
|
if (isCompatible(parent, MassComponent.class, warnings)) {
|
||||||
parent.addChild(mass);
|
parent.addChild(mass);
|
||||||
}
|
}
|
||||||
super.endHandler(element, attributes, content, warnings);
|
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());
|
* If it appears that the mass object is a shock cord, then create an OR shock cord instance.
|
||||||
cord.setRadius(mass.getRadius());
|
*
|
||||||
|
* @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
|
setOverride(cord, mass.isMassOverridden(), mass.getOverrideMass(), mass.getOverrideCGX());
|
||||||
//packed length and set the real length.
|
|
||||||
cord.setCordLength(mass.getLength());
|
cord.setRadialDirection(mass.getRadialDirection());
|
||||||
cord.setLength(cord.getCordLength()/MASS_LEN_FUDGE_FACTOR);
|
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
|
* @return LINE
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user