From 198227dc14b96901f3105fd816b6a9b84993adef Mon Sep 17 00:00:00 2001 From: plaa Date: Fri, 12 Mar 2010 23:09:54 +0000 Subject: [PATCH] committed Doug's Rocksim loader git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@45 180e2498-e6e9-4542-8430-84ac67f01cd8 --- ChangeLog | 4 + TODO | 56 +- .../openrocket/file/GeneralRocketLoader.java | 12 +- .../file/rocksim/AttachedPartsHandler.java | 74 + .../openrocket/file/rocksim/BaseHandler.java | 205 ++ .../file/rocksim/BodyTubeHandler.java | 100 + .../file/rocksim/FinSetHandler.java | 375 ++++ .../file/rocksim/InnerBodyTubeHandler.java | 110 + .../file/rocksim/LaunchLugHandler.java | 103 + .../file/rocksim/MassObjectHandler.java | 110 + .../file/rocksim/NoseConeHandler.java | 147 ++ .../file/rocksim/ParachuteHandler.java | 132 ++ .../rocksim/PositionDependentHandler.java | 80 + .../openrocket/file/rocksim/RingHandler.java | 100 + .../file/rocksim/RocksimFinishCode.java | 61 + .../file/rocksim/RocksimHandler.java | 363 +++ .../file/rocksim/RocksimLoader.java | 57 + .../file/rocksim/RocksimLocationMode.java | 59 + .../file/rocksim/RocksimNoseConeCode.java | 61 + .../file/rocksim/StreamerHandler.java | 95 + .../file/rocksim/TransitionHandler.java | 151 ++ .../sf/openrocket/gui/main/BasicFrame.java | 62 +- .../openrocket/gui/main/SimpleFileFilter.java | 62 + .../file/rocksim/BaseRocksimTest.java | 104 + .../file/rocksim/BodyTubeHandlerTest.java | 188 ++ .../file/rocksim/FinSetHandlerTest.java | 225 ++ .../rocksim/InnerBodyTubeHandlerTest.java | 197 ++ .../file/rocksim/LaunchLugHandlerTest.java | 184 ++ .../file/rocksim/MassObjectHandlerTest.java | 166 ++ .../file/rocksim/NoseConeHandlerTest.java | 239 ++ .../file/rocksim/ParachuteHandlerTest.java | 202 ++ .../file/rocksim/RingHandlerTest.java | 171 ++ .../rocksim/RocksimContentHandlerTest.java | 69 + .../file/rocksim/RocksimLoaderTest.java | 144 ++ .../file/rocksim/StreamerHandlerTest.java | 195 ++ .../file/rocksim/TransitionHandlerTest.java | 268 +++ .../file/rocksim/rocksimTestRocket1.rkt | 743 +++++++ .../file/rocksim/rocksimTestRocket2.rkt | 1583 +++++++++++++ .../file/rocksim/rocksimTestRocket3.rkt | 1961 +++++++++++++++++ 39 files changed, 9146 insertions(+), 72 deletions(-) create mode 100644 src/net/sf/openrocket/file/rocksim/AttachedPartsHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/BaseHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/BodyTubeHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/FinSetHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/InnerBodyTubeHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/LaunchLugHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/MassObjectHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/NoseConeHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/ParachuteHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/PositionDependentHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/RingHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/RocksimFinishCode.java create mode 100644 src/net/sf/openrocket/file/rocksim/RocksimHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/RocksimLoader.java create mode 100644 src/net/sf/openrocket/file/rocksim/RocksimLocationMode.java create mode 100644 src/net/sf/openrocket/file/rocksim/RocksimNoseConeCode.java create mode 100644 src/net/sf/openrocket/file/rocksim/StreamerHandler.java create mode 100644 src/net/sf/openrocket/file/rocksim/TransitionHandler.java create mode 100644 src/net/sf/openrocket/gui/main/SimpleFileFilter.java create mode 100644 test/net/sf/openrocket/file/rocksim/BaseRocksimTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/BodyTubeHandlerTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/FinSetHandlerTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/InnerBodyTubeHandlerTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/LaunchLugHandlerTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/MassObjectHandlerTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/NoseConeHandlerTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/ParachuteHandlerTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/RingHandlerTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/RocksimContentHandlerTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/RocksimLoaderTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/StreamerHandlerTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/TransitionHandlerTest.java create mode 100644 test/net/sf/openrocket/file/rocksim/rocksimTestRocket1.rkt create mode 100644 test/net/sf/openrocket/file/rocksim/rocksimTestRocket2.rkt create mode 100644 test/net/sf/openrocket/file/rocksim/rocksimTestRocket3.rkt diff --git a/ChangeLog b/ChangeLog index 82b64d13..9ed38adc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2010-03-13 Doug Pedrick / Sampo Niskanen + + * Initial RockSim design loading support + 2010-03-10 Sampo Niskanen * Released version 1.0.0 diff --git a/TODO b/TODO index ef866a76..ed0d27c7 100644 --- a/TODO +++ b/TODO @@ -1,12 +1,15 @@ -Feature roadmap for OpenRocket 1.0 +Feature roadmap for OpenRocket 2.0 ---------------------------------- -Must-have: +- Logging system into use +- Reduce memory footprint +- Reduce memory leakage +- Load thrust curves from external directory +- Support duplicate motor definitions -Maybe: @@ -135,48 +138,5 @@ Refactoring tasks: Done: ----- -- Search field in motor selection dialog -- Motor selection/editing from Edit configurations dialog -- Change FreeformFinSet to throw checked exceptions -- Fix engine block icons -- Exporting flight data -- Split cluster into separate components -- Create application icon and take into use -- Error dialog for uncaught exceptions -- Check where plot data ends (all rest NaN) -- Example rocket designs (hybrid w/ dual deployment, staged rocket) -- Better error/warning dialogs when reading/writing files -- Store custom materials -- Read more thrust curve formats -- Showing events in plots -- Table boolean selecting by clicking label -- Test automatic exception reporting (for 0.9.3) -- Draw remaining event icons (for 0.9.3) -- Update "About" dialog with icon and source info -In 0.9.4: -- Through-the-wall fins -- Make ThicknessRingComponent implement RadialParent and allow - attaching components to a TubeCoupler (for 0.9.4) -- Save file as oldest OpenRocket format possible (for 0.9.4) -- Non-exception bug handling -- JTree text is cropped unnecessarily -- Allow editing user-defined materials -- [BUG] All configuration dialogs too high -- Simulation plot dialog forces dialog one button row too high (All/None) -- Add styrofoam and depron materials -- Inform user about software updates -In 0.9.5: -- Add label to motor panel to tell current number of stages -In 0.9.6: -- Take into account all fins in interference effects -- Two-fin rocket stable at large number of roll angles?! -- Add slight randomness to yaw moment -- Update simulation time step filtering from exponential MA to - exponential growth until time step is reached (t1 = 1.5*t0) -- Limit time step during while on launch rod -- Re-investigate 15% reduction of three-fin CNa -In 1.0.0: -- BUG: Simulation table max. acceleration takes into account parachute deceleration -- Go through thrust curves and select best ones -- Updated splash screen -- BUG: Invalid fin points possible when removing points + +- Reading .RKT format \ No newline at end of file diff --git a/src/net/sf/openrocket/file/GeneralRocketLoader.java b/src/net/sf/openrocket/file/GeneralRocketLoader.java index 1dc3329a..c2246a4d 100644 --- a/src/net/sf/openrocket/file/GeneralRocketLoader.java +++ b/src/net/sf/openrocket/file/GeneralRocketLoader.java @@ -5,9 +5,11 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.util.zip.GZIPInputStream; +import java.util.Arrays; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.file.openrocket.OpenRocketLoader; +import net.sf.openrocket.file.rocksim.RocksimLoader; /** @@ -24,8 +26,12 @@ public class GeneralRocketLoader extends RocketLoader { private static final byte[] GZIP_SIGNATURE = { 31, -117 }; // 0x1f, 0x8b private static final byte[] OPENROCKET_SIGNATURE = "c is null + */ + public AttachedPartsHandler(RocketComponent c) throws IllegalArgumentException { + if (c == null) { + throw new IllegalArgumentException("The parent component of any attached part may not be null."); + } + component = c; + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + if ("FinSet".equals(element)) { + return new FinSetHandler(component); + } + if ("CustomFinSet".equals(element)) { + return new FinSetHandler(component); + } + if ("LaunchLug".equals(element)) { + return new LaunchLugHandler(component); + } + if ("Parachute".equals(element)) { + return new ParachuteHandler(component); + } + if ("Streamer".equals(element)) { + return new StreamerHandler(component); + } + if ("MassObject".equals(element)) { + return new MassObjectHandler(component); + } + if ("Ring".equals(element)) { + return new RingHandler(component); + } + if ("BodyTube".equals(element)) { + return new InnerBodyTubeHandler(component); + } + if ("Transition".equals(element)) { + return new TransitionHandler(component); + } + if ("TubeFinSet".equals(element)) { + warnings.add("Tube fins are not currently supported. Ignoring."); + } + if ("RingTail".equals(element)) { + warnings.add("Ring tails are not currently supported. Ignoring."); + } + if ("ExternalPod".equals(element)) { + warnings.add("Pods are not currently supported. Ignoring."); + } + return null; + } +} + diff --git a/src/net/sf/openrocket/file/rocksim/BaseHandler.java b/src/net/sf/openrocket/file/rocksim/BaseHandler.java new file mode 100644 index 00000000..aad4a330 --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/BaseHandler.java @@ -0,0 +1,205 @@ +/* + * BaseHandler.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.file.simplesax.ElementHandler; +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; + +/** + * An abstract base class that handles common parsing. All Rocksim component handlers are subclassed from here. + */ +public abstract class BaseHandler extends ElementHandler { + + /** + * 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 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 attributes, String content, WarningSet warnings) + throws SAXException { + final C component = getComponent(); + try { + if ("Name".equals(element)) { + component.setName(content); + } + if ("KnownMass".equals(element)) { + mass = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS); + } + if ("Density".equals(element)) { + density = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_DENSITY); + } + if ("KnownCG".equals(element)) { + cg = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + } + if ("UseKnownCG".equals(element)) { + boolean override = "1".equals(content); + setOverride(component, override, mass, cg); + } + } + catch (NumberFormatException nfe) { + warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); + } + } + + @Override + public void endHandler(String element, HashMap 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. + */ + RocketComponent component = getComponent(); + updateComponentMaterial(component, materialName, getMaterialType(), density); + } + + /** + * 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; + } + + /** + * 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 in g/cm^3 + * + * @return a Material instance + */ + public static Material createCustomMaterial(Material.Type type, String name, double density) { + return Material.newMaterial(type, "RS: " + name, density, true); + } + + /** + * 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 seta + * @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; + } + +} diff --git a/src/net/sf/openrocket/file/rocksim/BodyTubeHandler.java b/src/net/sf/openrocket/file/rocksim/BodyTubeHandler.java new file mode 100644 index 00000000..6347d3b2 --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/BodyTubeHandler.java @@ -0,0 +1,100 @@ +/* + * BodyTubeHandler.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.WarningSet; +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.BodyTube; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +/** + * A SAX handler for Rocksim Body Tubes. + */ +class BodyTubeHandler extends BaseHandler { + /** + * The OpenRocket BodyTube. + */ + private final BodyTube bodyTube; + + /** + * Constructor. + * + * @param c parent component + * @throws IllegalArgumentException thrown if c is null + */ + public BodyTubeHandler(RocketComponent c) throws IllegalArgumentException { + if (c == null) { + throw new IllegalArgumentException("The parent component of a body tube may not be null."); + } + bodyTube = new BodyTube(); + c.addChild(bodyTube); + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + if ("AttachedParts".equals(element)) { + return new AttachedPartsHandler(bodyTube); + } + return PlainTextHandler.INSTANCE; + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) + throws SAXException { + super.closeElement(element, attributes, content, warnings); + + try { + if ("OD".equals(element)) { + bodyTube.setRadius(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS); + } + if ("ID".equals(element)) { + final double r = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS; + bodyTube.setInnerRadius(r); + } + if ("Len".equals(element)) { + bodyTube.setLength(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + } + if ("FinishCode".equals(element)) { + bodyTube.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket()); + } + if ("IsMotorMount".equals(element)) { + bodyTube.setMotorMount("1".equals(content)); + } + if ("EngineOverhang".equals(element)) { + bodyTube.setMotorOverhang(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + } + if ("Material".equals(element)) { + setMaterialName(content); + } + } + catch (NumberFormatException nfe) { + warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); + } + } + + /** + * Get the component this handler is working upon. + * + * @return a component + */ + @Override + public BodyTube getComponent() { + return bodyTube; + } + + /** + * Get the required type of material for this component. + * + * @return BULK + */ + public Material.Type getMaterialType() { + return Material.Type.BULK; + } +} + diff --git a/src/net/sf/openrocket/file/rocksim/FinSetHandler.java b/src/net/sf/openrocket/file/rocksim/FinSetHandler.java new file mode 100644 index 00000000..180edae5 --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/FinSetHandler.java @@ -0,0 +1,375 @@ +/* + * FinSetHandler.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.WarningSet; +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.RocketComponent; +import net.sf.openrocket.rocketcomponent.FinSet; +import net.sf.openrocket.rocketcomponent.ExternalComponent; +import net.sf.openrocket.rocketcomponent.TrapezoidFinSet; +import net.sf.openrocket.rocketcomponent.EllipticalFinSet; +import net.sf.openrocket.rocketcomponent.FreeformFinSet; +import net.sf.openrocket.rocketcomponent.IllegalFinPointException; +import net.sf.openrocket.util.Coordinate; +import org.xml.sax.SAXException; + +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; + +/** + * A SAX handler for Rocksim fin sets. Because the type of + * fin may not be known first (in Rocksim file format, the fin shape type is in the middle of the XML structure), + * and because we're using SAX not DOM, all of the fin characteristics are kept here until the closing FinSet tag. + * At that point, asOpenRocket method is called to construct the corresponding OpenRocket FinSet. + */ +class FinSetHandler extends ElementHandler { + /** + * The parent component. + */ + private final RocketComponent component; + + /** + * The name of the fin. + */ + private String name; + /** + * The Rocksim fin shape code. + */ + private int shapeCode; + /** + * The location of the fin on its parent. + */ + private double location = 0.0d; + /** + * The OpenRocket Position which gives the absolute/relative positiong for location. + */ + private RocketComponent.Position position; + /** + * The number of fins in this fin set. + */ + private int finCount; + /** + * The length of the root chord. + */ + private double rootChord = 0.0d; + /** + * The length of the tip chord. + */ + private double tipChord = 0.0d; + /** + * The length of the mid-chord (aka height). + */ + private double midChordLen = 0.0d; + /** + * The distance of the leading edge from root to top. + */ + private double sweepDistance = 0.0d; + /** + * The angle the fins have been rotated from the y-axis, if looking down the tube, in radians. + */ + private double radialAngle = 0.0d; + /** + * The thickness of the fins. + */ + private double thickness; + /** + * The finish of the fins. + */ + private ExternalComponent.Finish finish; + /** + * The shape of the tip. + */ + private int tipShapeCode; + /** + * The length of the TTW tab. + */ + private double tabLength = 0.0d; + /** + * The depth of the TTW tab. + */ + private double tabDepth = 0.0d; + /** + * The offset of the tab, from the front of the fin. + */ + private double taboffset = 0.0d; + /** + * The elliptical semi-span (height). + */ + private double semiSpan; + /** + * The list of custom points. + */ + private String pointList; + /** + * Override the Cg and mass. + */ + private boolean override = false; + /** + * 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 material name. + */ + private String materialName = ""; + /** + * The Rocksim calculated mass. + */ + private Double calcMass = 0d; + /** + * The Rocksim calculated cg. + */ + private Double calcCg = 0d; + + + /** + * Constructor. + * + * @param c the parent + * + * @throws IllegalArgumentException thrown if c is null + */ + public FinSetHandler(RocketComponent c) throws IllegalArgumentException { + if (c == null) { + throw new IllegalArgumentException("The parent component of a fin set may not be null."); + } + component = c; + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + return PlainTextHandler.INSTANCE; + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) + throws SAXException { + try { + if ("Name".equals(element)) { + name = content; + } + if ("Material".equals(element)) { + materialName = content; + } + if ("FinishCode".equals(element)) { + finish = RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket(); + } + if ("Xb".equals(element)) { + location = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("LocationMode".equals(element)) { + position = RocksimLocationMode.fromCode(Integer.parseInt(content)).asOpenRocket(); + } + if ("FinCount".equals(element)) { + finCount = Integer.parseInt(content); + } + if ("RootChord".equals(element)) { + rootChord = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("TipChord".equals(element)) { + tipChord = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("SemiSpan".equals(element)) { + semiSpan = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("MidChordLen".equals(element)) { + midChordLen = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("SweepDistance".equals(element)) { + sweepDistance = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("Thickness".equals(element)) { + thickness = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("TipShapeCode".equals(element)) { + tipShapeCode = Integer.parseInt(content); + } + if ("TabLength".equals(element)) { + tabLength = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("TabDepth".equals(element)) { + tabDepth = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("TabOffset".equals(element)) { + taboffset = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("RadialAngle".equals(element)) { + radialAngle = Double.parseDouble(content); + } + if ("ShapeCode".equals(element)) { + shapeCode = Integer.parseInt(content); + } + if ("PointList".equals(element)) { + pointList = content; + } + if ("KnownMass".equals(element)) { + mass = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS); + } + if ("Density".equals(element)) { + density = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_DENSITY); + } + if ("KnownCG".equals(element)) { + cg = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS); + } + if ("UseKnownCG".equals(element)) { + override = "1".equals(content); + } + if ("CalcMass".equals(element)) { + calcMass = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS; + } + if ("CalcCg".equals(element)) { + calcCg = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + } + catch (NumberFormatException nfe) { + warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); + } + } + + @Override + public void endHandler(String element, HashMap attributes, + String content, WarningSet warnings) throws SAXException { + //Create the fin set and correct for overrides and actual material densities + final FinSet finSet = asOpenRocket(warnings); + BaseHandler.setOverride(finSet, override, mass, cg); + if (!override && finSet.getCrossSection().equals(FinSet.CrossSection.AIRFOIL)) { + //Override mass anyway. This is done only for AIRFOIL because Rocksim does not compute different + //mass/cg for different cross sections, but OpenRocket does. This can lead to drastic differences + //in mass. To counteract that, the cross section value is retained but the mass/cg is overridden + //with the calculated values from Rocksim. This will best approximate the Rocksim design in OpenRocket. + BaseHandler.setOverride(finSet, true, calcMass, calcCg); + } + BaseHandler.updateComponentMaterial(finSet, materialName, Material.Type.BULK, density); + component.addChild(finSet); + } + + + /** + * Convert the parsed Rocksim data values in this object to an instance of OpenRocket's FinSet. + * + * @param warnings the warning set to convey incompatibilities to the user + * @return a FinSet instance + */ + public FinSet asOpenRocket(WarningSet warnings) { + FinSet result; + + if (shapeCode == 0) { + //Trapezoidal + result = new TrapezoidFinSet(); + ((TrapezoidFinSet) result).setFinShape(rootChord, tipChord, sweepDistance, midChordLen, thickness); + } + else if (shapeCode == 1) { + //Elliptical + result = new EllipticalFinSet(); + ((EllipticalFinSet) result).setHeight(semiSpan); + ((EllipticalFinSet) result).setLength(rootChord); + } + else if (shapeCode == 2) { + + result = new FreeformFinSet(); + try { + ((FreeformFinSet) result).setPoints(toCoordinates(pointList, warnings)); + } + catch (IllegalFinPointException e) { + warnings.add("Illegal fin point set. " + e.getMessage() + " Ignoring."); + } + } + else { + return null; + } + result.setThickness(thickness); + result.setName(name); + result.setFinCount(finCount); + result.setFinish(finish); + //All TTW tabs in Rocksim are relative to the front of the fin. + result.setTabRelativePosition(FinSet.TabRelativePosition.FRONT); + result.setTabHeight(tabDepth); + result.setTabLength(tabLength); + result.setTabShift(taboffset); + result.setBaseRotation(radialAngle); + result.setCrossSection(convertTipShapeCode(tipShapeCode)); + result.setRelativePosition(position); + PositionDependentHandler.setLocation(result, position, location); + return result; + + } + + /** + * Convert a Rocksim string that represents fin plan points into an array of OpenRocket coordinates. + * + * @param pointList a comma and pipe delimited string of X,Y coordinates from Rocksim. This is of the format: + *
x0,y0|x1,y1|x2,y2|... 
+ * @param warnings the warning set to convey incompatibilities to the user + * + * @return an array of OpenRocket Coordinates + */ + private Coordinate[] toCoordinates(String pointList, WarningSet warnings) { + List result = new ArrayList(); + if (pointList != null && !pointList.isEmpty()) { + String[] points = pointList.split("\\Q|\\E"); + for (String point : points) { + String[] aPoint = point.split(","); + try { + if (aPoint.length > 1) { + Coordinate c = new Coordinate( + Double.parseDouble(aPoint[0]) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, + Double.parseDouble(aPoint[1]) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + result.add(c); + } + else { + warnings.add("Invalid fin point pair."); + } + } + catch (NumberFormatException nfe) { + warnings.add("Fin point not in numeric format."); + } + } + if (!result.isEmpty()) { + //OpenRocket requires fin plan points be ordered from leading root chord to trailing root chord in the + //Coordinate array. + Coordinate last = result.get(result.size() - 1); + if (last.x == 0 && last.y == 0) { + Collections.reverse(result); + } + } + } + final Coordinate[] coords = new Coordinate[result.size()]; + return result.toArray(coords); + } + + + /** + * Convert a Rocksim tip shape to an OpenRocket CrossSection. + * + * @param tipShape the tip shape code from Rocksim + * @return a CrossSection instance + */ + private FinSet.CrossSection convertTipShapeCode(int tipShape) { + switch (tipShape) { + case 0: + return FinSet.CrossSection.SQUARE; + case 1: + return FinSet.CrossSection.ROUNDED; + case 2: + return FinSet.CrossSection.AIRFOIL; + default: + return FinSet.CrossSection.SQUARE; + } + } + +} + diff --git a/src/net/sf/openrocket/file/rocksim/InnerBodyTubeHandler.java b/src/net/sf/openrocket/file/rocksim/InnerBodyTubeHandler.java new file mode 100644 index 00000000..1c7b41c2 --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/InnerBodyTubeHandler.java @@ -0,0 +1,110 @@ +/* + * InnerBodyTubeHandler.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.WarningSet; +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.InnerTube; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +/** + * A SAX handler for Rocksim inside tubes. + */ +class InnerBodyTubeHandler extends PositionDependentHandler { + + /** + * The OpenRocket InnerTube instance. + */ + private final InnerTube bodyTube; + + /** + * Constructor. + * + * @param c the parent component + * @throws IllegalArgumentException thrown if c is null + */ + public InnerBodyTubeHandler(RocketComponent c) throws IllegalArgumentException { + if (c == null) { + throw new IllegalArgumentException("The parent component of an inner tube may not be null."); + } + bodyTube = new InnerTube(); + c.addChild(bodyTube); + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + if ("AttachedParts".equals(element)) { + return new AttachedPartsHandler(bodyTube); + } + return PlainTextHandler.INSTANCE; + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) + throws SAXException { + super.closeElement(element, attributes, content, warnings); + + try { + if ("OD".equals(element)) { + bodyTube.setOuterRadius(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS); + } + if ("ID".equals(element)) { + final double r = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS; + bodyTube.setInnerRadius(r); + } + if ("Len".equals(element)) { + bodyTube.setLength(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + } + if ("IsMotorMount".equals(element)) { + bodyTube.setMotorMount("1".equals(content)); + } + if ("EngineOverhang".equals(element)) { + bodyTube.setMotorOverhang(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + } + if ("Material".equals(element)) { + setMaterialName(content); + } + } + catch (NumberFormatException nfe) { + warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); + } + } + + /** + * Get the InnerTube component this handler is working upon. + * + * @return an InnerTube component + */ + @Override + public InnerTube getComponent() { + return bodyTube; + } + + /** + * Set the relative position onto the component. This cannot be done directly because setRelativePosition is not + * public in all components. + * + * @param position the OpenRocket position + */ + @Override + public void setRelativePosition(RocketComponent.Position position) { + bodyTube.setRelativePosition(position); + } + + /** + * Get the required type of material for this component. + * + * @return BULK + */ + @Override + public Material.Type getMaterialType() { + return Material.Type.BULK; + } + +} diff --git a/src/net/sf/openrocket/file/rocksim/LaunchLugHandler.java b/src/net/sf/openrocket/file/rocksim/LaunchLugHandler.java new file mode 100644 index 00000000..969cfdbf --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/LaunchLugHandler.java @@ -0,0 +1,103 @@ +/* + * LaunchLugHandler.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.WarningSet; +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.LaunchLug; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +/** + * The SAX handler for Rocksim Launch Lugs. + */ +class LaunchLugHandler extends PositionDependentHandler { + + /** + * The OpenRocket LaunchLug instance. + */ + private final LaunchLug lug; + + /** + * Constructor. + * + * @param c the parent + * @throws IllegalArgumentException thrown if c is null + */ + public LaunchLugHandler(RocketComponent c) throws IllegalArgumentException { + if (c == null) { + throw new IllegalArgumentException("The parent component of a launch lug may not be null."); + } + lug = new LaunchLug(); + c.addChild(lug); + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + return PlainTextHandler.INSTANCE; + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) + throws SAXException { + super.closeElement(element, attributes, content, warnings); + + try { + if ("OD".equals(element)) { + lug.setRadius(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS)); + } + if ("ID".equals(element)) { + lug.setInnerRadius(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS)); + } + if ("Len".equals(element)) { + lug.setLength(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)); + } + if ("Material".equals(element)) { + setMaterialName(content); + } + if ("FinishCode".equals(element)) { + lug.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket()); + } + } + catch (NumberFormatException nfe) { + warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); + } + } + + /** + * Get the LaunchLug component this handler is working upon. + * + * @return a LaunchLug component + */ + @Override + public LaunchLug getComponent() { + return lug; + } + + /** + * Set the relative position onto the component. This cannot be done directly because setRelativePosition is not + * public in all components. + * + * @param position the OpenRocket position + */ + @Override + public void setRelativePosition(RocketComponent.Position position) { + lug.setRelativePosition(position); + } + + /** + * Get the required type of material for this component. + * + * @return BULK + */ + @Override + public Material.Type getMaterialType() { + return Material.Type.BULK; + } +} + diff --git a/src/net/sf/openrocket/file/rocksim/MassObjectHandler.java b/src/net/sf/openrocket/file/rocksim/MassObjectHandler.java new file mode 100644 index 00000000..31ddef70 --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/MassObjectHandler.java @@ -0,0 +1,110 @@ +/* + * MassObjectHandler.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.WarningSet; +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.MassComponent; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +/** + * A SAX handler for Rocksim's MassObject XML type. + */ +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. + */ + public static final int MASS_LEN_FUDGE_FACTOR = 100; + + /** + * The OpenRocket MassComponent - counterpart to the RS MassObject. + */ + private final MassComponent mass; + + /** + * Constructor. + *l + * @param c the parent component + * + * @throws IllegalArgumentException thrown if c is null + */ + public MassObjectHandler(RocketComponent c) throws IllegalArgumentException { + if (c == null) { + throw new IllegalArgumentException("The parent component of a mass component may not be null."); + } + mass = new MassComponent(); + c.addChild(mass); + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + return PlainTextHandler.INSTANCE; + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) + throws SAXException { + super.closeElement(element, attributes, content, warnings); + try { + if ("Len".equals(element)) { + mass.setLength(Double.parseDouble(content) / (RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH * MASS_LEN_FUDGE_FACTOR)); + } + if ("KnownMass".equals(element)) { + mass.setComponentMass(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS); + } + if ("KnownCG".equals(element)) { + //Setting the CG of the Mass Object to 0 is important because of the different ways that Rocksim and + //OpenRocket treat mass objects. Rocksim treats them as points (even though the data file contains a + //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); + } + } + catch (NumberFormatException nfe) { + warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); + } + } + + /** + * Get the component this handler is working upon. + * + * @return a component + */ + @Override + public MassComponent getComponent() { + return mass; + } + + /** + * Set the relative position onto the component. This cannot be done directly because setRelativePosition is not + * public in all components. + * + * @param position the OpenRocket position + */ + public void setRelativePosition(RocketComponent.Position position) { + mass.setRelativePosition(position); + } + + /** + * Get the required type of material for this component. Does not apply to MassComponents. + * + * @return BULK + */ + @Override + public Material.Type getMaterialType() { + return Material.Type.BULK; + } + +} diff --git a/src/net/sf/openrocket/file/rocksim/NoseConeHandler.java b/src/net/sf/openrocket/file/rocksim/NoseConeHandler.java new file mode 100644 index 00000000..6dc4efa3 --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/NoseConeHandler.java @@ -0,0 +1,147 @@ +/* + * NoseConeHandler.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.WarningSet; +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.NoseCone; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.Transition; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +/** + * The SAX nose cone handler for Rocksim NoseCones. + */ +class NoseConeHandler extends BaseHandler { + + /** + * The OpenRocket NoseCone. + */ + private final NoseCone noseCone = new NoseCone(); + + /** + * The wall thickness. Used for hollow nose cones. + */ + private double thickness = 0d; + + /** + * Constructor. + * + * @param c the parent component to the nosecone + * @throws IllegalArgumentException thrown if c is null + */ + public NoseConeHandler(RocketComponent c) throws IllegalArgumentException { + if (c == null) { + throw new IllegalArgumentException("The parent component of a nose cone may not be null."); + } + c.addChild(noseCone); + noseCone.setAftRadiusAutomatic(false); + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + //Nose cones in Rocksim may have attached parts - namely Mass Objects - as children. + if ("AttachedParts".equals(element)) { + return new AttachedPartsHandler(noseCone); + } + return PlainTextHandler.INSTANCE; + } + + @Override + public void closeElement(String element, HashMap attributes, + String content, WarningSet warnings) throws SAXException { + super.closeElement(element, attributes, content, warnings); + + try { + if ("ShapeCode".equals(element)) { + noseCone.setType(RocksimNoseConeCode.fromCode(Integer.parseInt(content)).asOpenRocket()); + } + if ("Len".equals(element)) { + noseCone.setLength(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)); + } + if ("BaseDia".equals(element)) { + noseCone.setAftRadius(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS)); + } + if ("WallThickness".equals(element)) { + thickness = Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + } + if ("ShoulderOD".equals(element)) { + noseCone.setAftShoulderRadius(Math.max(0, Double.parseDouble( + content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS)); + } + if ("ShoulderLen".equals(element)) { + noseCone.setAftShoulderLength(Math.max(0, Double.parseDouble( + content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)); + } + if ("ShapeParameter".equals(element)) { + //The Rocksim ShapeParameter only applies to certain shapes, although it is included + //in the design file for all nose cones. Applying it when it should not be causes oddities so + //a check is made for the allowable shapes. + if (Transition.Shape.POWER.equals(noseCone.getType()) || + Transition.Shape.HAACK.equals(noseCone.getType()) || + Transition.Shape.PARABOLIC.equals(noseCone.getType())) { + noseCone.setShapeParameter(Double.parseDouble(content)); + } + } + if ("ConstructionType".equals(element)) { + int typeCode = Integer.parseInt(content); + if (typeCode == 0) { + //SOLID + noseCone.setFilled(true); + } + else if (typeCode == 1) { + //HOLLOW + noseCone.setFilled(false); + } + } + if ("FinishCode".equals(element)) { + noseCone.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket()); + } + if ("Material".equals(element)) { + setMaterialName(content); + } + } + catch (NumberFormatException nfe) { + warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); + } + } + + @Override + public void endHandler(String element, HashMap attributes, String content, WarningSet warnings) + throws SAXException { + super.endHandler(element, attributes, content, warnings); + + if (noseCone.isFilled()) { + noseCone.setAftShoulderThickness(noseCone.getAftShoulderRadius()); + } + else { + noseCone.setThickness(thickness); + noseCone.setAftShoulderThickness(thickness); + } + } + + /** + * Get the nose cone component this handler is working upon. + * + * @return a nose cone component + */ + @Override + public NoseCone getComponent() { + return noseCone; + } + + /** + * Get the required type of material for this component. + * + * @return BULK + */ + public Material.Type getMaterialType() { + return Material.Type.BULK; + } + +} diff --git a/src/net/sf/openrocket/file/rocksim/ParachuteHandler.java b/src/net/sf/openrocket/file/rocksim/ParachuteHandler.java new file mode 100644 index 00000000..6f683a45 --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/ParachuteHandler.java @@ -0,0 +1,132 @@ +/* + * ParachuteHandler.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.WarningSet; +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.BodyTube; +import net.sf.openrocket.rocketcomponent.InnerTube; +import net.sf.openrocket.rocketcomponent.Parachute; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +/** + * A SAX handler for Rocksim's Parachute XML type. + *

+ */ +class ParachuteHandler extends PositionDependentHandler { + /** + * The OpenRocket Parachute instance + */ + private final Parachute chute; + /** + * The shroud line density. + */ + private double shroudLineDensity = 0.0d; + + /** + * Constructor. + * + * @param c the parent component + * @throws IllegalArgumentException thrown if c is null + */ + public ParachuteHandler(RocketComponent c) throws IllegalArgumentException { + if (c == null) { + throw new IllegalArgumentException("The parent of a parachute may not be null."); + } + chute = new Parachute(); + c.addChild(chute); + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + return PlainTextHandler.INSTANCE; + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) + throws SAXException { + super.closeElement(element, attributes, content, warnings); + try { + if ("Dia".equals(element)) { + chute.setDiameter(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + /* Rocksim doesn't have a packed parachute radius, so we approximate it. */ + double packed; + RocketComponent parent = chute.getParent(); + if (parent instanceof BodyTube) { + packed = ((BodyTube) parent).getRadius() * 0.9; + } + else if (parent instanceof InnerTube) { + packed = ((InnerTube) parent).getInnerRadius() * 0.9; + } + else { + packed = chute.getDiameter() * 0.025; + } + chute.setRadius(packed); + } + if ("ShroudLineCount".equals(element)) { + chute.setLineCount(Math.max(0, Integer.parseInt(content))); + } + if ("ShroudLineLen".equals(element)) { + chute.setLineLength(Math.max(0, Double.parseDouble( + content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)); + } + if ("SpillHoleDia".equals(element)) { + //Not supported in OpenRocket + double spillHoleRadius = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS; + warnings.add("Parachute spill holes are not supported. Ignoring."); + } + if ("ShroudLineMassPerMM".equals(element)) { + shroudLineDensity = Double.parseDouble(content) * 10d/ RocksimHandler.ROCKSIM_TO_OPENROCKET_DENSITY; + } + if ("ShroudLineMaterial".equals(element)) { + chute.setLineMaterial(BaseHandler.createCustomMaterial(Material.Type.LINE, content, shroudLineDensity)); + } + if ("DragCoefficient".equals(element)) { + chute.setCD(Double.parseDouble(content)); + } + if ("Material".equals(element)) { + setMaterialName(content); + } + } + catch (NumberFormatException nfe) { + warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); + } + } + + /** + * Get the component this handler is working upon. + * + * @return a component + */ + public Parachute getComponent() { + return chute; + } + + /** + * Set the relative position onto the component. This cannot be done directly because setRelativePosition is not + * public in all components. + * + * @param position the OpenRocket position + */ + public void setRelativePosition(RocketComponent.Position position) { + chute.setRelativePosition(position); + } + + /** + * Get the required type of material for this component. + * + * @return BULK + */ + @Override + public Material.Type getMaterialType() { + return Material.Type.SURFACE; + } + +} + diff --git a/src/net/sf/openrocket/file/rocksim/PositionDependentHandler.java b/src/net/sf/openrocket/file/rocksim/PositionDependentHandler.java new file mode 100644 index 00000000..9d457227 --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/PositionDependentHandler.java @@ -0,0 +1,80 @@ +/* + * PositionDependentHandler.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +/** + * An abstract base class that handles position dependencies for all lower level components that + * are position aware. + */ +public abstract class PositionDependentHandler extends BaseHandler { + + /** Temporary position value. */ + private Double positionValue; + + /** Temporary position. */ + private RocketComponent.Position position; + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) + throws SAXException { + super.closeElement(element, attributes, content, warnings); + if ("Xb".equals(element)) { + positionValue = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("LocationMode".equals(element)) { + position = RocksimLocationMode.fromCode(Integer.parseInt( + content)).asOpenRocket(); + } + } + + /** + * This method sets the position information onto the component. Rocksim splits the location/position + * information into two disparate data elements. Both pieces of data are necessary to map into OpenRocket's + * position model. + * + * @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 + */ + @Override + public void endHandler(String element, HashMap attributes, + String content, WarningSet warnings) throws SAXException { + super.endHandler(element, attributes, content, warnings); + setRelativePosition(position); + setLocation(getComponent(), position, positionValue); + } + + /** + * Set the relative position onto the component. This cannot be done directly because setRelativePosition is not + * public in all components. + * + * @param position the OpenRocket position + */ + protected abstract void setRelativePosition(RocketComponent.Position position); + + /** + * Set the position of a component. + * + * @param component the component + * @param position the relative position + * @param location the actual position value + */ + public static void setLocation(RocketComponent component, RocketComponent.Position position, double location) { + if (position.equals(RocketComponent.Position.BOTTOM)) { + component.setPositionValue(-1d * location); + } + else { + component.setPositionValue(location); + } + } + +} diff --git a/src/net/sf/openrocket/file/rocksim/RingHandler.java b/src/net/sf/openrocket/file/rocksim/RingHandler.java new file mode 100644 index 00000000..ccfcfb06 --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/RingHandler.java @@ -0,0 +1,100 @@ +/* + * RingHandler.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.WarningSet; +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.CenteringRing; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +/** + * A SAX handler for centering rings and bulkheads. + */ +class RingHandler extends PositionDependentHandler { + + /** + * The OpenRocket Ring. + */ + private final CenteringRing ring; + + /** + * Constructor. + * + * @param c the parent component + * @throws IllegalArgumentException thrown if c is null + */ + public RingHandler(RocketComponent c) throws IllegalArgumentException { + if (c == null) { + throw new IllegalArgumentException("The parent of a ring may not be null."); + } + ring = new CenteringRing(); + c.addChild(ring); + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + return PlainTextHandler.INSTANCE; + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) + throws SAXException { + super.closeElement(element, attributes, content, warnings); + + try { + if ("OD".equals(element)) { + ring.setOuterRadius(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS); + } + if ("ID".equals(element)) { + ring.setInnerRadius(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS); + } + if ("Len".equals(element)) { + ring.setLength(Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + } + if ("Material".equals(element)) { + setMaterialName(content); + } + } + catch (NumberFormatException nfe) { + warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); + } + } + + /** + * Get the ring component this handler is working upon. + * + * @return a component + */ + @Override + public CenteringRing getComponent() { + return ring; + } + + /** + * Set the relative position onto the component. This cannot be done directly because setRelativePosition is not + * public in all components. + * + * @param position the OpenRocket position + */ + @Override + public void setRelativePosition(RocketComponent.Position position) { + ring.setRelativePosition(position); + } + + /** + * Get the required type of material for this component. + * + * @return BULK + */ + @Override + public Material.Type getMaterialType() { + return Material.Type.BULK; + } +} + diff --git a/src/net/sf/openrocket/file/rocksim/RocksimFinishCode.java b/src/net/sf/openrocket/file/rocksim/RocksimFinishCode.java new file mode 100644 index 00000000..cf1748bc --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/RocksimFinishCode.java @@ -0,0 +1,61 @@ +/* + * RocksimFinishCode.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.rocketcomponent.ExternalComponent; + +/** + * Models the finish of a component. + */ +enum RocksimFinishCode { + POLISHED(0, ExternalComponent.Finish.POLISHED), + GLOSS(1, ExternalComponent.Finish.SMOOTH), + MATT(2, ExternalComponent.Finish.NORMAL), + UNFINISHED(3, ExternalComponent.Finish.UNFINISHED); + + /** The Rocksim code (from XML). */ + private final int ordinal; + + /** The corresponding OpenRocket finish. */ + private final ExternalComponent.Finish finish; + + /** + * Constructor. + * + * @param idx the Rocksim enum value + * @param theFinish the OpenRocket finish + */ + private RocksimFinishCode(int idx, ExternalComponent.Finish theFinish) { + ordinal = idx; + finish = theFinish; + } + + /** + * Get the OpenRocket finish. + * + * @return a Finish instance + */ + public ExternalComponent.Finish asOpenRocket() { + return finish; + } + + /** + * Lookup an instance of this enum from a Rocksim value. + * + * @param rocksimFinishCode the Rocksim value + * + * @return an instance of this enum; Defaults to MATT + */ + public static RocksimFinishCode fromCode(int rocksimFinishCode) { + RocksimFinishCode[] values = values(); + for (RocksimFinishCode value : values) { + if (value.ordinal == rocksimFinishCode) { + return value; + } + } + return MATT; //Default + } + +} + diff --git a/src/net/sf/openrocket/file/rocksim/RocksimHandler.java b/src/net/sf/openrocket/file/rocksim/RocksimHandler.java new file mode 100644 index 00000000..4cd29afd --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/RocksimHandler.java @@ -0,0 +1,363 @@ +/* + * RocksimHandler.java + * + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.Warning; +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.document.OpenRocketDocument; +import net.sf.openrocket.file.simplesax.ElementHandler; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.Stage; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +/** + * This class is a Sax element handler for Rocksim version 9 design files. It parses the Rocksim file (typically + * a .rkt extension) and creates corresponding OpenRocket components. This is a best effort approach and may not + * be an exact replica. + *

+ * Limitations: Rocksim flight simulations are not imported; tube fins are not supported; Rocksim 'pods' are not supported. + */ +public class RocksimHandler extends ElementHandler { + + /** + * Length conversion. Rocksim is in millimeters, OpenRocket in meters. + */ + public static final int ROCKSIM_TO_OPENROCKET_LENGTH = 1000; + + /** + * Mass conversion. Rocksim is in grams, OpenRocket in kilograms. + */ + public static final int ROCKSIM_TO_OPENROCKET_MASS = 1000; + + /** + * Density conversion. Rocksim is in milligrams/cubic centimeter, OpenRocket in grams/cubic centimeter. + */ + public static final int ROCKSIM_TO_OPENROCKET_DENSITY = 1; + + /** + * Radius conversion. Rocksim is always in diameters, OpenRocket mostly in radius. + */ + public static final int ROCKSIM_TO_OPENROCKET_RADIUS = 2 * ROCKSIM_TO_OPENROCKET_LENGTH; + + /** + * The main content handler. + */ + private RocksimContentHandler handler = null; + + /** + * Return the OpenRocketDocument read from the file, or null if a document + * has not been read yet. + * + * @return the document read, or null. + */ + public OpenRocketDocument getDocument() { + return handler.getDocument(); + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, + WarningSet warnings) { + + // Check for unknown elements + if (!element.equals("RockSimDocument")) { + warnings.add(Warning.fromString("Unknown element " + element + ", ignoring.")); + return null; + } + + // Check for first call + if (handler != null) { + warnings.add(Warning.fromString("Multiple document elements found, ignoring later " + + "ones.")); + return null; + } + + handler = new RocksimContentHandler(); + return handler; + } + +} + +/** + * Handles the content of the tag. + */ +class RocksimContentHandler extends ElementHandler { + /** + * The OpenRocketDocument that is the container for the rocket. + */ + private final OpenRocketDocument doc; + + /** + * The top-level component, from which all child components are added. + */ + private final Rocket rocket; + + /** + * The rocksim file version. + */ + private String version; + + /** + * Constructor. + */ + public RocksimContentHandler() { + this.rocket = new Rocket(); + this.doc = new OpenRocketDocument(rocket); + } + + /** + * Get the OpenRocket document that has been created from parsing the Rocksim design file. + * + * @return the instantiated OpenRocketDocument + */ + public OpenRocketDocument getDocument() { + return doc; + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, + WarningSet warnings) { + if ("DesignInformation".equals(element)) { + //The next sub-element is "RocketDesign", which is really the only thing that matters. Rather than + //create another handler just for that element, handle it here. + return this; + } + if ("FileVersion".equals(element)) { + return PlainTextHandler.INSTANCE; + } + if ("RocketDesign".equals(element)) { + return new RocketDesignHandler(rocket); + } + return null; + } + + @Override + public void closeElement(String element, HashMap attributes, + String content, WarningSet warnings) throws SAXException { + /** + * SAX handler for Rocksim file version number. The value is not used currently, but could be used in the future + * for backward/forward compatibility reasons (different lower level handlers could be called via a strategy pattern). + */ + if ("FileVersion".equals(element)) { + version = content; + } + } + + /** + * Answer the file version. + * + * @return the version of the Rocksim design file + */ + public String getVersion() { + return version; + } +} + + +/** + * A SAX handler for the high level Rocksim design. This structure includes sub-structures for each of the stages. + * Correct functioning of this handler is predicated on the stage count element appearing before the actual stage parts + * structures. If that invariant is not true, then behavior will be unpredictable. + */ +class RocketDesignHandler extends ElementHandler { + /** + * The parent component. + */ + private final RocketComponent component; + /** + * The parsed stage count. Defaults to 1. + */ + private int stageCount = 1; + /** + * The overridden stage 1 mass. + */ + private double stage1Mass = 0d; + /** + * The overridden stage 2 mass. + */ + private double stage2Mass = 0d; + /** + * The overridden stage 3 mass. + */ + private double stage3Mass = 0d; + /** + * The overridden stage 1 Cg. + */ + private double stage1CG = 0d; + /** + * The overridden stage 2 Cg. + */ + private double stage2CG = 0d; + /** + * The overridden stage 3 Cg. + */ + private double stage3CG = 0d; + + /** + * Constructor. + * + * @param c the parent component + */ + public RocketDesignHandler(RocketComponent c) { + component = c; + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + /** + * In Rocksim stages are from the top down, so a single stage rocket is actually stage '3'. A 2-stage + * rocket defines stage '2' as the initial booster with stage '3' sitting atop it. And so on. + */ + if ("Stage3Parts".equals(element)) { + final Stage stage = new Stage(); + if (stage3Mass > 0.0d) { + stage.setMassOverridden(true); + stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override + stage.setOverrideMass(stage3Mass); + } + if (stage3CG > 0.0d) { + stage.setCGOverridden(true); + stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override + stage.setOverrideCGX(stage3CG); + } + component.addChild(stage); + return new StageHandler(stage); + } + if ("Stage2Parts".equals(element)) { + if (stageCount >= 2) { + final Stage stage = new Stage(); + if (stage2Mass > 0.0d) { + stage.setMassOverridden(true); + stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override + stage.setOverrideMass(stage2Mass); + } + if (stage2CG > 0.0d) { + stage.setCGOverridden(true); + stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override + stage.setOverrideCGX(stage2CG); + } + component.addChild(stage); + return new StageHandler(stage); + } + } + if ("Stage1Parts".equals(element)) { + if (stageCount == 3) { + final Stage stage = new Stage(); + if (stage1Mass > 0.0d) { + stage.setMassOverridden(true); + stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override + stage.setOverrideMass(stage1Mass); + } + if (stage1CG > 0.0d) { + stage.setCGOverridden(true); + stage.setOverrideSubcomponents(true); //Rocksim does not support this type of override + stage.setOverrideCGX(stage1CG); + } + component.addChild(stage); + return new StageHandler(stage); + } + } + if ("Name".equals(element)) { + return PlainTextHandler.INSTANCE; + } + if ("StageCount".equals(element)) { + return PlainTextHandler.INSTANCE; + } + if ("Stage3Mass".equals(element)) { + return PlainTextHandler.INSTANCE; + } + if ("Stage2Mass".equals(element)) { + return PlainTextHandler.INSTANCE; + } + if ("Stage1Mass".equals(element)) { + return PlainTextHandler.INSTANCE; + } + if ("Stage3CG".equals(element)) { + return PlainTextHandler.INSTANCE; + } + if ("Stage2CGAlone".equals(element)) { + return PlainTextHandler.INSTANCE; + } + if ("Stage1CGAlone".equals(element)) { + return PlainTextHandler.INSTANCE; + } + return null; + } + + @Override + public void closeElement(String element, HashMap attributes, + String content, WarningSet warnings) throws SAXException { + try { + if ("Name".equals(element)) { + component.setName(content); + } + if ("StageCount".equals(element)) { + stageCount = Integer.parseInt(content); + } + if ("Stage3Mass".equals(element)) { + stage3Mass = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS; + } + if ("Stage2Mass".equals(element)) { + stage2Mass = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS; + } + if ("Stage1Mass".equals(element)) { + stage1Mass = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS; + } + if ("Stage3CG".equals(element)) { + stage3CG = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("Stage2CGAlone".equals(element)) { + stage2CG = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + if ("Stage1CGAlone".equals(element)) { + stage1CG = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH; + } + } + catch (NumberFormatException nfe) { + warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); + } + } + +} + +/** + * A SAX handler for a Rocksim stage. + */ +class StageHandler extends ElementHandler { + /** + * The parent OpenRocket component. + */ + private final RocketComponent component; + + /** + * Constructor. + * + * @param c the parent component + * @throws IllegalArgumentException thrown if c is null + */ + public StageHandler(RocketComponent c) throws IllegalArgumentException { + if (c == null) { + throw new IllegalArgumentException("The stage component may not be null."); + } + component = c; + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + if ("NoseCone".equals(element)) { + return new NoseConeHandler(component); + } + if ("BodyTube".equals(element)) { + return new BodyTubeHandler(component); + } + if ("Transition".equals(element)) { + return new TransitionHandler(component); + } + return null; + } +} diff --git a/src/net/sf/openrocket/file/rocksim/RocksimLoader.java b/src/net/sf/openrocket/file/rocksim/RocksimLoader.java new file mode 100644 index 00000000..70953415 --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/RocksimLoader.java @@ -0,0 +1,57 @@ +/* + * RocksimLoader.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.file.RocketLoader; +import net.sf.openrocket.file.RocketLoadException; +import net.sf.openrocket.file.simplesax.SimpleSAX; +import net.sf.openrocket.document.OpenRocketDocument; + +import java.io.InputStream; +import java.io.IOException; + +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * This class is the main entry point for Rocksim design file imported to OpenRocket. Currently only Rocksim v9 + * file formats are supported, although it is possible that v8 formats will work for most components. + * + * In the cases of v9 components that exist in Rocksim but have no corollary in OpenRocket a message is added to + * a warning set and presented to the user. In effect, this loading is a 'best-effort' mapping and is not meant to + * be an exact representation of any possible Rocksim design in an OpenRocket format. + * + * Rocksim simulations are not imported. + * + * Wish List: + * Material interface (or at least make them abstract in RocketComponent) + * setMaterial + * getMaterial + */ +public class RocksimLoader extends RocketLoader { + /** + * This method is called by the default implementations of {@link #load(java.io.File)} + * and {@link #load(java.io.InputStream)} to load the rocket. + * + * @throws net.sf.openrocket.file.RocketLoadException + * if an error occurs during loading. + */ + @Override + protected OpenRocketDocument loadFromStream(InputStream source) throws IOException, RocketLoadException { + + InputSource xmlSource = new InputSource(source); + + RocksimHandler handler = new RocksimHandler(); + + try { + SimpleSAX.readXML(xmlSource, handler, warnings); + } catch (SAXException e) { + throw new RocketLoadException("Malformed XML in input.", e); + } + + final OpenRocketDocument document = handler.getDocument(); + document.setFile(null); + return document; + } +} diff --git a/src/net/sf/openrocket/file/rocksim/RocksimLocationMode.java b/src/net/sf/openrocket/file/rocksim/RocksimLocationMode.java new file mode 100644 index 00000000..4b30703b --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/RocksimLocationMode.java @@ -0,0 +1,59 @@ +/* + * RocksimLocationMode.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.rocketcomponent.RocketComponent; + +/** + * Models the relative position of parts on a rocket. Maps from Rocksim's notion to OpenRocket's. + */ +enum RocksimLocationMode { + FRONT_OF_OWNING_PART (0, RocketComponent.Position.TOP), + FROM_TIP_OF_NOSE (1, RocketComponent.Position.ABSOLUTE), + BACK_OF_OWNING_PART (2, RocketComponent.Position.BOTTOM); + + /** The value Rocksim uses internally (and in the XML file). */ + private final int ordinal; + + /** The OpenRocket position equivalent. */ + private final RocketComponent.Position position; + + /** + * Constructor. + * + * @param idx the rocksim enum value + * @param theOpenRocketPosition the corresponding OpenRocket position + */ + RocksimLocationMode(int idx, RocketComponent.Position theOpenRocketPosition) { + ordinal = idx; + position = theOpenRocketPosition; + } + + /** + * Get the OpenRocket position. + * + * @return the position instance + */ + public RocketComponent.Position asOpenRocket() { + return position; + } + + /** + * Lookup an instance of this class from a rocksim enum value. + * + * @param rocksimCode the rocksim enum value + * + * @return an instance of this enum + */ + public static RocksimLocationMode fromCode(int rocksimCode) { + RocksimLocationMode[] values = values(); + for (RocksimLocationMode value : values) { + if (value.ordinal == rocksimCode) { + return value; + } + } + return FRONT_OF_OWNING_PART; + } + +} \ No newline at end of file diff --git a/src/net/sf/openrocket/file/rocksim/RocksimNoseConeCode.java b/src/net/sf/openrocket/file/rocksim/RocksimNoseConeCode.java new file mode 100644 index 00000000..8cd7c82a --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/RocksimNoseConeCode.java @@ -0,0 +1,61 @@ +/* + * RocksimNoseConeCode.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.rocketcomponent.Transition; + +/** + * Models the nose cone shape of a rocket. Maps from Rocksim's notion to OpenRocket's. + */ +enum RocksimNoseConeCode { + CONICAL (0, Transition.Shape.CONICAL), + OGIVE (1, Transition.Shape.OGIVE), + PARABOLIC (2, Transition.Shape.ELLIPSOID), //Rocksim' PARABOLIC most closely resembles an ELLIPSOID in OpenRocket + ELLIPTICAL (3, Transition.Shape.ELLIPSOID), + POWER_SERIES (4, Transition.Shape.POWER), + PARABOLIC_SERIES(5, Transition.Shape.PARABOLIC), + HAACK (6, Transition.Shape.HAACK); + + /** The Rocksim enumeration value. Sent in XML. */ + private final int ordinal; + + /** The corresponding OpenRocket shape. */ + private final Transition.Shape shape; + + /** + * Constructor. + * + * @param idx the Rocksim shape code + * @param aShape the corresponding OpenRocket shape + */ + private RocksimNoseConeCode(int idx, Transition.Shape aShape) { + ordinal = idx; + shape = aShape; + } + + /** + * Get the OpenRocket shape that corresponds to the Rocksim shape. + * + * @return a shape + */ + public Transition.Shape asOpenRocket() { + return shape; + } + + /** + * Lookup an instance of this enum based upon the Rocksim code. + * + * @param rocksimShapeCode the Rocksim code (from XML) + * @return an instance of this enum + */ + public static RocksimNoseConeCode fromCode(int rocksimShapeCode) { + RocksimNoseConeCode[] values = values(); + for (RocksimNoseConeCode value : values) { + if (value.ordinal == rocksimShapeCode) { + return value; + } + } + return PARABOLIC; //Default + } +} diff --git a/src/net/sf/openrocket/file/rocksim/StreamerHandler.java b/src/net/sf/openrocket/file/rocksim/StreamerHandler.java new file mode 100644 index 00000000..9db287d2 --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/StreamerHandler.java @@ -0,0 +1,95 @@ +/* + * StreamerHandler.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.WarningSet; +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.RocketComponent; +import net.sf.openrocket.rocketcomponent.Streamer; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +/** + * A SAX handler for Streamer components. + */ +class StreamerHandler extends PositionDependentHandler { + + /** + * The OpenRocket Streamer. + */ + private final Streamer streamer; + + /** + * Constructor. + * + * @param c the parent component + * @throws IllegalArgumentException thrown if c is null + */ + public StreamerHandler(RocketComponent c) throws IllegalArgumentException { + if (c == null) { + throw new IllegalArgumentException("The parent of a streamer may not be null."); + } + streamer = new Streamer(); + c.addChild(streamer); + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + return PlainTextHandler.INSTANCE; + } + + @Override + public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) + throws SAXException { + super.closeElement(element, attributes, content, warnings); + + try { + if ("Width".equals(element)) { + streamer.setStripWidth(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)); + } + if ("Len".equals(element)) { + streamer.setStripLength(Math.max(0, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)); + } + if ("DragCoefficient".equals(element)) { + streamer.setCD(Double.parseDouble(content)); + } + if ("Material".equals(element)) { + setMaterialName(content); + } + } + catch (NumberFormatException nfe) { + warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); + } + } + + @Override + public Streamer getComponent() { + return streamer; + } + + /** + * Set the relative position onto the component. This cannot be done directly because setRelativePosition is not + * public in all components. + * + * @param position the OpenRocket position + */ + @Override + public void setRelativePosition(RocketComponent.Position position) { + streamer.setRelativePosition(position); + } + + /** + * Get the required type of material for this component. + * + * @return BULK + */ + @Override + public Material.Type getMaterialType() { + return Material.Type.SURFACE; + } +} + diff --git a/src/net/sf/openrocket/file/rocksim/TransitionHandler.java b/src/net/sf/openrocket/file/rocksim/TransitionHandler.java new file mode 100644 index 00000000..1f3b02e1 --- /dev/null +++ b/src/net/sf/openrocket/file/rocksim/TransitionHandler.java @@ -0,0 +1,151 @@ +/* + * TransitionHandler.java + */ +package net.sf.openrocket.file.rocksim; + +import net.sf.openrocket.aerodynamics.WarningSet; +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.RocketComponent; +import net.sf.openrocket.rocketcomponent.Transition; +import org.xml.sax.SAXException; + +import java.util.HashMap; + +/** + * The SAX handler for Transition components. + */ +class TransitionHandler extends BaseHandler { + /** + * The OpenRocket Transition. + */ + private final Transition transition = new Transition(); + + /** + * The wall thickness. Used for hollow nose cones. + */ + private double thickness = 0d; + + /** + * Constructor. + * + * @param c the parent component + * @throws IllegalArgumentException thrown if c is null + */ + public TransitionHandler(RocketComponent c) throws IllegalArgumentException { + if (c == null) { + throw new IllegalArgumentException("The parent of a transition may not be null."); + } + c.addChild(transition); + } + + @Override + public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) { + return PlainTextHandler.INSTANCE; + } + + @Override + public void closeElement(String element, HashMap attributes, + String content, WarningSet warnings) throws SAXException { + super.closeElement(element, attributes, content, warnings); + + try { + if ("ShapeCode".equals(element)) { + transition.setType(RocksimNoseConeCode.fromCode(Integer.parseInt(content)).asOpenRocket()); + } + if ("Len".equals(element)) { + transition.setLength(Math.max(0, Double.parseDouble( + content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)); + } + if ("FrontDia".equals(element)) { + transition.setForeRadius(Math.max(0, Double.parseDouble( + content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS)); + } + if ("RearDia".equals(element)) { + transition.setAftRadius(Math.max(0, Double.parseDouble( + content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS)); + } + if ("WallThickness".equals(element)) { + thickness = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + } + if ("FrontShoulderDia".equals(element)) { + transition.setForeShoulderRadius(Math.max(0d, Double.parseDouble( + content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS)); + } + if ("RearShoulderDia".equals(element)) { + transition.setAftShoulderRadius(Math.max(0d, Double.parseDouble( + content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS)); + } + if ("FrontShoulderLen".equals(element)) { + transition.setForeShoulderLength(Math.max(0d, Double.parseDouble( + content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)); + } + if ("RearShoulderLen".equals(element)) { + transition.setAftShoulderLength(Math.max(0d, Double.parseDouble( + content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH)); + } + if ("ShapeParameter".equals(element)) { + if (Transition.Shape.POWER.equals(transition.getType()) || + Transition.Shape.HAACK.equals(transition.getType()) || + Transition.Shape.PARABOLIC.equals(transition.getType())) { + transition.setShapeParameter(Double.parseDouble(content)); + } + } + if ("ConstructionType".equals(element)) { + int typeCode = Integer.parseInt(content); + if (typeCode == 0) { + //SOLID + transition.setFilled(true); + } + else if (typeCode == 1) { + //HOLLOW + transition.setFilled(false); + } + } + if ("FinishCode".equals(element)) { + transition.setFinish(RocksimFinishCode.fromCode(Integer.parseInt(content)).asOpenRocket()); + } + if ("Material".equals(element)) { + setMaterialName(content); + } + } + catch (NumberFormatException nfe) { + warnings.add("Could not convert " + element + " value of " + content + ". It is expected to be a number."); + } + } + + @Override + public void endHandler(String element, HashMap attributes, String content, WarningSet warnings) + throws SAXException { + super.endHandler(element, attributes, content, warnings); + + if (transition.isFilled()) { + transition.setAftShoulderThickness(transition.getAftShoulderRadius()); + transition.setForeShoulderThickness(transition.getForeShoulderRadius()); + } + else { + transition.setThickness(thickness); + transition.setAftShoulderThickness(thickness); + transition.setForeShoulderThickness(thickness); + } + } + + + @Override + public Transition getComponent() { + return transition; + } + + /** + * Get the required type of material for this component. + * + * @return BULK + */ + public Material.Type getMaterialType() { + return Material.Type.BULK; + } + + +} + diff --git a/src/net/sf/openrocket/gui/main/BasicFrame.java b/src/net/sf/openrocket/gui/main/BasicFrame.java index f8fb7370..a2a18e14 100644 --- a/src/net/sf/openrocket/gui/main/BasicFrame.java +++ b/src/net/sf/openrocket/gui/main/BasicFrame.java @@ -105,24 +105,19 @@ public class BasicFrame extends JFrame { private static final RocketSaver ROCKET_SAVER = new OpenRocketSaver(); - /** - * File filter for filtering only rocket designs. - */ - private static final FileFilter ROCKET_DESIGN_FILTER = new FileFilter() { - @Override - public String getDescription() { - return "OpenRocket designs (*.ork)"; - } - @Override - public boolean accept(File f) { - if (f.isDirectory()) - return true; - String name = f.getName().toLowerCase(); - return name.endsWith(".ork") || name.endsWith(".ork.gz"); - } - }; - - + // FileFilters for different types of rocket design files + private static final FileFilter ALL_DESIGNS_FILTER = + new SimpleFileFilter("All rocket designs (*.ork; *.rkt)", + ".ork", ".ork.gz", ".rkt", ".rkt.gz"); + + private static final FileFilter OPENROCKET_DESIGN_FILTER = + new SimpleFileFilter("OpenRocket designs (*.ork)", ".ork", ".ork.gz"); + + private static final FileFilter ROCKSIM_DESIGN_FILTER = + new SimpleFileFilter("RockSim designs (*.rkt)", ".rkt", ".rkt.gz"); + + + public static final int COMPONENT_TAB = 0; public static final int SIMULATION_TAB = 1; @@ -757,7 +752,13 @@ public class BasicFrame extends JFrame { private void openAction() { JFileChooser chooser = new JFileChooser(); - chooser.setFileFilter(ROCKET_DESIGN_FILTER); + + chooser.addChoosableFileFilter(ALL_DESIGNS_FILTER); + chooser.addChoosableFileFilter(OPENROCKET_DESIGN_FILTER); + chooser.addChoosableFileFilter(ROCKSIM_DESIGN_FILTER); + chooser.setFileFilter(ALL_DESIGNS_FILTER); + + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setMultiSelectionEnabled(true); chooser.setCurrentDirectory(Prefs.getDefaultDirectory()); if (chooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) @@ -782,7 +783,6 @@ public class BasicFrame extends JFrame { - private static boolean open(URL url, BasicFrame parent) { String filename = null; @@ -953,19 +953,35 @@ public class BasicFrame extends JFrame { File file = document.getFile(); if (file==null) { return saveAsAction(); - } else { - return saveAs(file); } + + // Saving RockSim designs is not supported + if (ROCKSIM_DESIGN_FILTER.accept(file)) { + file = new File(file.getAbsolutePath().replaceAll(".[rR][kK][tT](.[gG][zZ])?$", + ".ork")); + + int option = JOptionPane.showConfirmDialog(this, new Object[] { + "Saving designs in RockSim format is not supported.", + "Save in OpenRocket format instead ("+file.getName()+")?" + }, "Save "+file.getName(), JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, null); + if (option != JOptionPane.YES_OPTION) + return false; + + document.setFile(file); + } + return saveAs(file); } private boolean saveAsAction() { File file = null; while (file == null) { + // TODO: HIGH: what if *.rkt chosen? StorageOptionChooser storageChooser = new StorageOptionChooser(document, document.getDefaultStorageOptions()); JFileChooser chooser = new JFileChooser(); - chooser.setFileFilter(ROCKET_DESIGN_FILTER); + chooser.setFileFilter(OPENROCKET_DESIGN_FILTER); chooser.setCurrentDirectory(Prefs.getDefaultDirectory()); chooser.setAccessory(storageChooser); if (document.getFile() != null) diff --git a/src/net/sf/openrocket/gui/main/SimpleFileFilter.java b/src/net/sf/openrocket/gui/main/SimpleFileFilter.java new file mode 100644 index 00000000..5fbcb1b7 --- /dev/null +++ b/src/net/sf/openrocket/gui/main/SimpleFileFilter.java @@ -0,0 +1,62 @@ +package net.sf.openrocket.gui.main; + +import java.io.File; + +import javax.swing.filechooser.FileFilter; + +/** + * A FileFilter similar to FileNameExtensionFilter except that + * it allows multipart extensions (.ork.gz). + * + * @author Sampo Niskanen + */ +public class SimpleFileFilter extends FileFilter { + + private final String description; + private final String[] extensions; + + + /** + * Sole constructor. + * + * @param description the description of this file filter. + * @param extensions an array of extensions that match this filter. + */ + public SimpleFileFilter(String description, String ... extensions) { + this.description = description; + this.extensions = new String[extensions.length]; + for (int i=0; iString specifying the simple name of the + * desired field.

+ * + * The object is first searched for any matching field. If no matching + * field is found, the superclasses are recursively searched. + * + * @exception NoSuchFieldException if a field with the specified name is + * not found. + */ + public static Object getField(Object object, + String name) + throws NoSuchFieldException { + if (object == null) { + throw new IllegalArgumentException("Invalid null object argument"); + } + for (Class cls = object.getClass(); + cls != null; + cls = cls.getSuperclass()) { + try { + Field field = cls.getDeclaredField(name); + field.setAccessible(true); + return field.get(object); + } catch (Exception ex) { + /* in case of an exception, we will throw a new + * NoSuchFieldException object */ + ; + } + } + throw new NoSuchFieldException("Could get value for field " + + object.getClass().getName() + "." + name); + } + + /** + * Returns the value of the field on the specified class. The name + * parameter is a String specifying the simple name of the + * desired field.

+ * + * The class is first searched for any matching field. If no matching + * field is found, the superclasses are recursively searched. + * + * @exception NoSuchFieldException if a field with the specified name is + * not found. + */ + public static Object getField(Class cls, + String name) + throws NoSuchFieldException { + if (cls == null) { + throw new IllegalArgumentException("Invalid null cls argument"); + } + Class base = cls; + while (base != null) { + try { + Field field = base.getDeclaredField(name); + field.setAccessible(true); + return field.get(base); + } catch (Exception ex) { + /* in case of an exception, we will throw a new + * NoSuchFieldException object */ + ; + } + base = base.getSuperclass(); + } + throw new NoSuchFieldException("Could get value for static field " + + cls.getName() + "." + name); + } + + +} diff --git a/test/net/sf/openrocket/file/rocksim/BodyTubeHandlerTest.java b/test/net/sf/openrocket/file/rocksim/BodyTubeHandlerTest.java new file mode 100644 index 00000000..061c8994 --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/BodyTubeHandlerTest.java @@ -0,0 +1,188 @@ +/* + * BodyTubeHandlerTest.java + */ +package net.sf.openrocket.file.rocksim; + +import junit.framework.Test; +import junit.framework.TestSuite; +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.database.Databases; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.BodyTube; +import net.sf.openrocket.rocketcomponent.Stage; +import net.sf.openrocket.rocketcomponent.ExternalComponent; + +import java.util.HashMap; + +/** + * BodyTubeHandler Tester. + * + */ +public class BodyTubeHandlerTest extends BaseRocksimTest { + + /** + * The class under test. + */ + public static final Class classUT = BodyTubeHandler.class; + + /** + * The test class (this class). + */ + public static final Class testClass = BodyTubeHandlerTest.class; + + /** + * Create a test suite of all tests within this test class. + * + * @return a suite of tests + */ + public static Test suite() { + return new TestSuite(BodyTubeHandlerTest.class); + } + + /** + * Test constructor. + * + * @param name the name of the test to run. + */ + public BodyTubeHandlerTest(String name) { + super(name); + } + + /** + * Setup the fixture. + */ + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Teardown the fixture. + */ + public void tearDown() throws Exception { + super.tearDown(); + } + + + /** + * Method: constructor + * + * @throws Exception thrown if something goes awry + */ + public void testConstructor() throws Exception { + + try { + new BodyTubeHandler(null); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException iae) { + //success + } + + Stage stage = new Stage(); + BodyTubeHandler handler = new BodyTubeHandler(stage); + BodyTube component = (BodyTube) getField(handler, "bodyTube"); + assertContains(component, stage.getChildren()); + } + + /** + * Method: openElement(String element, HashMap attributes, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testOpenElement() throws Exception { + assertEquals(PlainTextHandler.INSTANCE, new BodyTubeHandler(new Stage()).openElement(null, null, null)); + assertNotNull(new BodyTubeHandler(new Stage()).openElement("AttachedParts", null, null)); + } + + /** + * + * Method: closeElement(String element, HashMap attributes, String content, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testCloseElement() throws Exception { + Stage stage = new Stage(); + BodyTubeHandler handler = new BodyTubeHandler(stage); + BodyTube component = (BodyTube) getField(handler, "bodyTube"); + HashMap attributes = new HashMap(); + WarningSet warnings = new WarningSet(); + + handler.closeElement("OD", attributes, "-1", warnings); + assertEquals(0d, component.getInnerRadius()); + handler.closeElement("OD", attributes, "0", warnings); + assertEquals(0d, component.getInnerRadius()); + handler.closeElement("OD", attributes, "75", warnings); + assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius()); + handler.closeElement("OD", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("ID", attributes, "-1", warnings); + assertEquals(0d, component.getInnerRadius()); + handler.closeElement("ID", attributes, "0", warnings); + assertEquals(0d, component.getInnerRadius()); + handler.closeElement("ID", attributes, "75", warnings); + assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius()); + handler.closeElement("ID", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Len", attributes, "-1", warnings); + assertEquals(0d, component.getLength()); + handler.closeElement("Len", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength()); + handler.closeElement("Len", attributes, "10.0", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength()); + handler.closeElement("Len", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("IsMotorMount", attributes, "1", warnings); + assertTrue(component.isMotorMount()); + handler.closeElement("IsMotorMount", attributes, "0", warnings); + assertFalse(component.isMotorMount()); + handler.closeElement("IsMotorMount", attributes, "foo", warnings); + assertFalse(component.isMotorMount()); + + handler.closeElement("EngineOverhang", attributes, "-1", warnings); + assertEquals(-1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang()); + handler.closeElement("EngineOverhang", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang()); + handler.closeElement("EngineOverhang", attributes, "10.0", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang()); + handler.closeElement("EngineOverhang", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("FinishCode", attributes, "-1", warnings); + assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish()); + handler.closeElement("FinishCode", attributes, "100", warnings); + assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish()); + handler.closeElement("FinishCode", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Name", attributes, "Test Name", warnings); + assertEquals("Test Name", component.getName()); + } + + /** + * Method: getComponent() + * + * @throws Exception thrown if something goes awry + */ + public void testGetComponent() throws Exception { + assertTrue(new BodyTubeHandler(new Stage()).getComponent() instanceof BodyTube); + } + + /** + * Method: getMaterialType() + * + * @throws Exception thrown if something goes awry + */ + public void testGetMaterialType() throws Exception { + assertEquals(Material.Type.BULK, new BodyTubeHandler(new Stage()).getMaterialType()); + } + +} diff --git a/test/net/sf/openrocket/file/rocksim/FinSetHandlerTest.java b/test/net/sf/openrocket/file/rocksim/FinSetHandlerTest.java new file mode 100644 index 00000000..5b02142b --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/FinSetHandlerTest.java @@ -0,0 +1,225 @@ +/* + * FinSetHandlerTest.java + */ +package net.sf.openrocket.file.rocksim; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.rocketcomponent.BodyTube; +import net.sf.openrocket.rocketcomponent.EllipticalFinSet; +import net.sf.openrocket.rocketcomponent.FinSet; +import net.sf.openrocket.rocketcomponent.TrapezoidFinSet; +import net.sf.openrocket.util.Coordinate; + +import java.lang.reflect.Method; +import java.util.HashMap; + +/** + * FinSetHandler Tester. + * + */ +public class FinSetHandlerTest extends TestCase { + + /** + * The class under test. + */ + public static final Class classUT = FinSetHandler.class; + + /** + * The test class (this class). + */ + public static final Class testClass = FinSetHandlerTest.class; + + /** + * Create a test suite of all tests within this test class. + * + * @return a suite of tests + */ + public static Test suite() { + return new TestSuite(FinSetHandlerTest.class); + } + + /** + * Test constructor. + * + * @param name the name of the test to run. + */ + public FinSetHandlerTest(String name) { + super(name); + } + + /** + * Setup the fixture. + */ + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Teardown the fixture. + */ + public void tearDown() throws Exception { + super.tearDown(); + } + + + /** + * Method: asOpenRocket(WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testAsOpenRocket() throws Exception { + + FinSetHandler dto = new FinSetHandler(new BodyTube()); + + HashMap attributes = new HashMap(); + WarningSet warnings = new WarningSet(); + + dto.closeElement("Name", attributes, "The name", warnings); + dto.closeElement("ShapeCode", attributes, "0", warnings); + dto.closeElement("Xb", attributes, "2", warnings); + dto.closeElement("FinCount", attributes, "4", warnings); + dto.closeElement("RootChord", attributes, "10", warnings); + dto.closeElement("TipChord", attributes, "11", warnings); + dto.closeElement("SemiSpan", attributes, "12", warnings); + dto.closeElement("MidChordLen", attributes, "13", warnings); + dto.closeElement("SweepDistance", attributes, "14", warnings); + dto.closeElement("Thickness", attributes, "200", warnings); + dto.closeElement("TipShapeCode", attributes, "1", warnings); + dto.closeElement("TabLength", attributes, "400", warnings); + dto.closeElement("TabDepth", attributes, "500", warnings); + dto.closeElement("TabOffset", attributes, "30", warnings); + dto.closeElement("RadialAngle", attributes, ".123", warnings); + dto.closeElement("PointList", attributes, "20,0|2,2|0,0", warnings); + dto.closeElement("LocationMode", attributes, "0", warnings); + + WarningSet set = new WarningSet(); + FinSet fins = dto.asOpenRocket(set); + assertNotNull(fins); + assertEquals(0, set.size()); + + assertEquals("The name", fins.getName()); + assertTrue(fins instanceof TrapezoidFinSet); + assertEquals(4, fins.getFinCount()); + + assertEquals(0.2d, fins.getThickness()); + assertEquals(0.4d, fins.getTabLength()); + assertEquals(0.5d, fins.getTabHeight()); + assertEquals(0.03d, fins.getTabShift()); + assertEquals(.123d, fins.getBaseRotation()); + + dto.closeElement("ShapeCode", attributes, "1", warnings); + fins = dto.asOpenRocket(set); + assertNotNull(fins); + assertEquals(0, set.size()); + + assertEquals("The name", fins.getName()); + assertTrue(fins instanceof EllipticalFinSet); + assertEquals(4, fins.getFinCount()); + + assertEquals(0.2d, fins.getThickness()); + assertEquals(0.4d, fins.getTabLength()); + assertEquals(0.5d, fins.getTabHeight()); + assertEquals(0.03d, fins.getTabShift()); + assertEquals(.123d, fins.getBaseRotation()); + } + + + /** + * Method: toCoordinates(String pointList) + * + * @throws Exception thrown if something goes awry + */ + public void testToCoordinates() throws Exception { + FinSetHandler holder = new FinSetHandler(new BodyTube()); + Method method = FinSetHandler.class.getDeclaredMethod("toCoordinates", String.class, WarningSet.class); + method.setAccessible(true); + + WarningSet warnings = new WarningSet(); + //Null finlist + String finlist = null; + Coordinate[] result = (Coordinate[])method.invoke(holder, finlist, warnings); + assertNotNull(result); + assertTrue(0 == result.length); + + //Empty string finlist + finlist = ""; + result = (Coordinate[])method.invoke(holder, finlist, warnings); + assertNotNull(result); + assertTrue(0 == result.length); + + //Invalid finlist (only x coordinate) + finlist = "10.0"; + result = (Coordinate[])method.invoke(holder, finlist, warnings); + assertNotNull(result); + assertTrue(0 == result.length); + assertEquals(1, warnings.size()); + warnings.clear(); + + //Invalid finlist (non-numeric character) + finlist = "10.0,asdf"; + result = (Coordinate[])method.invoke(holder, finlist, warnings); + assertNotNull(result); + assertTrue(0 == result.length); + assertEquals(1, warnings.size()); + warnings.clear(); + + //Invalid finlist (all delimiters) + finlist = "||||||"; + result = (Coordinate[])method.invoke(holder, finlist, warnings); + assertNotNull(result); + assertTrue(0 == result.length); + assertEquals(0, warnings.size()); + warnings.clear(); + + //One point finlist - from a parsing view it's valid; from a practical view it may not be, but that's outside + //the scope of this test case + finlist = "10.0,5.0"; + result = (Coordinate[])method.invoke(holder, finlist, warnings); + assertNotNull(result); + assertTrue(1 == result.length); + assertEquals(0, warnings.size()); + warnings.clear(); + + //Two point finlist - from a parsing view it's valid; from a practical view it may not be, but that's outside + //the scope of this test case + finlist = "10.0,5.0|3.3,4.4"; + result = (Coordinate[])method.invoke(holder, finlist, warnings); + assertNotNull(result); + assertTrue(2 == result.length); + assertEquals(0, warnings.size()); + warnings.clear(); + + //Normal four point finlist. + finlist = "518.16,0|517.494,37.2145|1.31261,6.77283|0,0|"; + result = (Coordinate[])method.invoke(holder, finlist, warnings); + assertNotNull(result); + assertTrue(4 == result.length); + assertEquals(new Coordinate(0,0), result[0]); + assertEquals(0, warnings.size()); + warnings.clear(); + + //Normal four point finlist with spaces. + finlist = "518.16 , 0 | 517.494 , 37.2145 | 1.31261,6.77283|0,0|"; + result = (Coordinate[])method.invoke(holder, finlist, warnings); + assertNotNull(result); + assertTrue(4 == result.length); + assertEquals(new Coordinate(0,0), result[0]); + assertEquals(new Coordinate(.51816,0), result[3]); + assertEquals(0, warnings.size()); + warnings.clear(); + + //Reversed Normal four point finlist. + finlist = "0,0|1.31261,6.77283|517.494,37.2145|518.16,0|"; + result = (Coordinate[])method.invoke(holder, finlist, warnings); + assertNotNull(result); + assertTrue(4 == result.length); + assertEquals(new Coordinate(0,0), result[0]); + assertEquals(new Coordinate(.51816,0), result[3]); + assertEquals(0, warnings.size()); + warnings.clear(); + + } +} diff --git a/test/net/sf/openrocket/file/rocksim/InnerBodyTubeHandlerTest.java b/test/net/sf/openrocket/file/rocksim/InnerBodyTubeHandlerTest.java new file mode 100644 index 00000000..473f49d8 --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/InnerBodyTubeHandlerTest.java @@ -0,0 +1,197 @@ +/* + * InnerBodyTubeHandlerTest.java + */ +package net.sf.openrocket.file.rocksim; + +import junit.framework.Test; +import junit.framework.TestSuite; +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.database.Databases; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.BodyTube; +import net.sf.openrocket.rocketcomponent.InnerTube; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.Stage; + +import java.util.HashMap; + +/** + * InnerBodyTubeHandler Tester. + * + */ +public class InnerBodyTubeHandlerTest extends BaseRocksimTest { + + /** + * The class under test. + */ + public static final Class classUT = InnerBodyTubeHandler.class; + + /** + * The test class (this class). + */ + public static final Class testClass = InnerBodyTubeHandlerTest.class; + + /** + * Create a test suite of all tests within this test class. + * + * @return a suite of tests + */ + public static Test suite() { + return new TestSuite(InnerBodyTubeHandlerTest.class); + } + + /** + * Test constructor. + * + * @param name the name of the test to run. + */ + public InnerBodyTubeHandlerTest(String name) { + super(name); + } + + /** + * Setup the fixture. + */ + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Teardown the fixture. + */ + public void tearDown() throws Exception { + super.tearDown(); + } + + + /** + * Method: constructor + * + * @throws Exception thrown if something goes awry + */ + public void testConstructor() throws Exception { + + try { + new InnerBodyTubeHandler(null); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException iae) { + //success + } + + BodyTube tube = new BodyTube(); + InnerBodyTubeHandler handler = new InnerBodyTubeHandler(tube); + InnerTube component = (InnerTube) getField(handler, "bodyTube"); + assertContains(component, tube.getChildren()); + } + + /** + * Method: openElement(String element, HashMap attributes, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testOpenElement() throws Exception { + assertEquals(PlainTextHandler.INSTANCE, new InnerBodyTubeHandler(new BodyTube()).openElement(null, null, null)); + assertNotNull(new InnerBodyTubeHandler(new BodyTube()).openElement("AttachedParts", null, null)); + } + + /** + * + * Method: closeElement(String element, HashMap attributes, String content, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testCloseElement() throws Exception { + BodyTube tube = new BodyTube(); + InnerBodyTubeHandler handler = new InnerBodyTubeHandler(tube); + InnerTube component = (InnerTube) getField(handler, "bodyTube"); + HashMap attributes = new HashMap(); + WarningSet warnings = new WarningSet(); + + handler.closeElement("OD", attributes, "-1", warnings); + assertEquals(0d, component.getInnerRadius()); + handler.closeElement("OD", attributes, "0", warnings); + assertEquals(0d, component.getInnerRadius()); + handler.closeElement("OD", attributes, "75", warnings); + assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius()); + handler.closeElement("OD", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("ID", attributes, "-1", warnings); + assertEquals(0d, component.getInnerRadius()); + handler.closeElement("ID", attributes, "0", warnings); + assertEquals(0d, component.getInnerRadius()); + handler.closeElement("ID", attributes, "75", warnings); + assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius()); + handler.closeElement("ID", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Len", attributes, "-1", warnings); + assertEquals(0d, component.getLength()); + handler.closeElement("Len", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength()); + handler.closeElement("Len", attributes, "10.0", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength()); + handler.closeElement("Len", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("IsMotorMount", attributes, "1", warnings); + assertTrue(component.isMotorMount()); + handler.closeElement("IsMotorMount", attributes, "0", warnings); + assertFalse(component.isMotorMount()); + handler.closeElement("IsMotorMount", attributes, "foo", warnings); + assertFalse(component.isMotorMount()); + + handler.closeElement("EngineOverhang", attributes, "-1", warnings); + assertEquals(-1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang()); + handler.closeElement("EngineOverhang", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang()); + handler.closeElement("EngineOverhang", attributes, "10.0", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getMotorOverhang()); + handler.closeElement("EngineOverhang", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Name", attributes, "Test Name", warnings); + assertEquals("Test Name", component.getName()); + } + + /** + * Method: setRelativePosition(RocketComponent.Position position) + * + * @throws Exception thrown if something goes awry + */ + public void testSetRelativePosition() throws Exception { + BodyTube tube = new BodyTube(); + InnerBodyTubeHandler handler = new InnerBodyTubeHandler(tube); + InnerTube component = (InnerTube) getField(handler, "bodyTube"); + handler.setRelativePosition(RocketComponent.Position.ABSOLUTE); + assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition()); + } + + /** + * Method: getComponent() + * + * @throws Exception thrown if something goes awry + */ + public void testGetComponent() throws Exception { + assertTrue(new InnerBodyTubeHandler(new BodyTube()).getComponent() instanceof InnerTube); + } + + /** + * Method: getMaterialType() + * + * @throws Exception thrown if something goes awry + */ + public void testGetMaterialType() throws Exception { + assertEquals(Material.Type.BULK, new InnerBodyTubeHandler(new BodyTube()).getMaterialType()); + } + + + + +} diff --git a/test/net/sf/openrocket/file/rocksim/LaunchLugHandlerTest.java b/test/net/sf/openrocket/file/rocksim/LaunchLugHandlerTest.java new file mode 100644 index 00000000..b1b7acfd --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/LaunchLugHandlerTest.java @@ -0,0 +1,184 @@ +/* + * LaunchLugHandlerTest.java + */ +package net.sf.openrocket.file.rocksim; + +import junit.framework.Test; +import junit.framework.TestSuite; +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.database.Databases; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.BodyTube; +import net.sf.openrocket.rocketcomponent.ExternalComponent; +import net.sf.openrocket.rocketcomponent.LaunchLug; +import net.sf.openrocket.rocketcomponent.RocketComponent; + +import java.util.HashMap; + +/** + * LaunchLugHandler Tester. + * + */ +public class LaunchLugHandlerTest extends BaseRocksimTest { + + /** + * The class under test. + */ + public static final Class classUT = LaunchLugHandler.class; + + /** + * The test class (this class). + */ + public static final Class testClass = LaunchLugHandlerTest.class; + + /** + * Create a test suite of all tests within this test class. + * + * @return a suite of tests + */ + public static Test suite() { + return new TestSuite(LaunchLugHandlerTest.class); + } + + /** + * Test constructor. + * + * @param name the name of the test to run. + */ + public LaunchLugHandlerTest(String name) { + super(name); + } + + /** + * Setup the fixture. + */ + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Teardown the fixture. + */ + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Method: constructor + * + * @throws Exception thrown if something goes awry + */ + public void testConstructor() throws Exception { + + try { + new LaunchLugHandler(null); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException iae) { + //success + } + + BodyTube tube = new BodyTube(); + LaunchLugHandler handler = new LaunchLugHandler(tube); + LaunchLug component = (LaunchLug) getField(handler, "lug"); + assertContains(component, tube.getChildren()); + } + + /** + * Method: openElement(String element, HashMap attributes, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testOpenElement() throws Exception { + assertEquals(PlainTextHandler.INSTANCE, new LaunchLugHandler(new BodyTube()).openElement(null, null, null)); + } + + /** + * + * Method: closeElement(String element, HashMap attributes, String content, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testCloseElement() throws Exception { + BodyTube tube = new BodyTube(); + LaunchLugHandler handler = new LaunchLugHandler(tube); + LaunchLug component = (LaunchLug) getField(handler, "lug"); + HashMap attributes = new HashMap(); + WarningSet warnings = new WarningSet(); + + handler.closeElement("OD", attributes, "-1", warnings); + assertEquals(0d, component.getRadius()); + handler.closeElement("OD", attributes, "0", warnings); + assertEquals(0d, component.getRadius()); + handler.closeElement("OD", attributes, "75", warnings); + assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getRadius()); + handler.closeElement("OD", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("ID", attributes, "-1", warnings); + assertEquals(0d, component.getInnerRadius()); + handler.closeElement("ID", attributes, "0", warnings); + assertEquals(0d, component.getInnerRadius()); + handler.closeElement("ID", attributes, "75", warnings); + assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius()); + handler.closeElement("ID", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Len", attributes, "-1", warnings); + assertEquals(0d, component.getLength()); + handler.closeElement("Len", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength()); + handler.closeElement("Len", attributes, "10.0", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength()); + handler.closeElement("Len", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("FinishCode", attributes, "-1", warnings); + assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish()); + handler.closeElement("FinishCode", attributes, "100", warnings); + assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish()); + handler.closeElement("FinishCode", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Name", attributes, "Test Name", warnings); + assertEquals("Test Name", component.getName()); + } + + /** + * Method: setRelativePosition(RocketComponent.Position position) + * + * @throws Exception thrown if something goes awry + */ + public void testSetRelativePosition() throws Exception { + BodyTube tube = new BodyTube(); + LaunchLugHandler handler = new LaunchLugHandler(tube); + LaunchLug component = (LaunchLug) getField(handler, "lug"); + handler.setRelativePosition(RocketComponent.Position.ABSOLUTE); + assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition()); + } + + /** + * Method: getComponent() + * + * @throws Exception thrown if something goes awry + */ + public void testGetComponent() throws Exception { + assertTrue(new LaunchLugHandler(new BodyTube()).getComponent() instanceof LaunchLug); + } + + /** + * Method: getMaterialType() + * + * @throws Exception thrown if something goes awry + */ + public void testGetMaterialType() throws Exception { + assertEquals(Material.Type.BULK, new LaunchLugHandler(new BodyTube()).getMaterialType()); + } + + +} diff --git a/test/net/sf/openrocket/file/rocksim/MassObjectHandlerTest.java b/test/net/sf/openrocket/file/rocksim/MassObjectHandlerTest.java new file mode 100644 index 00000000..2bd30b4a --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/MassObjectHandlerTest.java @@ -0,0 +1,166 @@ +/* + * MassObjectHandlerTest.java + */ +package net.sf.openrocket.file.rocksim; + +import junit.framework.Test; +import junit.framework.TestSuite; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.BodyTube; +import net.sf.openrocket.rocketcomponent.MassComponent; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.Stage; +import net.sf.openrocket.rocketcomponent.NoseCone; +import net.sf.openrocket.rocketcomponent.Transition; +import net.sf.openrocket.aerodynamics.WarningSet; + +import java.util.HashMap; + +/** + * MassObjectHandler Tester. + * + */ +public class MassObjectHandlerTest extends BaseRocksimTest { + + /** + * The class under test. + */ + public static final Class classUT = MassObjectHandler.class; + + /** + * The test class (this class). + */ + public static final Class testClass = MassObjectHandlerTest.class; + + /** + * Create a test suite of all tests within this test class. + * + * @return a suite of tests + */ + public static Test suite() { + return new TestSuite(MassObjectHandlerTest.class); + } + + /** + * Test constructor. + * + * @param name the name of the test to run. + */ + public MassObjectHandlerTest(String name) { + super(name); + } + + /** + * Setup the fixture. + */ + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Teardown the fixture. + */ + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Method: constructor + * + * @throws Exception thrown if something goes awry + */ + public void testConstructor() throws Exception { + + try { + new MassObjectHandler(null); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException iae) { + //success + } + + BodyTube tube = new BodyTube(); + MassObjectHandler handler = new MassObjectHandler(tube); + MassComponent component = (MassComponent) getField(handler, "mass"); + assertContains(component, tube.getChildren()); + } + + /** + * Method: openElement(String element, HashMap attributes, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testOpenElement() throws Exception { + assertEquals(PlainTextHandler.INSTANCE, new MassObjectHandler(new BodyTube()).openElement(null, null, null)); + } + + /** + * + * Method: closeElement(String element, HashMap attributes, String content, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testCloseElement() throws Exception { + BodyTube tube = new BodyTube(); + HashMap attributes = new HashMap(); + WarningSet warnings = new WarningSet(); + + MassObjectHandler handler = new MassObjectHandler(tube); + MassComponent component = (MassComponent) getField(handler, "mass"); + + handler.closeElement("Len", attributes, "-1", warnings); + assertEquals(0d, component.getLength()); + handler.closeElement("Len", attributes, "10", warnings); + assertEquals(10d / (MassObjectHandler.MASS_LEN_FUDGE_FACTOR * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH) + , component.getLength()); + handler.closeElement("Len", attributes, "10.0", warnings); + assertEquals(10d / (MassObjectHandler.MASS_LEN_FUDGE_FACTOR * RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH) + , component.getLength()); + handler.closeElement("Len", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("KnownMass", attributes, "-1", warnings); + assertEquals(0d, component.getComponentMass()); + handler.closeElement("KnownMass", attributes, "100", warnings); + assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS, component.getComponentMass()); + handler.closeElement("KnownMass", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + } + + /** + * Method: setRelativePosition(RocketComponent.Position position) + * + * @throws Exception thrown if something goes awry + */ + public void testSetRelativePosition() throws Exception { + BodyTube tube = new BodyTube(); + MassObjectHandler handler = new MassObjectHandler(tube); + MassComponent component = (MassComponent) getField(handler, "mass"); + handler.setRelativePosition(RocketComponent.Position.ABSOLUTE); + assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition()); + } + + /** + * Method: getComponent() + * + * @throws Exception thrown if something goes awry + */ + public void testGetComponent() throws Exception { + assertTrue(new MassObjectHandler(new BodyTube()).getComponent() instanceof MassComponent); + } + + /** + * Method: getMaterialType() + * + * @throws Exception thrown if something goes awry + */ + public void testGetMaterialType() throws Exception { + assertEquals(Material.Type.BULK, new MassObjectHandler(new BodyTube()).getMaterialType()); + } + + +} diff --git a/test/net/sf/openrocket/file/rocksim/NoseConeHandlerTest.java b/test/net/sf/openrocket/file/rocksim/NoseConeHandlerTest.java new file mode 100644 index 00000000..79ce6005 --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/NoseConeHandlerTest.java @@ -0,0 +1,239 @@ +/* + * NoseConeHandlerTest.java + */ +package net.sf.openrocket.file.rocksim; + +import junit.framework.Test; +import junit.framework.TestSuite; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.NoseCone; +import net.sf.openrocket.rocketcomponent.Stage; +import net.sf.openrocket.rocketcomponent.Transition; +import net.sf.openrocket.rocketcomponent.ExternalComponent; +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.database.Databases; + +import java.util.HashMap; + +/** + * NoseConeHandler Tester. + * + */ +public class NoseConeHandlerTest extends BaseRocksimTest { + + /** + * The class under test. + */ + public static final Class classUT = NoseConeHandler.class; + + /** + * The test class (this class). + */ + public static final Class testClass = NoseConeHandlerTest.class; + + /** + * Create a test suite of all tests within this test class. + * + * @return a suite of tests + */ + public static Test suite() { + return new TestSuite(NoseConeHandlerTest.class); + } + + /** + * Test constructor. + * + * @param name the name of the test to run. + */ + public NoseConeHandlerTest(String name) { + super(name); + } + + /** + * Setup the fixture. + */ + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Teardown the fixture. + */ + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Method: constructor + * + * @throws Exception thrown if something goes awry + */ + public void testConstructor() throws Exception { + + try { + new NoseConeHandler(null); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException iae) { + //success + } + + Stage stage = new Stage(); + NoseConeHandler handler = new NoseConeHandler(stage); + NoseCone component = (NoseCone) getField(handler, "noseCone"); + assertContains(component, stage.getChildren()); + } + + /** + * Method: openElement(String element, HashMap attributes, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testOpenElement() throws Exception { + assertEquals(PlainTextHandler.INSTANCE, new NoseConeHandler(new Stage()).openElement(null, null, null)); + assertNotNull(new NoseConeHandler(new Stage()).openElement("AttachedParts", null, null)); + } + + /** + * + * Method: closeElement(String element, HashMap attributes, String content, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testCloseElement() throws Exception { + + Stage stage = new Stage(); + HashMap attributes = new HashMap(); + WarningSet warnings = new WarningSet(); + + NoseConeHandler handler = new NoseConeHandler(stage); + NoseCone component = (NoseCone) getField(handler, "noseCone"); + + handler.closeElement("ShapeCode", attributes, "0", warnings); + assertEquals(Transition.Shape.CONICAL, component.getType()); + handler.closeElement("ShapeCode", attributes, "1", warnings); + assertEquals(Transition.Shape.OGIVE, component.getType()); + handler.closeElement("ShapeCode", attributes, "17", warnings); + assertEquals(RocksimNoseConeCode.PARABOLIC.asOpenRocket(), component.getType()); //test of default + handler.closeElement("ShapeCode", attributes, "foo", warnings); + assertNotNull(component.getType()); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Len", attributes, "-1", warnings); + assertEquals(0d, component.getLength()); + handler.closeElement("Len", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength()); + handler.closeElement("Len", attributes, "10.0", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength()); + handler.closeElement("Len", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("BaseDia", attributes, "-1", warnings); + assertEquals(0d, component.getAftRadius()); + handler.closeElement("BaseDia", attributes, "100", warnings); + assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getAftRadius()); + handler.closeElement("BaseDia", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + + final double aft = 100d; + component.setAftRadius(aft); + + handler.closeElement("ConstructionType", attributes, "0", warnings); + component.setAftShoulderRadius(1.1d); + handler.closeElement("WallThickness", attributes, "-1", warnings); + handler.endHandler("Transition", attributes, null, warnings); + assertEquals(component.getAftRadius(), component.getThickness()); + assertEquals(component.getAftShoulderThickness(), component.getAftShoulderThickness()); + handler.closeElement("WallThickness", attributes, "100", warnings); + handler.endHandler("Transition", attributes, null, warnings); + assertEquals(aft, component.getThickness()); + handler.closeElement("WallThickness", attributes, "foo", warnings); + handler.endHandler("Transition", attributes, null, warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("ConstructionType", attributes, "1", warnings); + component.setAftShoulderRadius(1.1d); + handler.closeElement("WallThickness", attributes, "-1", warnings); + handler.endHandler("Transition", attributes, null, warnings); + assertEquals(0d, component.getThickness()); + assertEquals(0d, component.getAftShoulderThickness()); + handler.closeElement("WallThickness", attributes, "1.1", warnings); + handler.endHandler("Transition", attributes, null, warnings); + assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getThickness()); + assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderThickness()); + + handler.closeElement("ShoulderLen", attributes, "-1", warnings); + assertEquals(0d, component.getAftShoulderLength()); + handler.closeElement("ShoulderLen", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderLength()); + handler.closeElement("ShoulderLen", attributes, "10.0", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderLength()); + handler.closeElement("ShoulderLen", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("ShoulderOD", attributes, "-1", warnings); + assertEquals(0d, component.getAftShoulderRadius()); + handler.closeElement("ShoulderOD", attributes, "100", warnings); + assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getAftShoulderRadius()); + handler.closeElement("ShoulderOD", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + component.setType(Transition.Shape.HAACK); + handler.closeElement("ShapeParameter", attributes, "-1", warnings); + assertEquals(0d, component.getShapeParameter()); + handler.closeElement("ShapeParameter", attributes, "100", warnings); + assertEquals(Transition.Shape.HAACK.maxParameter(), component.getShapeParameter()); + handler.closeElement("ShapeParameter", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + assertEquals("Could not convert ShapeParameter value of foo. It is expected to be a number.", + warnings.iterator().next().toString()); + + warnings.clear(); + + component.setType(Transition.Shape.CONICAL); + component.setShapeParameter(0d); + handler.closeElement("ShapeParameter", attributes, "100", warnings); + assertEquals(0d, component.getShapeParameter()); + + handler.closeElement("FinishCode", attributes, "-1", warnings); + assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish()); + handler.closeElement("FinishCode", attributes, "100", warnings); + assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish()); + handler.closeElement("FinishCode", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Name", attributes, "Test Name", warnings); + assertEquals("Test Name", component.getName()); + + handler.closeElement("Material", attributes, "Some Material", warnings); + handler.endHandler("NoseCone", attributes, null, warnings); + assertTrue(component.getMaterial().getName().contains("Some Material")); + } + + /** + * Method: getComponent() + * + * @throws Exception thrown if something goes awry + */ + public void testGetComponent() throws Exception { + assertTrue(new NoseConeHandler(new Stage()).getComponent() instanceof NoseCone); + } + + /** + * Method: getMaterialType() + * + * @throws Exception thrown if something goes awry + */ + public void testGetMaterialType() throws Exception { + assertEquals(Material.Type.BULK, new NoseConeHandler(new Stage()).getMaterialType()); + } +} diff --git a/test/net/sf/openrocket/file/rocksim/ParachuteHandlerTest.java b/test/net/sf/openrocket/file/rocksim/ParachuteHandlerTest.java new file mode 100644 index 00000000..d5670e2f --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/ParachuteHandlerTest.java @@ -0,0 +1,202 @@ +/* + * ParachuteHandlerTest.java + */ +package net.sf.openrocket.file.rocksim; + +import junit.framework.Test; +import junit.framework.TestSuite; +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.database.Databases; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.BodyTube; +import net.sf.openrocket.rocketcomponent.Parachute; +import net.sf.openrocket.rocketcomponent.RocketComponent; + +import java.util.HashMap; + +/** + * ParachuteHandler Tester. + */ +public class ParachuteHandlerTest extends BaseRocksimTest { + + /** + * The class under test. + */ + public static final Class classUT = ParachuteHandler.class; + + /** + * The test class (this class). + */ + public static final Class testClass = ParachuteHandlerTest.class; + + /** + * Create a test suite of all tests within this test class. + * + * @return a suite of tests + */ + public static Test suite() { + return new TestSuite(ParachuteHandlerTest.class); + } + + /** + * Test constructor. + * + * @param name the name of the test to run. + */ + public ParachuteHandlerTest(String name) { + super(name); + } + + /** + * Setup the fixture. + */ + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Teardown the fixture. + */ + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Method: openElement(String element, HashMap attributes, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testOpenElement() throws Exception { + assertEquals(PlainTextHandler.INSTANCE, new ParachuteHandler(new BodyTube()).openElement(null, null, null)); + } + + /** + * Method: closeElement(String element, HashMap attributes, String content, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testCloseElement() throws Exception { + + BodyTube tube = new BodyTube(); + ParachuteHandler handler = new ParachuteHandler(tube); + Parachute component = (Parachute) getField(handler, "chute"); + HashMap attributes = new HashMap(); + WarningSet warnings = new WarningSet(); + + handler.closeElement("Name", attributes, "Test Name", warnings); + assertEquals("Test Name", component.getName()); + + handler.closeElement("DragCoefficient", attributes, "0.94", warnings); + assertEquals(0.94d, component.getCD()); + handler.closeElement("DragCoefficient", attributes, "-0.94", warnings); + assertEquals(-0.94d, component.getCD()); + handler.closeElement("DragCoefficient", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Dia", attributes, "-1", warnings); + assertEquals(-1d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getDiameter()); + handler.closeElement("Dia", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getDiameter()); + handler.closeElement("Dia", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("ShroudLineCount", attributes, "-1", warnings); + assertEquals(0, component.getLineCount()); + handler.closeElement("ShroudLineCount", attributes, "10", warnings); + assertEquals(10, component.getLineCount()); + handler.closeElement("ShroudLineCount", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("ShroudLineLen", attributes, "-1", warnings); + assertEquals(0d, component.getLineLength()); + handler.closeElement("ShroudLineLen", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLineLength()); + handler.closeElement("ShroudLineLen", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + } + + /** + * Method: constructor + * + * @throws Exception thrown if something goes awry + */ + public void testConstructor() throws Exception { + + try { + new ParachuteHandler(null); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException iae) { + //success + } + + BodyTube tube = new BodyTube(); + ParachuteHandler handler = new ParachuteHandler(tube); + Parachute component = (Parachute) getField(handler, "chute"); + assertContains(component, tube.getChildren()); + } + + /** + * Method: setRelativePosition(RocketComponent.Position position) + * + * @throws Exception thrown if something goes awry + */ + public void testSetRelativePosition() throws Exception { + BodyTube tube = new BodyTube(); + ParachuteHandler handler = new ParachuteHandler(tube); + Parachute component = (Parachute) getField(handler, "chute"); + handler.setRelativePosition(RocketComponent.Position.ABSOLUTE); + assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition()); + } + + /** + * Method: getComponent() + * + * @throws Exception thrown if something goes awry + */ + public void testGetComponent() throws Exception { + assertTrue(new ParachuteHandler(new BodyTube()).getComponent() instanceof Parachute); + } + + /** + * Method: getMaterialType() + * + * @throws Exception thrown if something goes awry + */ + public void testGetMaterialType() throws Exception { + assertEquals(Material.Type.SURFACE, new ParachuteHandler(new BodyTube()).getMaterialType()); + } + + /** + * Method: endHandler() + * + * @throws Exception thrown if something goes awry + */ + public void testEndHandler() throws Exception { + BodyTube tube = new BodyTube(); + ParachuteHandler handler = new ParachuteHandler(tube); + Parachute component = (Parachute) getField(handler, "chute"); + HashMap attributes = new HashMap(); + WarningSet warnings = new WarningSet(); + + handler.closeElement("Xb", attributes, "-10", warnings); + handler.closeElement("LocationMode", attributes, "1", warnings); + handler.endHandler("Parachute", attributes, null, warnings); + assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition()); + assertEquals(component.getPositionValue(), -10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + + handler.closeElement("Xb", attributes, "-10", warnings); + handler.closeElement("LocationMode", attributes, "2", warnings); + handler.endHandler("Parachute", attributes, null, warnings); + assertEquals(RocketComponent.Position.BOTTOM, component.getRelativePosition()); + assertEquals(component.getPositionValue(), 10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + } + + +} diff --git a/test/net/sf/openrocket/file/rocksim/RingHandlerTest.java b/test/net/sf/openrocket/file/rocksim/RingHandlerTest.java new file mode 100644 index 00000000..4c569ce1 --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/RingHandlerTest.java @@ -0,0 +1,171 @@ +/* + * RingHandlerTest.java + */ +package net.sf.openrocket.file.rocksim; + +import junit.framework.Test; +import junit.framework.TestSuite; +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.database.Databases; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.BodyTube; +import net.sf.openrocket.rocketcomponent.CenteringRing; +import net.sf.openrocket.rocketcomponent.RocketComponent; + +import java.util.HashMap; + +/** + * RingHandler Tester. + */ +public class RingHandlerTest extends BaseRocksimTest { + + /** + * The class under test. + */ + public static final Class classUT = RingHandler.class; + + /** + * The test class (this class). + */ + public static final Class testClass = RingHandlerTest.class; + + /** + * Create a test suite of all tests within this test class. + * + * @return a suite of tests + */ + public static Test suite() { + return new TestSuite(RingHandlerTest.class); + } + + /** + * Test constructor. + * + * @param name the name of the test to run. + */ + public RingHandlerTest(String name) { + super(name); + } + + /** + * Setup the fixture. + */ + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Teardown the fixture. + */ + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Method: openElement(String element, HashMap attributes, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testOpenElement() throws Exception { + assertEquals(PlainTextHandler.INSTANCE, new RingHandler(new BodyTube()).openElement(null, null, null)); + } + + /** + * Method: closeElement(String element, HashMap attributes, String content, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testCloseElement() throws Exception { + + BodyTube tube = new BodyTube(); + RingHandler handler = new RingHandler(tube); + CenteringRing component = (CenteringRing) getField(handler, "ring"); + HashMap attributes = new HashMap(); + WarningSet warnings = new WarningSet(); + + handler.closeElement("OD", attributes, "0", warnings); + assertEquals(0d, component.getOuterRadius()); + handler.closeElement("OD", attributes, "75", warnings); + assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getOuterRadius()); + handler.closeElement("OD", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("ID", attributes, "0", warnings); + assertEquals(0d, component.getInnerRadius()); + handler.closeElement("ID", attributes, "75", warnings); + assertEquals(75d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getInnerRadius()); + handler.closeElement("ID", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Len", attributes, "-1", warnings); + assertEquals(0d, component.getLength()); + handler.closeElement("Len", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength()); + handler.closeElement("Len", attributes, "10.0", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength()); + handler.closeElement("Len", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Name", attributes, "Test Name", warnings); + assertEquals("Test Name", component.getName()); + } + + + /** + * Method: constructor + * + * @throws Exception thrown if something goes awry + */ + public void testConstructor() throws Exception { + + try { + new RingHandler(null); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException iae) { + //success + } + + BodyTube tube = new BodyTube(); + RingHandler handler = new RingHandler(tube); + CenteringRing component = (CenteringRing) getField(handler, "ring"); + assertContains(component, tube.getChildren()); + } + + /** + * Method: setRelativePosition(RocketComponent.Position position) + * + * @throws Exception thrown if something goes awry + */ + public void testSetRelativePosition() throws Exception { + BodyTube tube = new BodyTube(); + RingHandler handler = new RingHandler(tube); + CenteringRing component = (CenteringRing) getField(handler, "ring"); + handler.setRelativePosition(RocketComponent.Position.ABSOLUTE); + assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition()); + } + + /** + * Method: getComponent() + * + * @throws Exception thrown if something goes awry + */ + public void testGetComponent() throws Exception { + assertTrue(new RingHandler(new BodyTube()).getComponent() instanceof CenteringRing); + } + + /** + * Method: getMaterialType() + * + * @throws Exception thrown if something goes awry + */ + public void testGetMaterialType() throws Exception { + assertEquals(Material.Type.BULK, new RingHandler(new BodyTube()).getMaterialType()); + } + + +} diff --git a/test/net/sf/openrocket/file/rocksim/RocksimContentHandlerTest.java b/test/net/sf/openrocket/file/rocksim/RocksimContentHandlerTest.java new file mode 100644 index 00000000..d0820cfc --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/RocksimContentHandlerTest.java @@ -0,0 +1,69 @@ +/* + * RocksimContentHandlerTest.java + */ +package net.sf.openrocket.file.rocksim; + +import junit.framework.Test; +import junit.framework.TestSuite; +import junit.framework.TestCase; + +/** + * RocksimContentHandler Tester. + * + */ +public class RocksimContentHandlerTest extends TestCase { + + /** + * The class under test. + */ + public static final Class classUT = RocksimContentHandler.class; + + /** + * The test class (this class). + */ + public static final Class testClass = RocksimContentHandlerTest.class; + + /** + * Create a test suite of all tests within this test class. + * + * @return a suite of tests + */ + public static Test suite() { + return new TestSuite(RocksimContentHandlerTest.class); + } + + /** + * Test constructor. + * + * @param name the name of the test to run. + */ + public RocksimContentHandlerTest(String name) { + super(name); + } + + /** + * Setup the fixture. + */ + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Teardown the fixture. + */ + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * + * Method: getDocument() + * + * @throws Exception thrown if something goes awry + */ + public void testGetDocument() throws Exception { + RocksimContentHandler handler = new RocksimContentHandler(); + assertNotNull(handler.getDocument()); + } + +} diff --git a/test/net/sf/openrocket/file/rocksim/RocksimLoaderTest.java b/test/net/sf/openrocket/file/rocksim/RocksimLoaderTest.java new file mode 100644 index 00000000..17b5f53c --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/RocksimLoaderTest.java @@ -0,0 +1,144 @@ +/* + * RocksimLoaderTest.java + * + */ +package net.sf.openrocket.file.rocksim; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import net.sf.openrocket.document.OpenRocketDocument; +import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.rocketcomponent.Stage; + +import java.io.BufferedInputStream; +import java.io.InputStream; + +/** + * RocksimLoader Tester. + * + */ +public class RocksimLoaderTest extends TestCase { + + /** + * The class under test. + */ + public static final Class classUT = RocksimLoader.class; + + /** + * The test class (this class). + */ + public static final Class testClass = RocksimLoaderTest.class; + + /** + * Create a test suite of all tests within this test class. + * + * @return a suite of tests + */ + public static Test suite() { + return new TestSuite(RocksimLoaderTest.class); + } + + /** + * Test constructor. + * + * @param name the name of the test to run. + */ + public RocksimLoaderTest(String name) { + super(name); + } + + /** + * Setup the fixture. + */ + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Teardown the fixture. + */ + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * + * Method: loadFromStream(InputStream source) + * + * @throws Exception thrown if something goes awry + */ + public void testLoadFromStream() throws Exception { + RocksimLoader loader = new RocksimLoader(); + //Stupid single stage rocket + InputStream stream = this.getClass().getResourceAsStream("rocksimTestRocket1.rkt"); + OpenRocketDocument doc = loader.loadFromStream(new BufferedInputStream(stream)); + + assertNotNull(doc); + Rocket rocket = doc.getRocket(); + assertNotNull(rocket); + assertEquals("FooBar Test", doc.getRocket().getName()); + assertTrue(loader.getWarnings().isEmpty()); + + stream = this.getClass().getResourceAsStream("rocksimTestRocket2.rkt"); + doc = loader.loadFromStream(new BufferedInputStream(stream)); + + assertNotNull(doc); + rocket = doc.getRocket(); + assertNotNull(rocket); + + //Do some simple asserts; the important thing here is just validating that the mass and cg were + //not overridden for each stage. + assertEquals("Three Stage Everything Included Rocket", doc.getRocket().getName()); + assertEquals(1, loader.getWarnings().size()); + assertEquals(3, rocket.getStageCount()); + Stage stage1 = (Stage)rocket.getChild(0); + assertFalse(stage1.isMassOverridden()); + assertFalse(stage1.isCGOverridden()); + Stage stage2 = (Stage)rocket.getChild(1); + assertFalse(stage2.isMassOverridden()); + assertFalse(stage2.isCGOverridden()); + Stage stage3 = (Stage)rocket.getChild(2); + assertFalse(stage3.isMassOverridden()); + assertFalse(stage3.isCGOverridden()); + + stream = this.getClass().getResourceAsStream("rocksimTestRocket3.rkt"); + doc = loader.loadFromStream(new BufferedInputStream(stream)); + + assertNotNull(doc); + rocket = doc.getRocket(); + assertNotNull(rocket); + assertEquals("Three Stage Everything Included Rocket - Override Total Mass/CG", doc.getRocket().getName()); + assertEquals(3, rocket.getStageCount()); + stage1 = (Stage)rocket.getChild(0); + stage2 = (Stage)rocket.getChild(1); + stage3 = (Stage)rocket.getChild(2); + + //Do some 1st level and simple asserts; the idea here is to not do a deep validation as that + //should have been covered elsewhere. Assert that the stage overrides are correct. + assertEquals(2, stage1.getChildCount()); + assertEquals("Nose cone", stage1.getChild(0).getName()); + assertEquals("Body tube", stage1.getChild(1).getName()); + assertTrue(stage1.isMassOverridden()); + assertEquals(0.185d, stage1.getOverrideMass()); + assertTrue(stage1.isCGOverridden()); + assertEquals(0.3d, stage1.getOverrideCG().x); + assertEquals(4, loader.getWarnings().size()); + + assertEquals(1, stage2.getChildCount()); + assertEquals("2nd Stage Tube", stage2.getChild(0).getName()); + assertTrue(stage2.isMassOverridden()); + assertEquals(0.21d, stage2.getOverrideMass()); + assertTrue(stage2.isCGOverridden()); + assertEquals(0.4d, stage2.getOverrideCG().x); + + assertEquals(2, stage3.getChildCount()); + assertEquals("Transition", stage3.getChild(0).getName()); + assertEquals("Body tube", stage3.getChild(1).getName()); + assertTrue(stage2.isMassOverridden()); + assertEquals(0.33d, stage3.getOverrideMass()); + assertTrue(stage2.isCGOverridden()); + assertEquals(0.5d, stage3.getOverrideCG().x); + } + +} diff --git a/test/net/sf/openrocket/file/rocksim/StreamerHandlerTest.java b/test/net/sf/openrocket/file/rocksim/StreamerHandlerTest.java new file mode 100644 index 00000000..3e0b2f11 --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/StreamerHandlerTest.java @@ -0,0 +1,195 @@ +/* + * StreamerHandlerTest.java + */ +package net.sf.openrocket.file.rocksim; + +import junit.framework.Test; +import junit.framework.TestSuite; +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.database.Databases; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.BodyTube; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.rocketcomponent.Streamer; + +import java.util.HashMap; + +/** + * StreamerHandler Tester. + */ +public class StreamerHandlerTest extends BaseRocksimTest { + + /** + * The class under test. + */ + public static final Class classUT = StreamerHandler.class; + + /** + * The test class (this class). + */ + public static final Class testClass = StreamerHandlerTest.class; + + /** + * Create a test suite of all tests within this test class. + * + * @return a suite of tests + */ + public static Test suite() { + return new TestSuite(StreamerHandlerTest.class); + } + + /** + * Test constructor. + * + * @param name the name of the test to run. + */ + public StreamerHandlerTest(String name) { + super(name); + } + + /** + * Setup the fixture. + */ + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Teardown the fixture. + */ + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Method: openElement(String element, HashMap attributes, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testOpenElement() throws Exception { + assertEquals(PlainTextHandler.INSTANCE, new StreamerHandler(new BodyTube()).openElement(null, null, null)); + } + + /** + * Method: closeElement(String element, HashMap attributes, String content, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testCloseElement() throws Exception { + + BodyTube tube = new BodyTube(); + StreamerHandler handler = new StreamerHandler(tube); + Streamer component = (Streamer) getField(handler, "streamer"); + HashMap attributes = new HashMap(); + WarningSet warnings = new WarningSet(); + + handler.closeElement("Width", attributes, "0", warnings); + assertEquals(0d/ RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getStripWidth()); + handler.closeElement("Width", attributes, "10", warnings); + assertEquals(10d/ RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getStripWidth()); + handler.closeElement("Width", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Len", attributes, "-1", warnings); + assertEquals(0d, component.getStripLength()); + handler.closeElement("Len", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getStripLength()); + handler.closeElement("Len", attributes, "10.0", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getStripLength()); + handler.closeElement("Len", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Name", attributes, "Test Name", warnings); + assertEquals("Test Name", component.getName()); + + handler.closeElement("DragCoefficient", attributes, "0.94", warnings); + assertEquals(0.94d, component.getCD()); + handler.closeElement("DragCoefficient", attributes, "-0.94", warnings); + assertEquals(-0.94d, component.getCD()); + handler.closeElement("DragCoefficient", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + } + + /** + * Method: constructor + * + * @throws Exception thrown if something goes awry + */ + public void testConstructor() throws Exception { + + try { + new StreamerHandler(null); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException iae) { + //success + } + + BodyTube tube = new BodyTube(); + StreamerHandler handler = new StreamerHandler(tube); + Streamer component = (Streamer) getField(handler, "streamer"); + assertContains(component, tube.getChildren()); + } + + /** + * Method: setRelativePosition(RocketComponent.Position position) + * + * @throws Exception thrown if something goes awry + */ + public void testSetRelativePosition() throws Exception { + BodyTube tube = new BodyTube(); + StreamerHandler handler = new StreamerHandler(tube); + Streamer component = (Streamer) getField(handler, "streamer"); + handler.setRelativePosition(RocketComponent.Position.ABSOLUTE); + assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition()); + } + + /** + * Method: getComponent() + * + * @throws Exception thrown if something goes awry + */ + public void testGetComponent() throws Exception { + assertTrue(new StreamerHandler(new BodyTube()).getComponent() instanceof Streamer); + } + + /** + * Method: getMaterialType() + * + * @throws Exception thrown if something goes awry + */ + public void testGetMaterialType() throws Exception { + assertEquals(Material.Type.SURFACE, new StreamerHandler(new BodyTube()).getMaterialType()); + } + + /** + * Method: endHandler() + * + * @throws Exception thrown if something goes awry + */ + public void testEndHandler() throws Exception { + BodyTube tube = new BodyTube(); + StreamerHandler handler = new StreamerHandler(tube); + Streamer component = (Streamer) getField(handler, "streamer"); + HashMap attributes = new HashMap(); + WarningSet warnings = new WarningSet(); + + handler.closeElement("Xb", attributes, "-10", warnings); + handler.closeElement("LocationMode", attributes, "1", warnings); + handler.endHandler("Streamer", attributes, null, warnings); + assertEquals(RocketComponent.Position.ABSOLUTE, component.getRelativePosition()); + assertEquals(component.getPositionValue(), -10d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + + handler.closeElement("Xb", attributes, "-10", warnings); + handler.closeElement("LocationMode", attributes, "2", warnings); + handler.endHandler("Streamer", attributes, null, warnings); + assertEquals(RocketComponent.Position.BOTTOM, component.getRelativePosition()); + assertEquals(component.getPositionValue(), 10d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH); + } + +} diff --git a/test/net/sf/openrocket/file/rocksim/TransitionHandlerTest.java b/test/net/sf/openrocket/file/rocksim/TransitionHandlerTest.java new file mode 100644 index 00000000..50657151 --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/TransitionHandlerTest.java @@ -0,0 +1,268 @@ +/* + * TransitionHandlerTest.java + */ +package net.sf.openrocket.file.rocksim; + +import junit.framework.Test; +import junit.framework.TestSuite; +import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.database.Databases; +import net.sf.openrocket.file.simplesax.PlainTextHandler; +import net.sf.openrocket.material.Material; +import net.sf.openrocket.rocketcomponent.ExternalComponent; +import net.sf.openrocket.rocketcomponent.Stage; +import net.sf.openrocket.rocketcomponent.Transition; + +import java.util.HashMap; + +/** + * TransitionHandler Tester. + */ +public class TransitionHandlerTest extends BaseRocksimTest { + + /** + * The class under test. + */ + public static final Class classUT = TransitionHandler.class; + + /** + * The test class (this class). + */ + public static final Class testClass = TransitionHandlerTest.class; + + /** + * Create a test suite of all tests within this test class. + * + * @return a suite of tests + */ + public static Test suite() { + return new TestSuite(TransitionHandlerTest.class); + } + + /** + * Test constructor. + * + * @param name the name of the test to run. + */ + public TransitionHandlerTest(String name) { + super(name); + } + + /** + * Setup the fixture. + */ + public void setUp() throws Exception { + super.setUp(); + } + + /** + * Teardown the fixture. + */ + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Method: constructor + * + * @throws Exception thrown if something goes awry + */ + public void testConstructor() throws Exception { + + try { + new TransitionHandler(null); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException iae) { + //success + } + + Stage stage = new Stage(); + TransitionHandler handler = new TransitionHandler(stage); + Transition component = (Transition) getField(handler, "transition"); + assertContains(component, stage.getChildren()); + } + + /** + * Method: openElement(String element, HashMap attributes, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testOpenElement() throws Exception { + assertEquals(PlainTextHandler.INSTANCE, new TransitionHandler(new Stage()).openElement(null, null, null)); + } + + /** + * Method: closeElement(String element, HashMap attributes, String content, WarningSet warnings) + * + * @throws Exception thrown if something goes awry + */ + public void testCloseElement() throws Exception { + + Stage stage = new Stage(); + HashMap attributes = new HashMap(); + WarningSet warnings = new WarningSet(); + + TransitionHandler handler = new TransitionHandler(stage); + Transition component = (Transition) getField(handler, "transition"); + + handler.closeElement("ShapeCode", attributes, "0", warnings); + assertEquals(Transition.Shape.CONICAL, component.getType()); + handler.closeElement("ShapeCode", attributes, "1", warnings); + assertEquals(Transition.Shape.OGIVE, component.getType()); + handler.closeElement("ShapeCode", attributes, "17", warnings); + assertEquals(RocksimNoseConeCode.PARABOLIC.asOpenRocket(), component.getType()); //test of default + handler.closeElement("ShapeCode", attributes, "foo", warnings); + assertNotNull(component.getType()); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Len", attributes, "-1", warnings); + assertEquals(0d, component.getLength()); + handler.closeElement("Len", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength()); + handler.closeElement("Len", attributes, "10.0", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getLength()); + handler.closeElement("Len", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("FrontDia", attributes, "-1", warnings); + assertEquals(0d, component.getForeRadius()); + handler.closeElement("FrontDia", attributes, "100", warnings); + assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getForeRadius()); + handler.closeElement("FrontDia", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("RearDia", attributes, "-1", warnings); + assertEquals(0d, component.getAftRadius()); + handler.closeElement("RearDia", attributes, "100", warnings); + assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getAftRadius()); + handler.closeElement("RearDia", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + final double aft = 100d; + component.setAftRadius(aft); + + handler.closeElement("ConstructionType", attributes, "0", warnings); + component.setAftShoulderRadius(1.1d); + component.setForeShoulderRadius(1.1d); + handler.closeElement("WallThickness", attributes, "-1", warnings); + handler.endHandler("Transition", attributes, null, warnings); + assertEquals(component.getAftRadius(), component.getThickness()); + assertEquals(component.getAftShoulderThickness(), component.getAftShoulderThickness()); + assertEquals(component.getForeShoulderThickness(), component.getForeShoulderThickness()); + handler.closeElement("WallThickness", attributes, "100", warnings); + handler.endHandler("Transition", attributes, null, warnings); + assertEquals(aft, component.getThickness()); + handler.closeElement("WallThickness", attributes, "foo", warnings); + handler.endHandler("Transition", attributes, null, warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("ConstructionType", attributes, "1", warnings); + component.setAftShoulderRadius(1.1d); + component.setForeShoulderRadius(1.1d); + handler.closeElement("WallThickness", attributes, "-1", warnings); + handler.endHandler("Transition", attributes, null, warnings); + assertEquals(0d, component.getThickness()); + assertEquals(0d, component.getAftShoulderThickness()); + assertEquals(0d, component.getForeShoulderThickness()); + handler.closeElement("WallThickness", attributes, "1.1", warnings); + handler.endHandler("Transition", attributes, null, warnings); + assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getThickness()); + assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderThickness()); + assertEquals(1.1d/RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getForeShoulderThickness()); + + + handler.closeElement("FrontShoulderLen", attributes, "-1", warnings); + assertEquals(0d, component.getForeShoulderLength()); + handler.closeElement("FrontShoulderLen", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getForeShoulderLength()); + handler.closeElement("FrontShoulderLen", attributes, "10.0", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getForeShoulderLength()); + handler.closeElement("FrontShoulderLen", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("RearShoulderLen", attributes, "-1", warnings); + assertEquals(0d, component.getAftShoulderLength()); + handler.closeElement("RearShoulderLen", attributes, "10", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderLength()); + handler.closeElement("RearShoulderLen", attributes, "10.0", warnings); + assertEquals(10d / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH, component.getAftShoulderLength()); + handler.closeElement("RearShoulderLen", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("FrontShoulderDia", attributes, "-1", warnings); + assertEquals(0d, component.getForeShoulderRadius()); + handler.closeElement("FrontShoulderDia", attributes, "100", warnings); + assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getForeShoulderRadius()); + handler.closeElement("FrontShoulderDia", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("RearShoulderDia", attributes, "-1", warnings); + assertEquals(0d, component.getAftShoulderRadius()); + handler.closeElement("RearShoulderDia", attributes, "100", warnings); + assertEquals(100d / RocksimHandler.ROCKSIM_TO_OPENROCKET_RADIUS, component.getAftShoulderRadius()); + handler.closeElement("RearShoulderDia", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + component.setType(Transition.Shape.HAACK); + handler.closeElement("ShapeParameter", attributes, "-1", warnings); + assertEquals(0d, component.getShapeParameter()); + handler.closeElement("ShapeParameter", attributes, "100", warnings); + assertEquals(Transition.Shape.HAACK.maxParameter(), component.getShapeParameter()); + handler.closeElement("ShapeParameter", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + assertEquals("Could not convert ShapeParameter value of foo. It is expected to be a number.", + warnings.iterator().next().toString()); + + warnings.clear(); + + component.setType(Transition.Shape.CONICAL); + component.setShapeParameter(0d); + handler.closeElement("ShapeParameter", attributes, "100", warnings); + assertEquals(0d, component.getShapeParameter()); + + handler.closeElement("FinishCode", attributes, "-1", warnings); + assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish()); + handler.closeElement("FinishCode", attributes, "100", warnings); + assertEquals(ExternalComponent.Finish.NORMAL, component.getFinish()); + handler.closeElement("FinishCode", attributes, "foo", warnings); + assertEquals(1, warnings.size()); + warnings.clear(); + + handler.closeElement("Name", attributes, "Test Name", warnings); + assertEquals("Test Name", component.getName()); + + handler.closeElement("Material", attributes, "Some Material", warnings); + handler.endHandler("Transition", attributes, null, warnings); + assertTrue(component.getMaterial().getName().contains("Some Material")); + } + + /** + * Method: getComponent() + * + * @throws Exception thrown if something goes awry + */ + public void testGetComponent() throws Exception { + assertTrue(new TransitionHandler(new Stage()).getComponent() instanceof Transition); + } + + /** + * Method: getMaterialType() + * + * @throws Exception thrown if something goes awry + */ + public void testGetMaterialType() throws Exception { + assertEquals(Material.Type.BULK, new TransitionHandler(new Stage()).getMaterialType()); + } + + +} diff --git a/test/net/sf/openrocket/file/rocksim/rocksimTestRocket1.rkt b/test/net/sf/openrocket/file/rocksim/rocksimTestRocket1.rkt new file mode 100644 index 00000000..79f7b003 --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/rocksimTestRocket1.rkt @@ -0,0 +1,743 @@ + +3 + + + FooBar Test +1 +1 +1 +0.75 +0.8 +0.81 +0.95 +0.95 +1 +0. +0. +0. +0. +0. +0. +0. +0. +1 +914.4 +0 +0 +0 +1 +0 +1 +11 +1 +0 +0,1215.49,0,0 +0,35.9506,0,0 +0,1226.38,0,0 +0,47.5027,0,0 +0,0,0,0 +0,0,0,0 +0 +1 +0 +1 +0. +0. +0 +0 +0 +0 +0 +0 +0 +0 +0. +10. +10. +10. +10. +0 +0 +0 +10. +0.15 +black +424.688 +66.04 +1417.95 +1332.23 +0. +1417.95 +0,66.04,0,0 +0,1332.23,0,0 + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + + +Apogee +24.1 +1049.21 +Polystyrene PS +Nose cone +65.3999 +1 +0. +126.438 +348.443 +0.0356487 +0.0356487 +0. +0 +19470 +PNC-70A +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +2 +0 +0 +0 +blue +2. +0.264319 +2. +0.264319 +1 +0 +8 +0 +0. +396.875 +57.15 +0 +0 +1 +58.3997 +2.159 +0. +53.1012 +66.675 +0. +0. + + + + +Estes +0. +1121.29 +Paper +Body tube +0. +0 +0. +10.636 +180.34 +0.0748306 +0.0748306 +0. +0 +EST 3090 +BT-80 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +3 +1 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +463.55 +66.04 +65.786 +360.68 +0 +0 +0. +0.5 +0. +0. +0 +0 + + + + +BalsaMachining.com +0. +128.148 +Balsa +Transition +0. +0 +0. +39.355 +37.0332 +0.0096001 +0.0096001 +0. +0 +TA7080 +Transition T70 to T80 2 in long +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +7 +0 +0 +0 +blue +-0.92852 +0.848729 +-0.92852 +0.848729 +1 +0 +8 +0 +824.23 +66.04 +53.34 +50.8 +0 +35.56 +35.56 +0 +0. +55.118 +53.34 +0. +0 +0. +264.12 +213.32 + + + + +Estes +0. +1121.29 +Paper +Body tube +0. +0 +0. +44.449 +222.25 +0.0787423 +0.0787423 +0. +0 +Estes +BT-70 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +8 +1 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +875.03 +56.388 +55.372 +444.5 +0 +0 +0. +0.5 +0. +0. +0 +0 + + +Public Missiles +0. +1905.24 +G10 fiberglass +Fin set +0. +0 +260.35 +153.85 +155.575 +0.0339112 +0.101734 +0. +0 +FIN-A-01 +Fins +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +9 +0 +0 +0 +blue +34.8792 +1.26026 +46.4312 +1.26026 +1 +0 +8 +0 +1135.38 +3 +184.15 +0. +184.15 +264.956 +282.575 +1.5875 +0 +0 +0 +0. +0. +0. +1 +0.990003 +0. +89.5773 +26.8071 +0. +0. +0. + + + + +Estes +0. +1121.29 +Paper +Body tube +0. +0 +0. +13.008 +228.6 +0. +0. +0. +0 +EST 3086 +BT-50 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +11 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +875.03 +24.7904 +24.13 +457.2 +0 +1 +24. +12.7 +0. +0. +1 +0 + + + + + + + + + + + + + + + + + + + + +445.129 +68.7587 +76.6476 +10.8263 +4.765 +1 +33.4284 +405.535 +2 +8.06125 +4 +6.06125 +22.4787 +8.06125 +1.35915 +65.9349 +1.0686 +76.5426 +4.01173 +172.076 +0. +0. +0 +1828.8 +0 +0. +0 +0.0523599 +0. +0. +770.314 +43. +0. +70. +7.22222 +304.8 +0. +0 +3 +1.34112 +3.53162 +2 +0.01 +0.02 +0 +5 +0. +0.1 +1 +0. +0 +3 +300. +2000. +1 +5.99999 +0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +2 +0.99 +2000. +1500. +2 +0.98 +1 +0. +0 +0.08 +1 +0. +1 +0. +1 +0. +1. +1. +0. +0 +0 +3600. +0. +0. +0. +0. +0. +0. +0. +0. +0. +0. +0. +0. +0. +0. +0. +0. +0. +0. +[E6-2] +15.4098 +0. +0. +0.25875 +5.69125 +0.11125 +10 +1 +800. +0 +Earth +Standard earth condistions. +4.078 +-172.076 +0. +56.537 +-3.38254 +-56.4357 +0. +0,0,8.06125,0,0 +-1,-1,-1,-1,-1 +0,0,0,0,0 +32,32,32,32,32 +1. +1 +0.233111 +0.739954 +0.0208295 +0.000194272 +{b33e529e-1ada-4524-9885-7382d7cf4d64} + + +0 +0 +0. +0. +0 +0. +0. +0. +0. +-1 +0,0,0 +0,0,0 +0,0,0 +0,0,0 +0,0,0 +0,0,0 +0,0,0 +0,0,0 + + + + +0 +0 +0. +0. +0 +0. +0. +0. +0. +-1 +0,0,0 +0,0,0 +0,0,0 +0,0,0 +0,0,0 +0,0,0 +0,0,0 +0,0,0 + + + + + + + + + + +1 +E6 +0. +Apogee +0.50038 +0. +5 +2. +0. +0. + + + + + + + diff --git a/test/net/sf/openrocket/file/rocksim/rocksimTestRocket2.rkt b/test/net/sf/openrocket/file/rocksim/rocksimTestRocket2.rkt new file mode 100644 index 00000000..39b3411b --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/rocksimTestRocket2.rkt @@ -0,0 +1,1583 @@ + +3 + + +Three Stage Everything Included Rocket +1 +1 +1 +0.75 +0.8 +0.81 +0.95 +0.95 +3 +0. +0. +0. +0. +0. +0. +0. +0. +1 +914.4 +0 +0 +0 +1 +0 +1 +25 +7 +0 +0,29.6333,326.159,887.03 +0,2,4.93008,33.0782 +0,29.6333,384.174,883.929 +0,2,6.91103,47.1184 +0,0,0,0 +0,0,0,0 +0 +3 +0 +3 +0. +0. +0 +0 +0 +0 +0 +0 +0 +0 +0. +10. +10. +10. +10. +0 +0 +0 +10. +0.15 +black +339.43 +66.3 +2104.53 +2104.53 +0. +1150.33 +0,66.3,66.3,66.3 +0,296.8,954.2,2104.53 + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + + +Aerospace Speciality Products +0. +128.148 +Balsa +Nose cone +0. +0 +0. +42.0747 +75.3029 +0.0152945 +0.0152945 +0. +0 +BNC80S + +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +1 +0 +0 +0 +blue +2. +0.0296333 +2. +0.0296333 +1 +0 +8 +0 +0. +88.9 +66.3 +0 +3 +0 +38.1 +0. +0. +64.3 +0. +0. +0. + + +Custom +20. +0. +Custom +Clay +17.8 +1 +17.8 +0. +0. +0. +0. +0. +0 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +2 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +17.8 +0 +0. + + + + +Apogee +0. +1121.29 +Paper +Attachment Rod +0. +0 +6.1 +2.47301 +78.85 +0.00684683 +0.00684683 +0. +0 +10062 +13 mm +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +3 +1 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +6.1 +13.82 +13.16 +157.7 +0 +0 +0. +0.5 +0. +0. +1 +0 + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Plate +0. +0 +78.9 +7.86272 +1.585 +0. +0. +0. +0 +LOC CR-2.56-(2)0.95 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +4 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +85. +66. +13.82 +3.17 +0 +0 +0 + + + + +Custom +0. +1400. +Carbon Fiber +Sleeve +0. +0 +0. +17.5527 +13.85 +0. +0. +0. +0 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +5 +0 +0 +2 +blue +0. +0. +0. +0. +1 +0 +8 +0 +136.1 +27.7 +13.82 +27.7 +0 +3 +0 + + + + +LOC Precision +170. +0.006685 +Rip stop nylon +Nose Cone Parachute +0. +1 +142.6 +15.8812 +34.5417 +0. +0. +0. +1 +LP-50 +50 In. 16 lines +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +6 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +148.7 +414.5 +0. +15 +16 +0.05 +1350. +1 +0.00032972 +Carpet String (Apogee 29500) +0.95 + + + + + + + + +Estes +15. +1121.29 +Paper +Body tube +100. +1 +0. +5.80486 +100. +0.0414942 +0.0414942 +0. +0 +EST 3090 +BT-80 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +7 +1 +0 +0 +rgb(54,250,21) +0. +0. +0. +0. +1 +0 +8 +0 +88.9 +66.04 +65.79 +200. +0 +0 +0. +0.5 +0. +0. +0 +0 + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Centering ring +0. +0 +190.2 +7.65502 +1.59 +0. +0. +0. +0 +LOC CR-2.56-0.95 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +8 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +279.1 +65.02 +25.4 +3.18 +0 +0 +0 + + + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Centering ring +0. +0 +165. +7.62626 +1.585 +0. +0. +0. +0 +LOC CR-2.56-(2)0.95 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +9 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +253.9 +65. +25.4 +3.17 +0 +0 +0 + + + + +Public Missiles Ltd. +0. +958.705 +Kraft phenolic +Body tube +0. +0 +137.9 +9.8818 +35. +0. +0. +0. +0 +KS-1.1 +KwikSwitch MMT 29mm +0. +-1.58371 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +10 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +226.8 +32.26 +29.21 +70. +0 +1 +29. +0.5 +0. +0. +1 +0 + + + + + + + + +Estes +0. +1121.29 +Paper +2nd Stage Tube +0. +0 +0. +10.4685 +180.34 +0.0748306 +0.0748306 +0. +0 +EST 3090 +BT-80 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +11 +1 +0 +0 +rgb(54,250,21) +0. +0. +0. +0. +1 +0 +8 +0 +288.9 +66.04 +65.79 +360.68 +0 +0 +0. +0.5 +0. +0. +0 +0 + + +LOC Precision +15.025 +1121.29 +Paper +Tube coupler +0. +1 +-10. +20.465 +35.45 +0. +0. +0. +0 +TC-2.56 +Tube Coupler +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +12 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +278.9 +65.79 +63.25 +70.9 +0 +4 +1 + + + + +Custom +40. +0. +Custom +Electronics +138.3 +1 +138.3 +0. +0. +0. +0. +0. +0 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +13 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +427.2 +0 +0. + + + + +Quest +0. +128.148 +Balsa +Fin set +0. +0 +228.6 +1.32269 +19.05 +0.0028791 +0.0086373 +0. +0 +Payloader One +Fin +0. +0.0830777 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +14 +0 +0 +0 +blue +2.93008 +0.52856 +5.49629 +0.52856 +1 +0 +8 +0 +517.5 +3 +38.1 +24.9 +45.7 +45.7 +6.6 +2.39 +0 +0 +2 +0. +0. +0. +1 +0.139993 +0. +54.2741 +2.83538 +0.653543 +0. +0. + + + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Centering ring +0. +0 +302. +7.65502 +1.59 +0. +0. +0. +0 +LOC CR-2.56-0.95 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +15 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +590.9 +65.02 +25.4 +3.18 +0 +0 +0 + + + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Centering ring +0. +0 +335.5 +7.62626 +1.585 +0. +0. +0. +0 +LOC CR-2.56-(2)0.95 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +16 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +624.4 +65. +25.4 +3.17 +0 +0 +0 + + + + +Public Missiles Ltd. +0. +958.705 +Kraft phenolic +Body tube +0. +0 +587.4 +9.8818 +35. +0. +0. +0. +0 +KS-1.1 +KwikSwitch MMT 29mm +0. +-1.58371 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +17 +1 +0 +1 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +587.4 +32.26 +29.21 +70. +0 +1 +29. +0.5 +0. +0. +1 +0 + + +Semroc +0. +1121.29 +Paper +Engine block +0. +0 +0. +2.69315 +2.39 +0. +0. +0. +0 +TB-7 +Thrust Block +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +18 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +587.4 +29.21 +14.61 +4.78 +0 +2 +1 + + + + + + + + + + +BalsaMachining.com +0. +128.148 +Balsa +Transition +0. +0 +0. +8.62096 +25.1578 +0.00986655 +0.00986655 +0. +0 +TA6080 +Transition T60 to T80 2.25 in long +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +19 +0 +0 +0 +blue +-1.20451 +0.675971 +-1.20451 +0.675971 +1 +0 +8 +0 +649.58 +66.04 +41.4 +57.15 +0 +20. +38.1 +1 +3. +64.77 +41.38 +0. +0 +0. +153.172 +96.022 + + + + +LOC/Precision +0. +1121.29 +Paper +Body tube +0. +0 +0. +33.5306 +209.2 +0.0604643 +0.0604643 +0. +0 +LOC BT-2.14 +Airframe tube +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +20 +1 +0 +0 +rgb(54,250,21) +0. +0. +0. +0. +1 +0 +8 +0 +706.73 +46. +45. +418.4 +0 +0 +0. +0.5 +0. +0. +0 +0 + + +Quest +0. +1121.29 +Paper +Elliptical Fins +0. +0 +69.7 +36.2048 +46. +0.00676907 +0.0203072 +0. +0 +0. +-0.519061 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +21 +0 +0 +0 +blue +3.64017 +0.802926 +6.19583 +0.802926 +1 +0 +8 +0 +776.43 +3 +92. +46. +46.9 +46.9 +33.49 +3.18 +1 +0 +0 +0. +0. +0. +1 +0.349066 +0. +43.8444 +3.30201 +0.5 +0. +0. + + + + +Public Missiles +0. +1905.24 +G10 fiberglass +Custom Fins +0. +0 +241.7 +256.292 +78.9922 +0.0355266 +0.10658 +0. +0 +FIN-C-02 +Fins +0. +0.357967 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +22 +0 +0 +0 +blue +25.7124 +0.996591 +34.6308 +0.996926 +1 +0 +8 +0 +948.43 +3 +152.4 +83.83 +146.72 +146.81 +39.42 +2.38 +2 +0 +2 +101.6 +10.6 +35.6 +1 +0. +0. +89.2598 +19.9941 +0.550066 +0. +0. +121.07 +83.8257 +152.4,0|126.202,146.715|36.455,146.715|0,0| +0,0,0,0,0,0,0 +10,10,10,10,10,10,10 +0,0,0,0,0,0,0 +0.5,10,0.5,0.5,0.00018939,0.001,1 +0.25,5,0.1,0.1,0.00018939,0.001,1 +0,0,0,0,0,0,0 +10,10,10,10,10,10,10 +0,0,0,0,0,0,0 +0.5,10,0.5,0.5,0.00018939,0.001,1 +0.25,5,0.1,0.1,0.00018939,0.001,1 + + + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Centering ring +0. +0 +379.5 +2.55395 +1.59 +0. +0. +0. +0 +LOC FCR-1.52-1.14 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +23 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +1086.23 +45. +24.79 +3.18 +0 +0 +1 + + + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Centering ring +0. +0 +272. +2.55395 +1.59 +0. +0. +0. +0 +LOC FCR-1.52-1.14 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +24 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +978.73 +45. +24.79 +3.18 +0 +0 +1 + + + + +Estes +0. +1121.29 +Paper +Body tube +0. +0 +259.7 +5.22902 +91.95 +0. +0. +0. +0 +EST 3086 +BT-50 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +25 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +966.43 +24.79 +24.13 +183.9 +0 +1 +24. +0.5 +0. +0. +1 +0 + + + + + + + + + + + + + + + + + diff --git a/test/net/sf/openrocket/file/rocksim/rocksimTestRocket3.rkt b/test/net/sf/openrocket/file/rocksim/rocksimTestRocket3.rkt new file mode 100644 index 00000000..a7c46dae --- /dev/null +++ b/test/net/sf/openrocket/file/rocksim/rocksimTestRocket3.rkt @@ -0,0 +1,1961 @@ + +3 + + +Three Stage Everything Included Rocket - Override Total Mass/CG +1 +1 +1 +0.75 +0.8 +0.81 +0.95 +0.95 +3 +185. +210. +330. +0. +0. +300. +400. +500. +1 +914.4 +0 +0 +0 +1 +0 +1 +32 +7 +0 +0,29.6333,327.236,966.855 +0,2,4.95647,83.562 +0,29.6333,385.082,953.76 +0,2,6.95476,97.0629 +0,0,0,0 +0,0,0,0 +0 +3 +0 +3 +0. +0. +0 +0 +0 +0 +0 +0 +0 +0 +0. +10. +10. +10. +10. +0 +0 +0 +10. +0.15 +black +334.83 +66. +2155.23 +2155.23 +0. +1150.33 +0,66,66,66 +0,347.5,1004.9,2155.23 + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + + +Aerospace Speciality Products +0. +128.148 +Balsa +Nose cone +0. +0 +0. +42.6368 +76.0242 +0.0152192 +0.0152192 +0. +0 +BNC80S + +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +1 +1 +0 +0 +blue +2. +0.0296333 +2. +0.0296333 +1 +0 +8 +0 +0. +88.9 +66. +0 +3 +0 +38.1 +0. +0. +65.9 +0. +0. +0. + + +Custom +20. +0. +Custom +Clay +17.8 +1 +17.8 +0. +0. +0. +0. +0. +0 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +2 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +17.8 +0 +0. + + + + +Apogee +0. +1121.29 +Paper +Attachment Rod +0. +0 +6.1 +2.47301 +78.85 +0.00684683 +0.00684683 +0. +0 +10062 +13 mm +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +3 +1 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +6.1 +13.82 +13.16 +157.7 +0 +0 +0. +0.5 +0. +0. +1 +0 + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Plate +0. +0 +78.9 +7.86272 +1.585 +0. +0. +0. +0 +LOC CR-2.56-(2)0.95 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +4 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +85. +66. +13.82 +3.17 +0 +0 +0 + + + + +Custom +0. +1400. +Carbon Fiber +Sleeve +0. +0 +0. +17.5527 +13.85 +0. +0. +0. +0 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +5 +0 +0 +2 +blue +0. +0. +0. +0. +1 +0 +8 +0 +136.1 +27.7 +13.82 +27.7 +0 +3 +0 + + + + +LOC Precision +170. +0.006685 +Rip stop nylon +Nose Cone Parachute +0. +1 +142.6 +15.8812 +34.5417 +0. +0. +0. +1 +LP-50 +50 In. 16 lines +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +6 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +148.7 +414.5 +0. +15 +16 +0.05 +1350. +1 +0.00032972 +Carpet String (Apogee 29500) +0.95 + + + + + + + + +Estes +15. +1121.29 +Paper +Body tube +100. +1 +0. +5.805 +100. +0.0414942 +0.0414942 +0. +0 +EST 3090 +BT-80 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +7 +1 +0 +0 +rgb(54,250,21) +0. +0. +0. +0. +1 +0 +8 +0 +88.9 +66. +65.79 +200. +0 +0 +0. +0.5 +0. +0. +0 +0 + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Centering ring +0. +0 +190.2 +7.65502 +1.59 +0. +0. +0. +0 +LOC CR-2.56-0.95 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +8 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +279.1 +65.02 +25.4 +3.18 +0 +0 +0 + + + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Centering ring +0. +0 +165. +7.62626 +1.585 +0. +0. +0. +0 +LOC CR-2.56-(2)0.95 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +9 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +253.9 +65. +25.4 +3.17 +0 +0 +0 + + + + +Public Missiles Ltd. +0. +958.705 +Kraft phenolic +Body tube +0. +0 +137.9 +9.8818 +35. +0. +0. +0. +0 +KS-1.1 +KwikSwitch MMT 29mm +0. +-1.58371 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +10 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +226.8 +32.26 +29.21 +70. +0 +1 +29. +0.5 +0. +0. +1 +0 + + + + +Apogee +0. +1121.29 +Paper +Launch lug +0. +0 +77.2 +1.11942 +38.1 +0.00374518 +0.00199411 +0. +0 +13056 + +37.185 +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +26 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +166.1 +8.33 +7.26 +76.2 +0 + + + + +Custom +0. +0. +Pod +0. +0 +200. +0. +0. +0. +0. +0. +0 +36.175 +-1.50735 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +29 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +288.9 +1 +1 +1 + + +Apogee +0. +958.705 +Kraft phenolic +Body tube +0. +0 +0. +0.400397 +29.3 +0.00116902 +0.00116902 +0. +0 +9601 +6 mm +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +30 +0 +0 +0 +rgb(54,250,21) +0. +0. +0. +0. +1 +0 +8 +0 +288.9 +6.35 +5.59 +58.6 +0 +0 +0. +0.5 +0. +0. +0 +0 + + + + + + + + + + +Estes +0. +1121.29 +Paper +2nd Stage Tube +0. +0 +0. +10.468 +180.34 +0.0748306 +0.0748306 +0. +0 +EST 3090 +BT-80 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +11 +0 +0 +0 +rgb(54,250,21) +0. +0. +0. +0. +1 +0 +8 +0 +288.9 +66. +65.79 +360.68 +0 +0 +0. +0.5 +0. +0. +0 +0 + + +LOC Precision +15.025 +1121.29 +Paper +Tube coupler +0. +1 +-10. +20.465 +35.45 +0. +0. +0. +0 +TC-2.56 +Tube Coupler +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +12 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +278.9 +65.79 +63.25 +70.9 +0 +4 +1 + + + + +Custom +40. +0. +Custom +Electronics +138.3 +1 +138.3 +0. +0. +0. +0. +0. +0 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +13 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +427.2 +0 +0. + + + + +Quest +0. +128.148 +Balsa +Fin set +0. +0 +228.6 +1.32269 +19.05 +0.0028791 +0.0086373 +0. +0 +Payloader One +Fin +0. +0.0830777 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +14 +0 +0 +0 +blue +2.95647 +0.52856 +5.54523 +0.52856 +1 +0 +8 +0 +517.5 +3 +38.1 +24.9 +45.7 +45.7 +6.6 +2.39 +0 +0 +2 +0. +0. +0. +1 +0.139993 +0. +54.2541 +2.86063 +0.653543 +0. +0. + + + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Centering ring +0. +0 +302. +7.65502 +1.59 +0. +0. +0. +0 +LOC CR-2.56-0.95 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +15 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +590.9 +65.02 +25.4 +3.18 +0 +0 +0 + + + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Centering ring +0. +0 +335.5 +7.62626 +1.585 +0. +0. +0. +0 +LOC CR-2.56-(2)0.95 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +16 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +624.4 +65. +25.4 +3.17 +0 +0 +0 + + + + +Public Missiles Ltd. +0. +958.705 +Kraft phenolic +Body tube +0. +0 +587.4 +9.8818 +35. +0. +0. +0. +0 +KS-1.1 +KwikSwitch MMT 29mm +0. +-1.58371 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +17 +0 +0 +1 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +587.4 +32.26 +29.21 +70. +0 +1 +29. +0.5 +0. +0. +1 +0 + + +Semroc +0. +1121.29 +Paper +Engine block +0. +0 +0. +2.69315 +2.39 +0. +0. +0. +0 +TB-7 +Thrust Block +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +18 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +587.4 +29.21 +14.61 +4.78 +0 +2 +1 + + + + + + +Apogee +0. +1121.29 +Paper +Launch lug +0. +0 +265.8 +1.11942 +38.1 +0.00374518 +0.00199411 +0. +0 +13056 + +37.185 +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +27 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +554.7 +8.33 +7.26 +76.2 +0 + + + + + + + + +BalsaMachining.com +0. +128.148 +Balsa +Transition +0. +0 +0. +8.61936 +25.1551 +0.0098623 +0.0098623 +0. +0 +TA6080 +Transition T60 to T80 2.25 in long +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +19 +0 +0 +0 +blue +-1.213 +0.675973 +-1.213 +0.675973 +1 +0 +8 +0 +649.58 +66. +41.4 +57.15 +0 +20. +38.1 +1 +3. +64.77 +41.38 +0. +0 +0. +153.339 +96.1895 + + + + +LOC/Precision +0. +1121.29 +Paper +Body tube +0. +0 +0. +0. +nan. +0.0544179 +0.0544179 +0. +0 +LOC BT-2.14 +Airframe tube +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +20 +0 +0 +0 +rgb(54,250,21) +0. +0. +0. +0. +1 +0 +8 +0 +706.73 +41.4 +41. +418.4 +0 +0 +0. +0.5 +0. +0. +0 +0 + + +Quest +0. +1121.29 +Paper +Elliptical Fins +0. +0 +69.7 +36.2048 +46. +0.00676907 +0.0203072 +0. +0 +0. +-0.519061 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +21 +0 +0 +0 +blue +3.61024 +0.802926 +6.03948 +0.802926 +1 +0 +8 +0 +776.43 +3 +92. +46. +46.9 +46.9 +33.49 +3.18 +1 +0 +0 +0. +0. +0. +1 +0.349066 +0. +41.5444 +3.21868 +0.5 +0. +0. + + + + +Public Missiles +0. +1905.24 +G10 fiberglass +Custom Fins +0. +0 +241.7 +256.292 +78.9922 +0.0355266 +0.10658 +0. +0 +FIN-C-02 +Fins +0. +0.357967 +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +22 +0 +0 +0 +blue +25.7037 +0.996526 +34.1865 +0.996822 +1 +0 +8 +0 +948.43 +3 +152.4 +84.53 +146.72 +146.81 +39.07 +2.38 +2 +0 +2 +101.6 +10.6 +35.6 +1 +0. +0. +87.0529 +19.7376 +0.554659 +0. +0. +121.39 +84.5261 +152.4,0|126.202,146.715|36.455,146.715|0,0| +0,0,0,0,0,0,0 +10,10,10,10,10,10,10 +0,0,0,0,0,0,0 +0.5,10,0.5,0.5,0.00018939,0.001,1 +0.25,5,0.1,0.1,0.00018939,0.001,1 +0,0,0,0,0,0,0 +10,10,10,10,10,10,10 +0,0,0,0,0,0,0 +0.5,10,0.5,0.5,0.00018939,0.001,1 +0.25,5,0.1,0.1,0.00018939,0.001,1 + + + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Centering ring +0. +0 +379.5 +1.99074 +1.59 +0. +0. +0. +0 +LOC FCR-1.52-1.14 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +23 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +1086.23 +41.4 +24.79 +3.18 +0 +0 +1 + + + + +LOC Precision +0. +724.996 +Aircraft plywood (LOC) +Centering ring +0. +0 +272. +1.99074 +1.59 +0. +0. +0. +0 +LOC FCR-1.52-1.14 +Centering Ring +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +24 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +978.73 +41.4 +24.79 +3.18 +0 +0 +1 + + + + +Estes +0. +1121.29 +Paper +Body tube +0. +0 +259.7 +5.22902 +91.95 +0. +0. +0. +0 +EST 3086 +BT-50 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +rgb(0,0,250) +rgb(0,0,250) +rgb(255,255,255) +1 +25 +0 +0 +0 +rgb(0,0,250) +0. +0. +0. +0. +1 +0 +8 +0 +966.43 +24.79 +24.13 +183.9 +0 +1 +24. +0.5 +0. +0. +1 +0 + + + + +Custom +0. +1121.29 +Paper +Tube fins +0. +0 +0. +12.6878 +24.79 +0.0688063 +0.0688063 +0. +0 +35.395 +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +28 +0 +0 +0 +blue +10.866 +0.707815 +10.866 +0.707815 +1 +0 +8 +0 +706.73 +24.79 +24.13 +49.58 +0 +9 +0.715549 +9 + + + + +Custom +0. +688.794 +Cardboard +Ringtail +0. +0 +0. +2.93707 +10. +0.00474229 +0.00444249 +0. +0 +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +31 +0 +0 +2 +rgb(255,9,18) +39.6386 +1.10463 +39.6386 +1.10463 +1 +0 +8 +0 +1105.13 +3 +20. +20. +7.495 +7.495 +0. +3. +0 +0 +0 +0. +0. +0. +1 +0. +0. +0. +0. +0. +0. +0. +56.39 +55.37 +20. +1121.29 +0 +Paper + + + + +Apogee +0. +1309. +Mylar +Streamer +0. +0 +149.4 +5.67514 +50.8 +0. +0. +0. +0 +29006 + +0. +0. +file=()|position=(0,0,0)|origin=(0.5,0.5,0.5)|scale=(1,1,1)|repeat=(1)|interpolate=(0)|flipr(0)|flips(0)|flipt=(0)|preventseam=(1) +1. +0. +1. +0. +1. +blue +blue +white +1 +32 +0 +0 +0 +blue +0. +0. +0. +0. +1 +0 +8 +0 +856.13 +1422.4 +101.6 +0.03 +1 +0.127 +0 +1 + + + + + + + + + + + + + + + + + -- 2.30.2