]> git.gag.com Git - debian/openrocket/commitdiff
Merge branch 'v1.1.0' into debian debian/1.1.0-1
authorBdale Garbee <bdale@gag.com>
Wed, 4 Aug 2010 12:26:45 +0000 (08:26 -0400)
committerBdale Garbee <bdale@gag.com>
Wed, 4 Aug 2010 12:26:45 +0000 (08:26 -0400)
Conflicts:
debian/changelog

86 files changed:
ChangeLog
README.TXT
ReleaseNotes
TODO
build.properties
build.xml
debian/changelog
debian/control
debian/patches/use-system-libs.diff
html/actions/.htaccess [deleted file]
html/actions/reportbug.php [deleted file]
html/actions/testbugreport.html [deleted file]
html/actions/updates.php [deleted file]
html/contact.html [deleted file]
html/documentation.html [deleted file]
html/download.html [deleted file]
html/favicon.ico [deleted file]
html/features.html [deleted file]
html/index.html [deleted file]
html/layout.css [deleted file]
html/license.html [deleted file]
html/report.html [deleted file]
html/robots.txt [deleted file]
html/screenshots.html [deleted file]
html/shots-small/dialog-analysis.jpg [deleted file]
html/shots-small/dialog-edit.jpg [deleted file]
html/shots-small/dialog-plot-options.jpg [deleted file]
html/shots-small/dialog-plot.jpg [deleted file]
html/shots-small/main.jpg [deleted file]
html/shots/dialog-analysis.png [deleted file]
html/shots/dialog-edit.png [deleted file]
html/shots/dialog-plot-options.png [deleted file]
html/shots/dialog-plot.png [deleted file]
html/shots/main.png [deleted file]
html/thesis.pdf [deleted file]
html/update-html.sh [deleted file]
html/valid-xhtml10.png [deleted file]
html/vcss.gif [deleted file]
html/whitebox.png [deleted file]
releasing.txt
src/net/sf/openrocket/file/GeneralRocketLoader.java
src/net/sf/openrocket/file/rocksim/AttachedPartsHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/BaseHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/BodyTubeHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/FinSetHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/InnerBodyTubeHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/LaunchLugHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/MassObjectHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/NoseConeHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/ParachuteHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/PositionDependentHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/RecoveryDeviceHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/RingHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/RocksimDensityType.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/RocksimFinishCode.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/RocksimHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/RocksimLoader.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/RocksimLocationMode.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/RocksimNoseConeCode.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/StreamerHandler.java [new file with mode: 0644]
src/net/sf/openrocket/file/rocksim/TransitionHandler.java [new file with mode: 0644]
src/net/sf/openrocket/gui/main/BasicFrame.java
src/net/sf/openrocket/gui/main/ExceptionHandler.java
src/net/sf/openrocket/gui/main/SimpleFileFilter.java [new file with mode: 0644]
src/net/sf/openrocket/logging/DelegatorLogger.java
src/net/sf/openrocket/logging/LogHelper.java
src/net/sf/openrocket/logging/PrintStreamLogger.java [new file with mode: 0644]
src/net/sf/openrocket/logging/StandardOutputLogger.java [deleted file]
src/net/sf/openrocket/startup/Application.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/BodyTubeHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/FinSetHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/InnerBodyTubeHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/LaunchLugHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/MassObjectHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/NoseConeHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/ParachuteHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/RingHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/RocksimContentHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/RocksimLoaderTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/RocksimTestBase.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/StreamerHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/TransitionHandlerTest.java [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/rocksimTestRocket1.rkt [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/rocksimTestRocket2.rkt [new file with mode: 0644]
test/net/sf/openrocket/file/rocksim/rocksimTestRocket3.rkt [new file with mode: 0644]
test/net/sf/openrocket/logging/LoggingTest.java

index 82b64d13704be6b3564653127706acc280d94967..4404b9ca9e27beb455bc61b75b062521aebf21f2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2010-03-21  Sampo Niskanen
+
+       * Released version 1.1.0
+
+2010-03-20  Doug Pedrick
+
+       * [BUG] Fixed RockSim design material loading
+
+2010-03-20  Sampo Niskanen
+
+       * Minor enhancements to the logging system
+       * Updated unit tests of Rocksim file loading
+
+2010-03-13  Doug Pedrick / Sampo Niskanen
+
+       * Initial RockSim design loading support
+
 2010-03-10  Sampo Niskanen
 
        * Released version 1.0.0
index a9d6d6f0f7983b0db826873d9f52d8b6d8c4bb7f..54084d7763907a92b7f7498d7a93074e8078e65b 100644 (file)
@@ -18,3 +18,12 @@ To start the software run the class
 or from the JAR file run
 
     $ java -jar OpenRocket-<VERSION>.jar
+
+
+
+Contributions have been made by:
+--------------------------------
+
+Sampo Niskanen, main developer
+Doug Pedrick, support for reading RockSim designs
+
index 596a411a5fb69a53d719d976a35b4b9edc663a06..a72db2e66101d4cbf0183dc9e8d117b17b753ff0 100644 (file)
@@ -1,3 +1,10 @@
+OpenRocket 1.1.0  (2010-03-21):
+-------------------------------
+
+Support for loading RockSim rocket design files (.rkt) thanks to
+Doug Pedrick.
+
+
 OpenRocket 1.0.0  (2010-03-10):
 -------------------------------
 
diff --git a/TODO b/TODO
index ef866a76699f4c1529fabe634abf4b511f840d7d..1645b66a7c633adcae1510dcb6d10eddc8780dcf 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,18 +1,24 @@
 
-Feature roadmap for OpenRocket 1.0
+Feature roadmap for OpenRocket 2.0
 ----------------------------------
 
+Must have:
 
-Must-have:
+- Logging system into use
+- Reduce memory footprint
+- Reduce memory leakage
+- Load thrust curves from external directory
+- Support duplicate motor definitions
 
 
 Maybe:
 
+- Water rocket modeling
 
 
 
-Postponed:
-----------
+More ideas:
+-----------
 
 
 Memory usage:
@@ -120,6 +126,8 @@ File support:
 
 Refactoring tasks:
 
+- Change databases and icon loading to bean instances, implement stubs
+  for unit tests
 - Move startup class to src14 directory, remove reflection
 - Remove database etc. initialization from class initialization,
   create separate set of test motors
@@ -135,48 +143,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
index 73ec3d0b3a64f9317cc87686668d68136e3495bd..1bb030aca055620495d4d88c2549b4eac4db0769 100644 (file)
@@ -1,7 +1,7 @@
 
 # The OpenRocket build version
 
-build.version=1.0.0
+build.version=1.1.0
 
 
 # The source of the package.  When building a package for a specific
index 394aea4ee87ea6393cdcb1b7f97cf8291b098f6b..58155ea3c03d3c715802230e5b92292619d59113 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -36,6 +36,7 @@
                <pathelement location="${basedir}"/>
                <pathelement location="${build-test.dir}"/>
                <pathelement location="${classes.dir}"/>
+               <pathelement location="${src-test.dir}"/>
 <!--           <pathelement location="${ant.library.dir}/junit4.jar"/> -->
                <pathelement location="lib-test/junit-4.7.jar"/>
        </path>
@@ -189,14 +190,15 @@ ${nonascii}</fail>
                
                <echo>Running unit tests</echo>
                <mkdir dir="tmp/rawtestoutput"/>
-               <junit fork="yes" forkmode="once" printsummary="true" failureproperty="junit.failure">
+               <junit fork="yes" forkmode="once" printsummary="false" failureproperty="junit.failure">
                        <classpath>
                                <path refid="test-classpath"/>
                                <path location="${basedir}"/>
                        </classpath>
                        <batchtest todir="tmp/rawtestoutput">
                                <fileset dir="${build-test.dir}">
-                                       <include name="**/*Test*.class" />
+                                       <include name="**/Test*.class" />
+                                       <include name="**/*Test.class" />
                                        <exclude name="**/*$*.class" />
                                        <exclude name="Test.class" />
                                </fileset>
index ed356b6a92fb4278b718b397e49168c66a6ad706..a8c3a0e57b450a5c6b59084b9d0dfea88f5d5228 100644 (file)
@@ -1,3 +1,10 @@
+openrocket (1.1.0-1) unstable; urgency=low
+
+  * new upstream version
+  * update build deps
+
+ -- Bdale Garbee <bdale@gag.com>  Tue, 03 Aug 2010 22:50:39 -0400
+
 openrocket (1.0.0-3) unstable; urgency=low
 
   * fix bashism in debian/rules file, closes: #581463
index 8b1138a453367c977dd81c58f2372ae10ce56e0e..484880790d69903ddec524e1e18c32aeb97e4e0f 100644 (file)
@@ -3,7 +3,7 @@ Section: science
 Priority: optional
 Maintainer: Bdale Garbee <bdale@gag.com>
 Build-Depends: debhelper (>= 7.0.50~), openjdk-6-jdk, ant, ant-optional, libjcommon-java, libjfreechart-java, libmiglayout-java, junit4
-Standards-Version: 3.8.4
+Standards-Version: 3.9.1
 Homepage: http://openrocket.sourceforge.net/
 Vcs-Git: git://git.gag.com/debian/openrocket
 
index 24caa9d2b2f5c069838d9382e28a418590acbc53..152a87a886120a64d39e02030268a7c242900a8d 100644 (file)
@@ -1,5 +1,5 @@
 diff --git a/build.xml b/build.xml
-index 394aea4..5915b1a 100644
+index 58155ea..8c4421b 100644
 --- a/build.xml
 +++ b/build.xml
 @@ -13,7 +13,6 @@
@@ -10,7 +10,7 @@ index 394aea4..5915b1a 100644
  
        <property name="pkgname"     value="${ant.project.name}-${build.version}"/>
        
-@@ -28,16 +27,18 @@
+@@ -28,7 +27,10 @@
        
        <!-- Classpath definitions -->
        <path id="classpath">
@@ -20,20 +20,19 @@ index 394aea4..5915b1a 100644
 +              <pathelement location="/usr/share/java/jfreechart.jar"/>
 +              <pathelement location="/usr/share/java/miglayout.jar"/>
        </path>
--      
-+
+       
        <path id="test-classpath">
-               <path refid="classpath"/>
-               <pathelement location="${basedir}"/>
+@@ -37,8 +39,7 @@
                <pathelement location="${build-test.dir}"/>
                <pathelement location="${classes.dir}"/>
+               <pathelement location="${src-test.dir}"/>
 -<!--          <pathelement location="${ant.library.dir}/junit4.jar"/> -->
 -              <pathelement location="lib-test/junit-4.7.jar"/>
 +              <pathelement location="/usr/share/java/junit4.jar"/>
        </path>
        
  
-@@ -71,10 +72,8 @@
+@@ -72,10 +73,8 @@
                        <manifest>
                                <attribute name="Main-Class" value="${main-class}"/>
                                <attribute name="SplashScreen-Image" value="pix/splashscreen.png"/>
@@ -45,7 +44,7 @@ index 394aea4..5915b1a 100644
                </jar>
        </target>
        
-@@ -90,7 +89,7 @@
+@@ -91,7 +90,7 @@
                        <fileset dir="." includes="*">
                                <type type="file"/>
                        </fileset>
@@ -54,7 +53,7 @@ index 394aea4..5915b1a 100644
                </copy>
                <zip destfile="${dist.src}" basedir="${build.dir}" includes="${pkgname}/"/>
                <delete dir="${build.dir}/${pkgname}"/>
-@@ -213,4 +212,4 @@ ${nonascii}</fail>
+@@ -215,4 +214,4 @@ ${nonascii}</fail>
                </echo>
        </target>
      
diff --git a/html/actions/.htaccess b/html/actions/.htaccess
deleted file mode 100644 (file)
index d18e09c..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-
-#RewriteEngine On
-#RewriteBase /actions/
-#RewriteRule ^reportbug$ reportbug.php
-
-
-# Redirect bug reports to a server that allows sending mail
-
-Redirect 307 /actions/reportbug http://sampo.kapsi.fi/openrocket/reportbug.php
-
-RewriteEngine On
-RewriteBase /actions/
-RewriteRule ^updates$ updates.php
-
diff --git a/html/actions/reportbug.php b/html/actions/reportbug.php
deleted file mode 100644 (file)
index 86b8d8c..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-<?
-$mailaddr = "openrocket-bugs@lists.sourceforge.net";
-//$mailaddr = "sampo.niskanen@gmail.com";
-
-$version = $_POST["version"];
-$content = $_POST["content"];
-
-
-// Parse headers
-if (!function_exists('getallheaders')) {
-    function getallheaders() {
-       foreach ($_SERVER as $name => $value) {
-           if (substr($name, 0, 5) == 'HTTP_') {
-               $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
-           }
-       }
-       return $headers;
-    }
-}
-
-$headers = "\n\n\n";
-foreach (getallheaders() as $header => $value) {
-       $headers = $headers . "$header: $value\n";
-}
-
-// Set HTTP content-type header
-header("Content-type: text/plain; charset=utf-8");
-
-
-// Check for valid submission
-if (preg_match("/^[a-zA-Z0-9. -]{1,30}$/", $version) &&
-    strlen($content) > 0) {
-
-  $subject = date("Y-m-d H:i:s") . " Automatic bug report for OpenRocket " . $version;
-  if (mail($mailaddr, $subject, $content . $headers, 
-       "From: Automatic Bug Reports <".$mailaddr.">\r\n".
-       "Content-Type: text/plain; charset=utf-8")) {
-       
-       // Success - OpenRocket recognizes status code 202
-       header("HTTP/1.0 202 Accepted");
-       echo "202 Accepted:  Bug report successfully sent.";
-//     echo "\nContent:\n$content";
-       
-    } else {
-       
-       // Sending mail failed
-       header("HTTP/1.0 503 Service Unavailable");
-       echo "503 Service Unavailable:  Unable to send bug report.";
-       
-    }
-
-} else {
-       
-       // Bad request
-       header("HTTP/1.0 400 Bad Request");
-       echo "400 Bad Request:  Illegal request.\n";
-       
-}
-
-?>
\ No newline at end of file
diff --git a/html/actions/testbugreport.html b/html/actions/testbugreport.html
deleted file mode 100644 (file)
index 28d7e9a..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>Bug report test</title>
-  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"/>
-</head>
-
-<body>
-  <form method="post" action="http://openrocket.sourceforge.net/actions/reportbug" accept-charset="UTF-8">
-    <p>Version: <input type="text" size="30" name="version" value="1.0.0"/></p>
-    <p>Test bug report content:</p>
-    <p><textarea name="content" cols="80" rows="20">
----------- Test bug report ----------
-
-äöå
-
----------- End ----------
-</textarea></p>
-    <p><input type="submit" value="Submit bug report"/></p>
-    <p>A successful submission should result in a <em>202 Accepted</em> response.</p>
-    <p>Please do not abuse.</p>
-  </form>
-</body>
-</html>
-
diff --git a/html/actions/updates.php b/html/actions/updates.php
deleted file mode 100644 (file)
index e7fa0ee..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-<?
-$logfiles = "/home/groups/o/op/openrocket/persistent/logs/access-";
-
-
-// getallheaders method
-if (!function_exists('getallheaders')) {
-    function getallheaders() {
-       foreach ($_SERVER as $name => $value) {
-           if (substr($name, 0, 5) == 'HTTP_') {
-               $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
-           }
-       }
-       return $headers;
-    }
-}
-
-
-// Parse + validate headers
-$orid = "";
-$orversion = "";
-$oros = "";
-$orjava = "";
-$orcountry = "";
-foreach (getallheaders() as $header => $value) {
-    if (preg_match("/^[a-zA-Z0-9 !$%&()*+,.\\/:=?@_~-]{1,40}$/", $value)) {
-       $h = strtolower($header);
-       if ($h == 'x-openrocket-version') {
-           $orversion = $value;
-       } else if ($h == 'x-openrocket-id') {
-           $orid = $value;
-       } else if ($h == 'x-openrocket-os') {
-           $oros = $value;
-       } else if ($h == 'x-openrocket-java') {
-           $orjava = $value;
-       } else if ($h == 'x-openrocket-country') {
-           $orcountry = $value;
-       }
-    }
-}
-
-// Log the request
-if ((strlen($orversion) > 0 || strlen($orid) > 0 || strlen($oros) > 0
-     || strlen($orjava) > 0 || strlen($orcountry) > 0) &&
-
-    (strlen($orversion) < 20 && strlen($orid) < 50 && strlen($oros) < 50
-     && strlen($orjava) < 50 && strlen($orcountry) < 50)) {
-
-    $file = $logfiles . gmdate("Y-m");
-    $line = gmdate("Y-m-d H:i:s") . ";" . $orid . ";" . $orversion .
-       ";" . $oros . ";" . $orjava . ";" . $orcountry . "\n";
-
-    $fp = fopen($file, 'a');
-    if ($fp != FALSE) {
-       fwrite($fp, $line);
-       fclose($fp);
-    }
-}
-
-
-// Set HTTP content-type header
-// No charset allowed for 0.9.4
-//header("Content-type: text/plain; charset=utf-8");
-header("Content-type: text/plain");
-
-/*
- * Currently all old versions are handled manually.
- * Update checking was introduced in OpenRocket 0.9.4
- */
-$version = $_GET["version"];
-$updates = "";
-
-if (preg_match("/^0\.9\.(4|5pre|5|6pre)/",$version)) {
-  $updates = "Version: 0.9.6\n" .
-    "6: Aerodynamic computation updates\n" .
-    "5: Numerous bug fixes";
-}
-
-
-if (strlen($updates) == 0) {
-
-  // No updates available
-  header("HTTP/1.0 204 No Content");
-
-} else {
-
-  header("HTTP/1.0 200 OK");
-  echo $updates;
-
-}
-
-?>
\ No newline at end of file
diff --git a/html/contact.html b/html/contact.html
deleted file mode 100644 (file)
index 73be76d..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>OpenRocket&mdash;Support and contact information</title>
-  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"/>
-  <meta name="keywords" content="OpenRocket, model rocket, simulator, simulation, rocketry, support, bug report, feature request, contact information"/>
-  <link rel="stylesheet" type="text/css" href="layout.css"/>
-</head>
-
-<body class="page_contact">
-  <!--[if lte IE 6]>
-  <div id="iewarn">
-    You are using a browser that is <strong>8 years old!</strong>  
-    &nbsp;&nbsp;&nbsp;
-    In Internet-years that is <em>prehistoric!</em><br/>
-    For the sanity of all webmasterkind, 
-    <em>please <a href="http://www.mozilla.com/">upgrade</a></em>.  It's easy!
-  </div>
-  <![endif]-->
-
-  <h1>Support and contact information for OpenRocket</h1>
-
-  <div class="menucontainer">
-  <div class="menu">
-    <ul>
-      <li>OpenRocket</li>
-      <li><a href="index.html">Home</a></li>
-      <li><a href="features.html">Features</a></li>
-      <li><a href="screenshots.html">Screenshots</a></li>
-      <li><a href="download.html">Download</a></li>
-      <li><a href="documentation.html">Documentation</a></li>
-      <li><a href="contact.html">
-        Mailing lists<br/>
-        Support forums<br/>
-       Contact info</a></li>
-      <li><a href="report.html">
-        Report a bug<br/>
-       Request a feature</a></li>
-      <li><a href="license.html">License</a></li>
-    </ul>
-    <div class="logo">
-      <a href="http://sourceforge.net/projects/openrocket"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=260357&amp;type=12" width="120" height="30" alt="Get OpenRocket at SourceForge.net. Fast, secure and Free Open Source software downloads" /></a>
-    </div>
-  </div>
-  </div>
-
-  <div class="content">
-
-    <h2>Mailing lists</h2>
-
-    <p>If you would like to be notified when new versions of
-    OpenRocket are released, you can join the
-    <a href="https://lists.sourceforge.net/lists/listinfo/openrocket-announce"><tt>OpenRocket-announce</tt> mailing list</a>.  The
-    list is moderated and meant only for OpenRocket related
-    announcements.</p>
-
-    <p>When more developers join the project, a development mailing
-    list will be created as well.</p>
-
-    <p><strong>Unsubscribing</strong> from the lists can be performed
-    in the above links as well.  <em>Please do not send unsubscription
-    requests to the list.</em></p>
-
-
-    <h2>Support forums</h2>
-
-    <p>The main support channel for the usage of OpenRocket is the
-    support forums.  This way everybody can benefit from the answers
-    provided.</p>
-
-    <p><em><a href="http://apps.sourceforge.net/phpbb/openrocket/">Go
-    to the support forums &rarr;</a></em></p>
-
-
-    <h2 id="contact">Contact information</h2>
-
-    <p>OpenRocket is developed by Sampo Niskanen.  His contact
-    information can be found below.</p>
-
-    <p><em>If you would like to contribute something to OpenRocket, please
-    contact me!</em></p>
-
-    <p><strong><em>Support requests</em></strong> should be sent to
-    the <a href="http://apps.sourceforge.net/phpbb/openrocket/">support 
-    forums</a>.<br/>
-    <strong><em>Bug reports and feature requests</em></strong> should
-    be <a href="report.html">reported separately</a>.</p>
-
-    <p><strong>Email:</strong>  &nbsp;&nbsp;
-    <em>sam<span>po</span>.<span>niskanen</span><span>@i</span>ki.fi</em></p>
-
-    <p><strong>WWW:</strong>  &nbsp;&nbsp;
-    <a href="http://www.iki.fi/sampo.niskanen/" 
-    title="Home page of Sampo Niskanen"><em>http://www.iki.fi/sampo.niskanen/</em></a></p>
-
-  </div>
-
-  <div class="valid">
-    <p><a href="http://validator.w3.org/check/referer"><img src="valid-xhtml10.png" alt="Valid XHTML 1.0!"/></a>
-       <a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="vcss.gif" alt="Valid CSS!"/></a>
-    </p>
-  </div>
-
-<!-- Piwik -->
-<script type="text/javascript">
-var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
-document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
-</script><script type="text/javascript">
-piwik_action_name = '';
-piwik_idsite = 1;
-piwik_url = pkBaseURL + "piwik.php";
-piwik_log(piwik_action_name, piwik_idsite, piwik_url);
-</script>
-<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
-<!-- End Piwik Tag -->
-
-</body>
-</html>
-
diff --git a/html/documentation.html b/html/documentation.html
deleted file mode 100644 (file)
index d40766b..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>OpenRocket&mdash;Documentation</title>
-  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"/>
-  <meta name="keywords" content="OpenRocket, model rocket, simulator, simulation, rocketry, documentation"/>
-  <link rel="stylesheet" type="text/css" href="layout.css"/>
-</head>
-
-<body class="page_documentation">
-  <!--[if lte IE 6]>
-  <div id="iewarn">
-    You are using a browser that is <strong>8 years old!</strong>  
-    &nbsp;&nbsp;&nbsp;
-    In Internet-years that is <em>prehistoric!</em><br/>
-    For the sanity of all webmasterkind, 
-    <em>please <a href="http://www.mozilla.com/">upgrade</a></em>.  It's easy!
-  </div>
-  <![endif]-->
-
-  <h1>Documentation for OpenRocket</h1>
-
-  <div class="menucontainer">
-  <div class="menu">
-    <ul>
-      <li>OpenRocket</li>
-      <li><a href="index.html">Home</a></li>
-      <li><a href="features.html">Features</a></li>
-      <li><a href="screenshots.html">Screenshots</a></li>
-      <li><a href="download.html">Download</a></li>
-      <li><a href="documentation.html">Documentation</a></li>
-      <li><a href="contact.html">
-        Mailing lists<br/>
-        Support forums<br/>
-       Contact info</a></li>
-      <li><a href="report.html">
-        Report a bug<br/>
-       Request a feature</a></li>
-      <li><a href="license.html">License</a></li>
-    </ul>
-    <div class="logo">
-      <a href="http://sourceforge.net/projects/openrocket"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=260357&amp;type=12" width="120" height="30" alt="Get OpenRocket at SourceForge.net. Fast, secure and Free Open Source software downloads" /></a>
-    </div>
-  </div>
-  </div>
-
-  <div class="content">
-
-    <h2>User documentation</h2>
-
-    <p>No user's guide currently exists for OpenRocket.  There is a
-    <a href="http://apps.sourceforge.net/mediawiki/openrocket/index.php?title=User%27s_Guide">page on the wiki</a> for creating a User's guide.</p>
-    <p>If you would like to help, please extend it!</p>
-
-
-    <h2>Technical documentation</h2>
-
-    <p>OpenRocket was originally written as the Master's thesis of
-    Sampo Niskanen at Helsinki University of Technology.  The thesis
-    currently functions as the technical documentation, and will be
-    updated in the future to account for further enhancements.
-    The thesis is licensed under a 
-    <a rel="license" href="http://creativecommons.org/licenses/by-nd-nc/1.0/fi/deed.en">Creative Commons BY-NC-ND License</a>.</p>
-
-    <p class="right"><a rel="license" href="http://creativecommons.org/licenses/by-nd-nc/1.0/fi/deed.en"><img alt="Creative Commons BY-NC-ND License" src="http://i.creativecommons.org/l/by-nd-nc/1.0/fi/88x31.png" /></a></p>
-
-
-
-    <p><a href="thesis.pdf">Development of an Open Source model
-    rocket simulation software</a> (PDF, 1.3MB)</p>
-
-
-    <p class="quote"><strong>Table of contents:</strong></p>
-    <ol class="toc">
-      <li>1. Introduction</li>
-      <li>2. Basics of model rocket flight</li>
-      <li>3. Aerodynamic properties of model rockets</li>
-      <li>4. Flight simulation</li>
-      <li>5. The OpenRocket simulation software</li>
-      <li>6. Comparison with experimental data</li>
-      <li>7. Conclusion</li>
-    </ol>
-    <ol class="toc">
-      <li>A. Nose cone and transition geometries</li>
-      <li>B. Transonic wave drag of nose cones</li>
-      <li>C. Streamer drag coefficient estimation</li>
-    </ol>
-
-
-    <h2>Resources</h2>
-
-    <p>Below are resources that have been found useful in the analysis
-    of model rockets.  Many useful scientific aerodynamic articles and
-    documents are available at the invaluable
-    <a href="http://ntrs.nasa.gov/">NASA Technical Resources Server
-    (NTRS)</a>.</p>
-
-    <dl>
-      <dt><em>
-      <a href="http://www.apogeerockets.com/Education/downloads/barrowman_report.pdf">The Theoretical Prediction of the Center of
-      Pressure</a></em>, James and Judith Barrowman, 1966.</dt>
-      <dd>The original NARAM R&amp;D report explaining how to
-      calculate the CP position of a rocket.</dd>
-
-      <dt><em>
-      <a href="http://ntrs.nasa.gov/search.jsp?Ntk=all&amp;Ntx=mode+matchall&amp;Ntt=Barrowman+Practical+Calculation+of+the+Aerodynamic+Characteristics+of+Slender+Finned+Vehicles">The Practical Calculation of the Aerodynamic
-      Characteristics of Slender Finned Vehicles</a></em>, James
-      Barrowman, 1967.</dt>
-      <dd>The more in-depth and technical thesis, where Barrowman
-      presents methods for calculating the CP position of a rocket at
-      both subsonic and supersonic velocities and its other
-      aerodynamic properties.  Available on 
-      <a href="http://ntrs.nasa.gov/">NTRS</a>.</dd>
-
-      <dt><em>
-      <a href="http://projetosulfos.if.sc.usp.br/artigos/sentinel39-galejs.pdf">Wind instability&mdash;What Barrowman left out</a></em>,
-      Robert Galejs.</dt>
-      <dd>An extension to the Barrowman method to account for body
-      lift at large angles of attack.</dd>
-
-      <dt><em>Topics in Advanced Model Rocketry</em>, Mandell,
-      Caporaso, Bengen, MIT Press, 1973.</dt>
-      <dd>An excellent theoretical study on the flight of model
-      rockets.  Available as a reprint edition.</dd>
-
-      <dt><em>Fluid-dynamic drag</em>, Sighard Hoerner,
-      published by the author, 1965.</dt>
-      <dd>An excellent resource for all kinds of experimental data
-      regarding drag.  Available as a reprint edition.</dd>
-
-      <dt><em>Tactical missile design</em>, 2nd edition, Eugene
-      L. Fleeman, AIAA, 2006.</dt>
-      <dd>Useful approximation methods for estimating the aerodynamic
-      properties of rockets.</dd>
-
-      <dt><em><a href="http://www.aoe.vt.edu/~mason/Mason_f/CAtxtTop.html">Applied
-      Computational Aerodynamics</a></em>, William Mason.</dt>
-      <dd>An online textbook on computational aerodynamics.</dd>
-
-      <dt><em><a href="http://www.combatindex.com/mil_docs/pdf/hdbk/0700/MIL-HDBK-762.pdf">Design of aerodynamically stabilized free rockets</a></em>,
-      MIL-HDBK-762, US Army Missile Command, 1990.</dt>
-      <dd>Military handbook on the design of rockets, a good resource
-      for aerodynamic estimation methods.</dd>
-
-      <dt><em>
-      <a href="http://www.thrustcurve.org/">ThrustCurve.org</a></em>,
-      John Coker.</dt>
-      <dd>An excellent resource for model rocket motor thrust curves.</dd>
-
-      <dt><em>
-      <a href="http://ntrs.nasa.gov/search.jsp?Ntk=all&amp;Ntx=mode+matchall&amp;Ntt=NASA-TN-D-4013">Static stability investigation of a single-stage
-      sounding rocket at Mach numbers from 0.60 to 1.20</a></em>, James
-      Ferris, NASA-TN-D-4013, 1967.</dt>
-      <dt><em>
-      <a href="http://ntrs.nasa.gov/search.jsp?Ntk=all&amp;Ntx=mode+matchall&amp;Ntt=NASA-TN-D-4014">Static stability investigation of a sounding-rocket
-      vehicle at Mach numbers from 1.50 to 4.63</a></em>, Donald Babb and
-      Dennis Fuller, NASA-TN-D-4014, 1967.</dt>
-      <dd>Experimental data of a wind tunnel investigation of a
-      sounding rocket at subsonic, transonic and supersonic
-      velocities.  Available on
-      <a href="http://ntrs.nasa.gov/">NTRS</a>.</dd>
-
-     
-
-    </dl>
-
-
-  </div>
-
-  <div class="valid">
-    <p><a href="http://validator.w3.org/check/referer"><img src="valid-xhtml10.png" alt="Valid XHTML 1.0!"/></a>
-       <a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="vcss.gif" alt="Valid CSS!"/></a>
-    </p>
-  </div>
-
-<!-- Piwik -->
-<script type="text/javascript">
-var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
-document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
-</script><script type="text/javascript">
-piwik_action_name = '';
-piwik_idsite = 1;
-piwik_url = pkBaseURL + "piwik.php";
-piwik_log(piwik_action_name, piwik_idsite, piwik_url);
-</script>
-<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
-<!-- End Piwik Tag -->
-
-</body>
-</html>
-
diff --git a/html/download.html b/html/download.html
deleted file mode 100644 (file)
index 5e3d49c..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>OpenRocket&mdash;Download</title>
-  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"/>
-  <meta name="keywords" content="OpenRocket, model rocket, simulator, simulation, rocketry"/>
-  <link rel="stylesheet" type="text/css" href="layout.css"/>
-</head>
-
-<body class="page_download">
-  <!--[if lte IE 6]>
-  <div id="iewarn">
-    You are using a browser that is <strong>8 years old!</strong>  
-    &nbsp;&nbsp;&nbsp;
-    In Internet-years that is <em>prehistoric!</em><br/>
-    For the sanity of all webmasterkind, 
-    <em>please <a href="http://www.mozilla.com/">upgrade</a></em>.  It's easy!
-  </div>
-  <![endif]-->
-
-  <h1>Download OpenRocket</h1>
-
-  <div class="menucontainer">
-  <div class="menu">
-    <ul>
-      <li>OpenRocket</li>
-      <li><a href="index.html">Home</a></li>
-      <li><a href="features.html">Features</a></li>
-      <li><a href="screenshots.html">Screenshots</a></li>
-      <li><a href="download.html">Download</a></li>
-      <li><a href="documentation.html">Documentation</a></li>
-      <li><a href="contact.html">
-        Mailing lists<br/>
-        Support forums<br/>
-       Contact info</a></li>
-      <li><a href="report.html">
-        Report a bug<br/>
-       Request a feature</a></li>
-      <li><a href="license.html">License</a></li>
-    </ul>
-    <div class="logo">
-      <a href="http://sourceforge.net/projects/openrocket"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=260357&amp;type=12" width="120" height="30" alt="Get OpenRocket at SourceForge.net. Fast, secure and Free Open Source software downloads" /></a>
-    </div>
-  </div>
-  </div>
-
-  <div class="content">
-
-    <h2>Binary download</h2>
-
-    <p>The binary download below is the recommended package for general
-    use.  It is pre-packaged with motor thrust curves from
-    <a href="http://www.thrustcurve.org/">thrustcurve.org</a>.</p>
-
-    <p><em>OpenRocket requires <strong>Java version 6</strong> or
-    later.  The Sun JRE is recommended.</em></p>
-
-    <p class="download">
-    <a href="https://sourceforge.net/projects/openrocket/files/openrocket/OpenRocket-0.9.6.jar/download">Download OpenRocket 0.9.6</a></p>
-
-    <p>OpenRocket is still considered <strong>beta software</strong>.
-    If you encounter any problems, please 
-    <a href="report.html">report them</a> so they can be fixed!</p>
-
-    <p>OpenRocket can be started in graphical environments (such as
-    Windows) by double-clicking the package icon.  No installation is
-    required.  From the command line it can be started by</p>
-    <pre class="quote">$ java -jar OpenRocket-0.9.6.jar</pre>
-
-    <p>Older packages and source code are available from the
-    <a href="https://sourceforge.net/project/showfiles.php?group_id=260357&amp;package_id=319743">SourceForge repository</a>.</p>
-
-
-    <h2>Source code</h2>
-
-    <p><strong>Source packages</strong> for OpenRocket are available in the
-    <a href="https://sourceforge.net/project/showfiles.php?group_id=260357&amp;package_id=319743">SourceForge repository</a>.</p>
-
-    <p>Alternatively, the most recent development version can be 
-    obtained from the
-    <a href="http://openrocket.svn.sourceforge.net/viewvc/openrocket/">SVN 
-    repository</a>.  It can be retrieved simply using the command</p>
-    <pre class="quote">$ svn co https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk OpenRocket</pre>
-    <p>The above URL may be used to connect to the repository with
-    other Subversion clients as well.</p>
-
-
-
-  </div>
-
-  <div class="valid">
-    <p><a href="http://validator.w3.org/check/referer"><img src="valid-xhtml10.png" alt="Valid XHTML 1.0!"/></a>
-       <a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="vcss.gif" alt="Valid CSS!"/></a>
-    </p>
-  </div>
-
-<!-- Piwik -->
-<script type="text/javascript">
-var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
-document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
-</script><script type="text/javascript">
-piwik_action_name = '';
-piwik_idsite = 1;
-piwik_url = pkBaseURL + "piwik.php";
-piwik_log(piwik_action_name, piwik_idsite, piwik_url);
-</script>
-<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
-<!-- End Piwik Tag -->
-
-</body>
-</html>
-
diff --git a/html/favicon.ico b/html/favicon.ico
deleted file mode 100644 (file)
index 09c23f8..0000000
Binary files a/html/favicon.ico and /dev/null differ
diff --git a/html/features.html b/html/features.html
deleted file mode 100644 (file)
index 92bd16c..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>OpenRocket&mdash;Features</title>
-  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"/>
-  <meta name="keywords" content="OpenRocket, model rocket, simulator, simulation, rocketry, features"/>
-  <link rel="stylesheet" type="text/css" href="layout.css"/>
-</head>
-
-<body class="page_features">
-  <!--[if lte IE 6]>
-  <div id="iewarn">
-    You are using a browser that is <strong>8 years old!</strong>  
-    &nbsp;&nbsp;&nbsp;
-    In Internet-years that is <em>prehistoric!</em><br/>
-    For the sanity of all webmasterkind, 
-    <em>please <a href="http://www.mozilla.com/">upgrade</a></em>.  It's easy!
-  </div>
-  <![endif]-->
-
-  <h1>Features of OpenRocket</h1>
-
-  <div class="menucontainer">
-  <div class="menu">
-    <ul>
-      <li>OpenRocket</li>
-      <li><a href="index.html">Home</a></li>
-      <li><a href="features.html">Features</a></li>
-      <li><a href="screenshots.html">Screenshots</a></li>
-      <li><a href="download.html">Download</a></li>
-      <li><a href="documentation.html">Documentation</a></li>
-      <li><a href="contact.html">
-        Mailing lists<br/>
-        Support forums<br/>
-       Contact info</a></li>
-      <li><a href="report.html">
-        Report a bug<br/>
-       Request a feature</a></li>
-      <li><a href="license.html">License</a></li>
-    </ul>
-    <div class="logo">
-      <a href="http://sourceforge.net/projects/openrocket"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=260357&amp;type=12" width="120" height="30" alt="Get OpenRocket at SourceForge.net. Fast, secure and Free Open Source software downloads" /></a>
-    </div>
-  </div>
-  </div>
-
-  <div class="content">
-
-    <h2>Current features</h2>
-
-    <h3>General</h3>
-
-    <ul>
-      <li><strong>Fully cross-platform</strong>, written in Java</li>
-      <li><strong>Fully documented</strong> <a href="documentation.html">simulation
-      methods</a></li>
-      <li><strong>Open Source</strong>, source code available under the
-        <a href="license.html">GNU GPL</a></li>
-    </ul>
-
-    <h3>User interface</h3>
-    <ul>
-      <li><a href="screenshots.html">Easy-to-use user interface</a> for
-        rocket design</li>
-      <li><strong>Zoomable schematic view</strong> of rocket from the side or rear</li>
-      <li>Rocket rotation around center axis</li>
-      <li><strong>Real-time view of CG and CP</strong> position</li>
-      <li><strong>Real-time flight altitude, velocity and
-        acceleration</strong> information from a continuous simulation
-       performed in the background</li> 
-    </ul>
-
-    <h3>Design</h3>
-
-    <ul>
-      <li>A multitude of available components to
-      choose from</li>
-      <li><strong>Trapezoidal</strong>, <strong>elliptical</strong>
-      and <strong>free-form fins</strong> supported</li> 
-      <li>Support for <strong>canted fins</strong> (roll
-      stabilization)</li>
-      <li><strong>Staging</strong> and <strong>clustering</strong> support</li>
-      <li>Automatic calculation of component mass and CG based on
-        shape and density</li>
-      <li>Ability to <strong>override mass and CG</strong> of
-        components or stages separately</li>
-    </ul>
-
-    <h3>Simulation and analysis</h3>
-
-    <ul>
-      <li>Full <strong>six degree of freedom</strong> simulation</li>
-      <li>Rocket stability computed using <strong>extended Barrowman
-        method</strong></li>
-      <li>Realistic wind modeling</li>
-      <li>Analysis of the <strong>effect of separate
-      components</strong> on the stability, drag and roll
-      characteristics of the rocket</li>
-      <li><strong>Fully configurable plotting</strong>, with
-      various preset configurations</li>
-      <li><strong>Simulation listeners</strong> allowing custom-made
-      code to interact with the rocket during flight simulation</li>
-    </ul>
-
-
-    <h2 id="future">Planned future features</h2>
-
-    <p>OpenRocket is under constant work, and anybody can help make
-    OpenRocket an even better simulator!  Here are a few features that
-    have been planned...</p>
-
-    <ul>
-      <li>Aerodynamic computation using 
-      <acronym title="Computational Fluid Dynamics">CFD</acronym>
-      <a href="contact.html" class="help">(help needed!)</a></li>
-      <li>Better support for supersonic simulation
-      <a href="contact.html" class="help">(help needed!)</a></li>
-      <li>3D view of the rocket design 
-      <a href="contact.html" class="help">(help needed!)</a></li>
-      <li>Saving figures and exporting simulation data</li>
-      <li>Importing and plotting actual flight data from altimeters</li>
-      <li>Importing new motor thrust curves</li>
-      <li>Support for ready-made component databases</li>
-      <li>Customized support for hybrid rocket motors and water
-      rockets</li>
-      <li>Rocket flight animation</li>
-      <li>A "wizard" for creating new rocket designs</li>
-      <li>. . .</li>
-    </ul>
-
-    <p>If you want to help make OpenRocket the best rocket simulator,
-    don't hesitate to <a href="contact.html">contact us</a>!</p>
-
-  </div>
-
-  <div class="valid">
-    <p><a href="http://validator.w3.org/check/referer"><img src="valid-xhtml10.png" alt="Valid XHTML 1.0!"/></a>
-       <a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="vcss.gif" alt="Valid CSS!"/></a>
-    </p>
-  </div>
-
-<!-- Piwik -->
-<script type="text/javascript">
-var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
-document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
-</script><script type="text/javascript">
-piwik_action_name = '';
-piwik_idsite = 1;
-piwik_url = pkBaseURL + "piwik.php";
-piwik_log(piwik_action_name, piwik_idsite, piwik_url);
-</script>
-<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
-<!-- End Piwik Tag -->
-
-</body>
-</html>
-
diff --git a/html/index.html b/html/index.html
deleted file mode 100644 (file)
index 7be48a7..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>OpenRocket</title>
-  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"/>
-  <meta name="keywords" content="OpenRocket, model rocket, simulator, simulation, rocketry"/>
-  <link rel="stylesheet" type="text/css" href="layout.css"/>
-</head>
-
-<body class="page_index">
-  <!--[if lte IE 6]>
-  <div id="iewarn">
-    You are using a browser that is <strong>8 years old!</strong>  
-    &nbsp;&nbsp;&nbsp;
-    In Internet-years that is <em>prehistoric!</em><br/>
-    For the sanity of all webmasterkind, 
-    <em>please <a href="http://www.mozilla.com/">upgrade</a></em>.  It's easy!
-  </div>
-  <![endif]-->
-
-  <h1>OpenRocket &mdash; an Open Source model rocket simulator</h1>
-
-  <div class="menucontainer">
-    <div class="menu">
-      <ul>
-        <li>OpenRocket</li>
-        <li><a href="index.html">Home</a></li>
-        <li><a href="features.html">Features</a></li>
-        <li><a href="screenshots.html">Screenshots</a></li>
-        <li><a href="download.html">Download</a></li>
-        <li><a href="documentation.html">Documentation</a></li>
-        <li><a href="contact.html">
-          Mailing lists<br/>
-          Support forums<br/>
-         Contact info</a></li>
-        <li><a href="report.html">
-          Report a bug<br/>
-         Request a feature</a></li>
-        <li><a href="license.html">License</a></li>
-      </ul>
-      <div class="logo">
-        <a href="http://sourceforge.net/projects/openrocket"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=260357&amp;type=12" width="120" height="30" alt="Get OpenRocket at SourceForge.net. Fast, secure and Free Open Source software downloads" /></a>
-      </div>
-    </div>
-  </div>
-
-  <div class="content">
-
-    <h2>Introduction</h2>
-
-    <p><strong>OpenRocket</strong> is a Free, fully featured model
-      rocket simulator written in Java.  It can be used to design and
-      simulate rockets before actually building and flying them.
-    </p>
-    <p>OpenRocket features a full six-degree-of-freedom simulation,
-      realistic wind modeling, a multitude of different components
-      including free-form fins and canted fins, clustering and
-      staging.  Read more about its <a href="features.html">features</a>.
-    </p>
-    <p>Best of all, OpenRocket is Open Source&mdash;its source code is
-      freely available to study and extend.  Anybody wishing to
-      contribute to the project can do so according to the
-      <a href="license.html">GNU GPL</a>.  Simply 
-      <a href="download.html">download</a> the source code
-      and start hacking, or <a href="download.html">get the ready
-      package</a> to begin designing and simulating.
-    </p>
-    <p>OpenRocket is still considered to be <strong>beta
-      software</strong>&mdash;there will still be bugs and occasional
-      problems.  If you encounter problems, please
-      <a href="contact.html">report them</a> so they can be fixed.
-    </p>
-
-    <div>
-      <div class="smallshot"><a href="screenshots.html">
-        <img src="shots-small/main.jpg" alt="Main window"/><br/>
-        Main window
-      </a></div>
-      <div class="smallshot"><a href="screenshots.html">
-        <img src="shots-small/dialog-analysis.jpg" alt="Analysis dialog"/><br/>
-        Analysis dialog
-      </a></div>
-      <div class="smallshot last"><a href="screenshots.html">
-        <img src="shots-small/dialog-plot.jpg" alt="Simulation plot"/><br/>
-        Simulation plot
-      </a></div>
-    </div>
-    <div class="clear"></div>
-
-
-    <h2>News</h2>
-
-    <p><strong>17.2.2010:</strong> Version 0.9.6 is
-      <a href="download.html">released</a>!</p>
-
-    <p>This release updates the aerodynamic calculation methods to be
-      more in line with the Barrowman method and enhances the simulation
-      time step selection, in addition to fixing numerous bugs.</p>
-
-    <p><strong>28.11.2009:</strong> Version 0.9.5 is
-      <a href="download.html">released</a>!</p>
-
-    <p>This release <strong>fixes a serious bug in 0.9.4</strong> that
-      prevented adding a tube coupler and centering ring to the same
-      body tube, in addition to a few smaller additions.  Users of
-      0.9.4 should upgrade immediately!</p>
-
-    <p><strong>24.11.2009:</strong> Version 0.9.4 is
-      <a href="download.html">released</a>!</p>
-
-    <p>This version adds support for through-the-wall fin tabs,
-    attaching components to coupler tubes, material editing, automatic
-    update checking, in addition to fixing numerous bugs.</p>
-
-    <p><strong>1.9.2009:</strong> Version 0.9.3 is
-      <a href="download.html">released</a>!</p>
-
-    <p>This version includes lots of bug fixes and new features including
-    data exporting, showing flight events in plots, example rocket designs,
-     splitting clustered inner tubes and automated bug reporting.</p>
-
-    <p><strong>13.7.2009:</strong> Version 0.9.2 is
-      <a href="download.html">released</a>!</p>
-
-    <p>This version includes <strong>bug fixes for imperial unit 
-    conversions</strong> and UI improvements for motor selection.
-    <em>All users of imperial units should upgrade!</em></p>
-
-    <p><strong>9.6.2009:</strong> The 
-    <a href="documentation.html">Master's thesis</a> for which OpenRocket
-    was written for is now available!</p>
-
-    <p>At the same time version 0.9.1 was
-    <a href="download.html">released</a>.  This release fixes various
-    file handling bugs and adds small UI enhancements.</p>
-
-    <p><strong>24.5.2009:</strong> First version 0.9.0 
-      <a href="download.html">released</a>!</p>
-
-  </div>
-
-  <div class="valid">
-    <p><a href="http://validator.w3.org/check/referer"><img src="valid-xhtml10.png" alt="Valid XHTML 1.0!"/></a>
-       <a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="vcss.gif" alt="Valid CSS!"/></a>
-    </p>
-  </div>
-
-<!-- Piwik -->
-<script type="text/javascript">
-var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
-document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
-</script><script type="text/javascript">
-piwik_action_name = '';
-piwik_idsite = 1;
-piwik_url = pkBaseURL + "piwik.php";
-piwik_log(piwik_action_name, piwik_idsite, piwik_url);
-</script>
-<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
-<!-- End Piwik Tag -->
-
-</body>
-</html>
-
diff --git a/html/layout.css b/html/layout.css
deleted file mode 100644 (file)
index d1e3de1..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-
-body {
-  margin: 0;
-  padding: 0;
-}
-
-#iewarn {
-  width: 100%;
-  background-color: #fa0;
-  text-align: center;
-  padding: 1em 2em;
-  border-top: solid 1px black;
-  border-bottom: solid 1px black;
-}
-
-
-h1 {
-  margin: 0.75em 2em 1.25em 2em;
-}
-
-h2 {
-  margin-top: 1.5em;
-  border-bottom: dotted 2px #f99;
-}
-
-a {
-  text-decoration: none;
-  color: #00F;
-}
-a:hover {
-  color: #55c;
-}
-
-
-div.menucontainer {
-  position: relative;
-}
-
-div.menu {
-  position: absolute;
-  left: 1.5em;
-  width: 12em;
-  margin: 0;
-  padding: 0 0;
-  background-color: #ccc;
-}
-div.menu ul {
-  position: relative;
-  left: -2px;
-  top: -2px;
-  right: 2px;
-  bottom: 2px;
-  background-color: #89cbe0;
-  border: solid 1px black;
-  list-style: none;
-  margin: 0;
-  padding: 0 0;
-}
-
-div.menu li {
-  display: block;
-  left: 0;
-  right: 0;
-  margin: 0;
-  text-align: center;
-}
-
-div.menu li:first-child {
-  padding: 0.5em 0;
-  font-size: 160%;
-}
-
-div.menu li+li {
-  border-top: dashed 1px black;
-}
-
-div.menu li a {
-  display: block;
-  left: 0;
-  right: 0;
-  font-style: normal;
-  text-decoration: none;
-  color: #00d;
-  padding: 0.75em 1em;
-  outline: none;
-}
-div.menu li a:focus {
-  background-color: #8fd5eb;
-}
-
-div.menu li a:hover {
-  background-color: #ee9494;
-}
-
-div.menu div.logo {
-  position: absolute;
-  top: 100%;
-  left: -2px;
-  margin-top: 15px;
-  width: 100%;
-}
-
-div.menu div.logo img {
-  display: block;
-  margin: 0 auto;
-}
-
-
-.page_index div.menu a[href="index.html"],
-.page_features div.menu a[href="features.html"],
-.page_screenshots div.menu a[href="screenshots.html"],
-.page_download div.menu a[href="download.html"],
-.page_documentation div.menu a[href="documentation.html"],
-.page_contact div.menu a[href="contact.html"],
-.page_report div.menu a[href="report.html"],
-.page_license div.menu a[href="license.html"] {
-  font-weight: bold;
-  font-size: 110%;
-}
-
-
-.content {
-  margin: 0em 2em 2em 15.5em;
-  min-height: 27em;
-}
-
-img {
-  border: 0px;
-  outline: none;
-  font-size: 70%;
-}
-
-.smallshot {
-  float: left;
-  margin-top:2em;
-  text-align: center;
-  font-style: italic;
-  margin-right: 2em;
-}
-.smallshot.last {
-  margin-right: 0;
-}
-.clear {
-  clear:both;
-}
-
-
-.smallshotconst {
-  float: left;
-  width: 270px;
-  height: 220px;
-  margin: 1em 1em;
-  text-align: center;
-  font-style: italic;
-}
-.smallshotconst em {
-  font-style: normal;
-}
-
-
-
-a.help {
-  margin-left: 1em;
-  font-size: smaller;
-  font-style: italic;
-}
-
-
-pre.quote {
-  margin: 2em;
-  padding: 1em;
-  border: dashed 1px #888;
-  background-color: #ddd;
-}
-
-p.quote {
-  margin: 2em;
-}
-
-hr {
-  margin: 2em 0em;
-}
-
-.right {
-  float: right;
-  margin: 0;
-}
-
-li {
-  margin-top: 0.5em;
-}
-
-
-p.download {
-  margin: 2em;
-}
-p.download a {
-  font-size: 140%;
-  font-style: italic;
-  padding: 0.5em;
-  border: dashed 1px red;
-  background-color: #89cbe0;
-  outline: none;
-}
-p.download a:hover {
-  color: #00F;
-  background-color: #ee9494;
-}
-p.download a:focus {
-  background-color: #8fd5eb;
-}
-
-div.valid {
-  float: right;
-  margin-right: 2em;
-}
-
-
-
-ol.toc {
-  list-style-type: none;
-}
-
-dt+dt {
-  margin-top: 0.5em;
-}
-dd {
-  margin-top: 0.2em;
-  margin-bottom: 1.4em;
-}
diff --git a/html/license.html b/html/license.html
deleted file mode 100644 (file)
index 9066611..0000000
+++ /dev/null
@@ -1,782 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>OpenRocket&mdash;License</title>
-  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"/>
-  <meta name="keywords" content="OpenRocket, model rocket, simulator, simulation, rocketry, license"/>
-  <link rel="stylesheet" type="text/css" href="layout.css"/>
-</head>
-
-<body class="page_license">
-  <!--[if lte IE 6]>
-  <div id="iewarn">
-    You are using a browser that is <strong>8 years old!</strong>  
-    &nbsp;&nbsp;&nbsp;
-    In Internet-years that is <em>prehistoric!</em><br/>
-    For the sanity of all webmasterkind, 
-    <em>please <a href="http://www.mozilla.com/">upgrade</a></em>.  It's easy!
-  </div>
-  <![endif]-->
-
-  <h1>OpenRocket license</h1>
-
-  <div class="menucontainer">
-  <div class="menu">
-    <ul>
-      <li>OpenRocket</li>
-      <li><a href="index.html">Home</a></li>
-      <li><a href="features.html">Features</a></li>
-      <li><a href="screenshots.html">Screenshots</a></li>
-      <li><a href="download.html">Download</a></li>
-      <li><a href="documentation.html">Documentation</a></li>
-      <li><a href="contact.html">
-        Mailing lists<br/>
-        Support forums<br/>
-       Contact info</a></li>
-      <li><a href="report.html">
-        Report a bug<br/>
-       Request a feature</a></li>
-      <li><a href="license.html">License</a></li>
-    </ul>
-    <div class="logo">
-      <a href="http://sourceforge.net/projects/openrocket"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=260357&amp;type=12" width="120" height="30" alt="Get OpenRocket at SourceForge.net. Fast, secure and Free Open Source software downloads" /></a>
-    </div>
-  </div>
-  </div>
-
-  <div class="content">
-
-    <p><em>The license text is available also in the simulator under
-    <strong>Help&nbsp;&rarr;&nbsp;License</strong> and in the file
-    <tt>LICENSE.TXT</tt>.</em></p>
-
-    <hr/>
-
-    <pre>
-OpenRocket - A model rocket simulator
-
-Copyright (C) 2007-2009 Sampo Niskanen
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3 of the License, or (at
-your option) any later version.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License (below) for more details.
-
-
-Additional permission under GNU GPL version 3 section 7:
-
-The licensors grant additional permission to package this Program, or
-any covered work, along with any non-compilable data files (such as
-thrust curves or component databases) and convey the resulting work.
-
-
-------------------------------------------------------------------------
-
-
-                   GNU GENERAL PUBLIC LICENSE
-                      Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                           Preamble
-
-  The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
-  The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works.  By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.  We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors.  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
-  To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights.  Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received.  You must make sure that they, too, receive
-or can get the source code.  And you must show them these terms so they
-know their rights.
-
-  Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
-  For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software.  For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
-  Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so.  This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software.  The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable.  Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products.  If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
-  Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary.  To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                      TERMS AND CONDITIONS
-
-  0. Definitions.
-
-  "This License" refers to version 3 of the GNU General Public License.
-
-  "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-  "The Program" refers to any copyrightable work licensed under this
-License.  Each licensee is addressed as "you".  "Licensees" and
-"recipients" may be individuals or organizations.
-
-  To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy.  The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
-  A "covered work" means either the unmodified Program or a work based
-on the Program.
-
-  To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy.  Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
-  To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies.  Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
-  An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License.  If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
-  1. Source Code.
-
-  The "source code" for a work means the preferred form of the work
-for making modifications to it.  "Object code" means any non-source
-form of a work.
-
-  A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
-  The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form.  A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
-  The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities.  However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work.  For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
-  The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
-  The Corresponding Source for a work in source code form is that
-same work.
-
-  2. Basic Permissions.
-
-  All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met.  This License explicitly affirms your unlimited
-permission to run the unmodified Program.  The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work.  This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
-  You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force.  You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright.  Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
-  Conveying under any other circumstances is permitted solely under
-the conditions stated below.  Sublicensing is not allowed; section 10
-makes it unnecessary.
-
-  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-  No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
-  When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
-  4. Conveying Verbatim Copies.
-
-  You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
-  You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
-  5. Conveying Modified Source Versions.
-
-  You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
-    a) The work must carry prominent notices stating that you modified
-    it, and giving a relevant date.
-
-    b) The work must carry prominent notices stating that it is
-    released under this License and any conditions added under section
-    7.  This requirement modifies the requirement in section 4 to
-    "keep intact all notices".
-
-    c) You must license the entire work, as a whole, under this
-    License to anyone who comes into possession of a copy.  This
-    License will therefore apply, along with any applicable section 7
-    additional terms, to the whole of the work, and all its parts,
-    regardless of how they are packaged.  This License gives no
-    permission to license the work in any other way, but it does not
-    invalidate such permission if you have separately received it.
-
-    d) If the work has interactive user interfaces, each must display
-    Appropriate Legal Notices; however, if the Program has interactive
-    interfaces that do not display Appropriate Legal Notices, your
-    work need not make them do so.
-
-  A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit.  Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
-  6. Conveying Non-Source Forms.
-
-  You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
-    a) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by the
-    Corresponding Source fixed on a durable physical medium
-    customarily used for software interchange.
-
-    b) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by a
-    written offer, valid for at least three years and valid for as
-    long as you offer spare parts or customer support for that product
-    model, to give anyone who possesses the object code either (1) a
-    copy of the Corresponding Source for all the software in the
-    product that is covered by this License, on a durable physical
-    medium customarily used for software interchange, for a price no
-    more than your reasonable cost of physically performing this
-    conveying of source, or (2) access to copy the
-    Corresponding Source from a network server at no charge.
-
-    c) Convey individual copies of the object code with a copy of the
-    written offer to provide the Corresponding Source.  This
-    alternative is allowed only occasionally and noncommercially, and
-    only if you received the object code with such an offer, in accord
-    with subsection 6b.
-
-    d) Convey the object code by offering access from a designated
-    place (gratis or for a charge), and offer equivalent access to the
-    Corresponding Source in the same way through the same place at no
-    further charge.  You need not require recipients to copy the
-    Corresponding Source along with the object code.  If the place to
-    copy the object code is a network server, the Corresponding Source
-    may be on a different server (operated by you or a third party)
-    that supports equivalent copying facilities, provided you maintain
-    clear directions next to the object code saying where to find the
-    Corresponding Source.  Regardless of what server hosts the
-    Corresponding Source, you remain obligated to ensure that it is
-    available for as long as needed to satisfy these requirements.
-
-    e) Convey the object code using peer-to-peer transmission, provided
-    you inform other peers where the object code and Corresponding
-    Source of the work are being offered to the general public at no
-    charge under subsection 6d.
-
-  A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
-  A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling.  In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage.  For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product.  A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
-  "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source.  The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
-  If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information.  But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
-  The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed.  Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
-  Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
-  7. Additional Terms.
-
-  "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law.  If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
-  When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it.  (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.)  You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
-  Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
-    a) Disclaiming warranty or limiting liability differently from the
-    terms of sections 15 and 16 of this License; or
-
-    b) Requiring preservation of specified reasonable legal notices or
-    author attributions in that material or in the Appropriate Legal
-    Notices displayed by works containing it; or
-
-    c) Prohibiting misrepresentation of the origin of that material, or
-    requiring that modified versions of such material be marked in
-    reasonable ways as different from the original version; or
-
-    d) Limiting the use for publicity purposes of names of licensors or
-    authors of the material; or
-
-    e) Declining to grant rights under trademark law for use of some
-    trade names, trademarks, or service marks; or
-
-    f) Requiring indemnification of licensors and authors of that
-    material by anyone who conveys the material (or modified versions of
-    it) with contractual assumptions of liability to the recipient, for
-    any liability that these contractual assumptions directly impose on
-    those licensors and authors.
-
-  All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10.  If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term.  If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
-  If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
-  Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
-  8. Termination.
-
-  You may not propagate or modify a covered work except as expressly
-provided under this License.  Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
-  However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
-  Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
-  Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License.  If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
-  9. Acceptance Not Required for Having Copies.
-
-  You are not required to accept this License in order to receive or
-run a copy of the Program.  Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance.  However,
-nothing other than this License grants you permission to propagate or
-modify any covered work.  These actions infringe copyright if you do
-not accept this License.  Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
-  10. Automatic Licensing of Downstream Recipients.
-
-  Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License.  You are not responsible
-for enforcing compliance by third parties with this License.
-
-  An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations.  If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
-  You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License.  For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
-  11. Patents.
-
-  A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based.  The
-work thus licensed is called the contributor's "contributor version".
-
-  A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version.  For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
-  Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
-  In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement).  To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
-  If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients.  "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-  
-  If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
-  A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License.  You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
-  Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
-  12. No Surrender of Others' Freedom.
-
-  If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all.  For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
-  13. Use with the GNU Affero General Public License.
-
-  Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work.  The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
-  14. Revised Versions of this License.
-
-  The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-  Each version is given a distinguishing version number.  If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation.  If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
-  If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
-  Later license versions may give you additional or different
-permissions.  However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
-  15. Disclaimer of Warranty.
-
-  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. Limitation of Liability.
-
-  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
-  17. Interpretation of Sections 15 and 16.
-
-  If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
-                    END OF TERMS AND CONDITIONS
-
-           How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    &lt;one line to give the program's name and a brief idea of what it does.&gt;
-    Copyright (C) &lt;year&gt;  &lt;name of author&gt;
-
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.
-
-Also add information on how to contact you by electronic and paper mail.
-
-  If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
-    &lt;program&gt;  Copyright (C) &lt;year&gt;  &lt;name of author&gt;
-    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
-  You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-&lt;http://www.gnu.org/licenses/&gt;.
-
-  The GNU General Public License does not permit incorporating your program
-into proprietary programs.  If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.  But first, please read
-&lt;http://www.gnu.org/philosophy/why-not-lgpl.html&gt;.
-    </pre>
-
-    <hr/>
-
-  </div>
-
-  <div class="valid">
-    <p><a href="http://validator.w3.org/check/referer"><img src="valid-xhtml10.png" alt="Valid XHTML 1.0!"/></a>
-       <a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="vcss.gif" alt="Valid CSS!"/></a>
-    </p>
-  </div>
-
-<!-- Piwik -->
-<script type="text/javascript">
-var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
-document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
-</script><script type="text/javascript">
-piwik_action_name = '';
-piwik_idsite = 1;
-piwik_url = pkBaseURL + "piwik.php";
-piwik_log(piwik_action_name, piwik_idsite, piwik_url);
-</script>
-<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
-<!-- End Piwik Tag -->
-
-</body>
-</html>
-
diff --git a/html/report.html b/html/report.html
deleted file mode 100644 (file)
index 1e5be1d..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>OpenRocket&mdash;Support and contact information</title>
-  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"/>
-  <meta name="keywords" content="OpenRocket, model rocket, simulator, simulation, rocketry, support, bug report, feature request, contact information"/>
-  <link rel="stylesheet" type="text/css" href="layout.css"/>
-</head>
-
-<body class="page_report">
-  <!--[if lte IE 6]>
-  <div id="iewarn">
-    You are using a browser that is <strong>8 years old!</strong>  
-    &nbsp;&nbsp;&nbsp;
-    In Internet-years that is <em>prehistoric!</em><br/>
-    For the sanity of all webmasterkind, 
-    <em>please <a href="http://www.mozilla.com/">upgrade</a></em>.  It's easy!
-  </div>
-  <![endif]-->
-
-  <h1>Support and contact information for OpenRocket</h1>
-
-  <div class="menucontainer">
-  <div class="menu">
-    <ul>
-      <li>OpenRocket</li>
-      <li><a href="index.html">Home</a></li>
-      <li><a href="features.html">Features</a></li>
-      <li><a href="screenshots.html">Screenshots</a></li>
-      <li><a href="download.html">Download</a></li>
-      <li><a href="documentation.html">Documentation</a></li>
-      <li><a href="contact.html">
-        Mailing lists<br/>
-        Support forums<br/>
-       Contact info</a></li>
-      <li><a href="report.html">
-        Report a bug<br/>
-       Request a feature</a></li>
-      <li><a href="license.html">License</a></li>
-    </ul>
-    <div class="logo">
-      <a href="http://sourceforge.net/projects/openrocket"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=260357&amp;type=12" width="120" height="30" alt="Get OpenRocket at SourceForge.net. Fast, secure and Free Open Source software downloads" /></a>
-    </div>
-  </div>
-  </div>
-
-  <div class="content">
-
-    <h2>Bug reports</h2>
-
-    <p>If you encounter problems with OpenRocket, please report them
-    so they can be fixed in future versions.  Please follow the
-    instructions below to report a bug:</p>
-
-    <ul>
-      <li>Search the bug repository to see if the bug has already been
-      reported.  If it is, please add extra information to that bug
-      report:
-      <form action="https://sourceforge.net/search/index.php" method="get">
-        <p><input type="hidden" name="group_id" value="260357" />
-       <input type="hidden" name="type_of_search" value="artifact"/>
-<!--    <input type="hidden" name="group_artifact_id" value="1127606" /> -->
-<!--    <input type="hidden" name="artifact_group" value="Bug" /> -->
-        <input type="hidden" name="search_summary" value="1" />
-        <input type="hidden" name="search_details" value="1" />
-        <input type="hidden" name="search_comments" value="1" />
-
-       <input type="text" name="all_words" value="" />
-       <input type="submit" name="form_submit" value="Search" /></p>
-      </form>
-      </li>
-
-      <li>Report the bug using the 
-      <a href="https://sourceforge.net/tracker/?func=add&amp;group_id=260357&amp;atid=1127606">bug
-      tracker</a>.  Follow the instructions provided to fill in the 
-      report.</li>
-
-      <li>If you are unsure about some issue, you can discuss it in
-      the appropriate 
-      <a href="http://apps.sourceforge.net/phpbb/openrocket/">support 
-      forum</a>.</li>
-    </ul>
-
-    <h2>Feature requests</h2>
-
-    <p>Good ideas on how to make OpenRocket better are always welcome!
-    The features will be implemented as there is time.  However, no
-    promises are made of when or whether some feature will be
-    provided.</p>
-
-    <p>If you would like to implement some feature yourself, patches
-    are sincerely welcome.  Please <a href="contact.html#contact">contact
-    me</a> in order to coordinate our efforts.</p>
-
-    <p>When requesting a feature:</p>
-
-    <ul>
-      <li>Check that the feature is not already in the
-      <a href="features.html#future">planned future features</a> or
-      the <a href="https://sourceforge.net/tracker/?group_id=260357&amp;atid=1127606&amp;artgroup=899287">enhancement requests</a>.</li>
-      <li>Send the request to the <a href="https://sourceforge.net/tracker/?func=add&amp;group_id=260357&amp;atid=1127606">bug tracker</a> as an
-      enhancement request.  Please send multiple enhancements as
-      individual items.</li>
-    </ul>
-
-  </div>
-
-  <div class="valid">
-    <p><a href="http://validator.w3.org/check/referer"><img src="valid-xhtml10.png" alt="Valid XHTML 1.0!"/></a>
-       <a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="vcss.gif" alt="Valid CSS!"/></a>
-    </p>
-  </div>
-
-<!-- Piwik -->
-<script type="text/javascript">
-var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
-document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
-</script><script type="text/javascript">
-piwik_action_name = '';
-piwik_idsite = 1;
-piwik_url = pkBaseURL + "piwik.php";
-piwik_log(piwik_action_name, piwik_idsite, piwik_url);
-</script>
-<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
-<!-- End Piwik Tag -->
-
-</body>
-</html>
-
diff --git a/html/robots.txt b/html/robots.txt
deleted file mode 100644 (file)
index 91d9f61..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-
-User-agent: *
-Disallow:   /actions/
-
diff --git a/html/screenshots.html b/html/screenshots.html
deleted file mode 100644 (file)
index d424922..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>OpenRocket&mdash;Screenshots</title>
-  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"/>
-  <meta name="keywords" content="OpenRocket, model rocket, simulator, simulation, rocketry, screenshots"/>
-  <link rel="stylesheet" type="text/css" href="layout.css"/>
-</head>
-
-<body class="page_screenshots">
-  <!--[if lte IE 6]>
-  <div id="iewarn">
-    You are using a browser that is <strong>8 years old!</strong>  
-    &nbsp;&nbsp;&nbsp;
-    In Internet-years that is <em>prehistoric!</em><br/>
-    For the sanity of all webmasterkind, 
-    <em>please <a href="http://www.mozilla.com/">upgrade</a></em>.  It's easy!
-  </div>
-  <![endif]-->
-
-  <h1>Screenshots of OpenRocket</h1>
-
-  <div class="menucontainer">
-  <div class="menu">
-    <ul>
-      <li>OpenRocket</li>
-      <li><a href="index.html">Home</a></li>
-      <li><a href="features.html">Features</a></li>
-      <li><a href="screenshots.html">Screenshots</a></li>
-      <li><a href="download.html">Download</a></li>
-      <li><a href="documentation.html">Documentation</a></li>
-      <li><a href="contact.html">
-        Mailing lists<br/>
-        Support forums<br/>
-       Contact info</a></li>
-      <li><a href="report.html">
-        Report a bug<br/>
-       Request a feature</a></li>
-      <li><a href="license.html">License</a></li>
-    </ul>
-    <div class="logo">
-      <a href="http://sourceforge.net/projects/openrocket"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=260357&amp;type=12" width="120" height="30" alt="Get OpenRocket at SourceForge.net. Fast, secure and Free Open Source software downloads" /></a>
-    </div>
-  </div>
-  </div>
-
-  <div class="content">
-
-    <p>Below are screenshots of the <strong>OpenRocket</strong> model
-      rocket simulator.  Click on the images for a full view.  You can
-      also <a href="download.html">download the program</a> and start
-      experimenting yourself!</p>
-
-
-    <div class="smallshotconst"><a href="shots/main.png">
-      <img src="shots-small/main.jpg" alt="Main window"/><br/>
-      The main rocket design window is used to design the rocket and
-      it also provides information about a flight simulation in
-      real-time.
-    </a></div>
-    <div class="smallshotconst"><a href="shots/dialog-edit.png">
-      <img src="shots-small/dialog-edit.jpg" alt="Component edit dialog"/><br/>
-      The component shape and properties are defined in their own
-      dialog.
-    </a></div>
-    <div class="smallshotconst"><a href="shots/dialog-analysis.png">
-      <img src="shots-small/dialog-analysis.jpg" alt="Analysis dialog"/><br/>
-      You can analyze the effect of individual components on the
-      stability, drag and roll characteristics of the rocket.
-    </a></div>
-    <div class="smallshotconst"><a href="shots/dialog-plot-options.png">
-      <img src="shots-small/dialog-plot-options.jpg" 
-        alt="Simulation plot options"/><br/>
-      The simulation results can be plotted in a multitude
-      of ways.  You can either use the predefined plot
-      configurations or define your own.<br/>
-    </a></div>
-    <div class="smallshotconst"><a href="shots/dialog-plot.png">
-      <img src="shots-small/dialog-plot.jpg" alt="Simulation plot"/><br/>
-      The simulations are plotted using the
-      <em>JFreeChart</em> plotting library.
-    </a></div>
-    <div class="clear"></div>
-
-  </div>
-
-  <div class="valid">
-    <p><a href="http://validator.w3.org/check/referer"><img src="valid-xhtml10.png" alt="Valid XHTML 1.0!"/></a>
-       <a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="vcss.gif" alt="Valid CSS!"/></a>
-    </p>
-  </div>
-
-<!-- Piwik -->
-<script type="text/javascript">
-var pkBaseURL = (("https:" == document.location.protocol) ? "https://apps.sourceforge.net/piwik/openrocket/" : "http://apps.sourceforge.net/piwik/openrocket/");
-document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
-</script><script type="text/javascript">
-piwik_action_name = '';
-piwik_idsite = 1;
-piwik_url = pkBaseURL + "piwik.php";
-piwik_log(piwik_action_name, piwik_idsite, piwik_url);
-</script>
-<noscript><p><img src="http://apps.sourceforge.net/piwik/openrocket/piwik.php?idsite=1" alt=""/></p></noscript>
-<!-- End Piwik Tag -->
-
-</body>
-</html>
-
diff --git a/html/shots-small/dialog-analysis.jpg b/html/shots-small/dialog-analysis.jpg
deleted file mode 100644 (file)
index 570c484..0000000
Binary files a/html/shots-small/dialog-analysis.jpg and /dev/null differ
diff --git a/html/shots-small/dialog-edit.jpg b/html/shots-small/dialog-edit.jpg
deleted file mode 100644 (file)
index c2dc593..0000000
Binary files a/html/shots-small/dialog-edit.jpg and /dev/null differ
diff --git a/html/shots-small/dialog-plot-options.jpg b/html/shots-small/dialog-plot-options.jpg
deleted file mode 100644 (file)
index ad977ab..0000000
Binary files a/html/shots-small/dialog-plot-options.jpg and /dev/null differ
diff --git a/html/shots-small/dialog-plot.jpg b/html/shots-small/dialog-plot.jpg
deleted file mode 100644 (file)
index d0fc66d..0000000
Binary files a/html/shots-small/dialog-plot.jpg and /dev/null differ
diff --git a/html/shots-small/main.jpg b/html/shots-small/main.jpg
deleted file mode 100644 (file)
index 7fcd946..0000000
Binary files a/html/shots-small/main.jpg and /dev/null differ
diff --git a/html/shots/dialog-analysis.png b/html/shots/dialog-analysis.png
deleted file mode 100644 (file)
index b71f1aa..0000000
Binary files a/html/shots/dialog-analysis.png and /dev/null differ
diff --git a/html/shots/dialog-edit.png b/html/shots/dialog-edit.png
deleted file mode 100644 (file)
index 9107859..0000000
Binary files a/html/shots/dialog-edit.png and /dev/null differ
diff --git a/html/shots/dialog-plot-options.png b/html/shots/dialog-plot-options.png
deleted file mode 100644 (file)
index ca627fa..0000000
Binary files a/html/shots/dialog-plot-options.png and /dev/null differ
diff --git a/html/shots/dialog-plot.png b/html/shots/dialog-plot.png
deleted file mode 100644 (file)
index 225dca8..0000000
Binary files a/html/shots/dialog-plot.png and /dev/null differ
diff --git a/html/shots/main.png b/html/shots/main.png
deleted file mode 100644 (file)
index 2b9af49..0000000
Binary files a/html/shots/main.png and /dev/null differ
diff --git a/html/thesis.pdf b/html/thesis.pdf
deleted file mode 100644 (file)
index e82acf6..0000000
Binary files a/html/thesis.pdf and /dev/null differ
diff --git a/html/update-html.sh b/html/update-html.sh
deleted file mode 100755 (executable)
index 913a8b3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-scp *.html  plaa,openrocket@web.sourceforge.net:htdocs/
diff --git a/html/valid-xhtml10.png b/html/valid-xhtml10.png
deleted file mode 100644 (file)
index b81de91..0000000
Binary files a/html/valid-xhtml10.png and /dev/null differ
diff --git a/html/vcss.gif b/html/vcss.gif
deleted file mode 100644 (file)
index 020c75a..0000000
Binary files a/html/vcss.gif and /dev/null differ
diff --git a/html/whitebox.png b/html/whitebox.png
deleted file mode 100644 (file)
index e5acdb2..0000000
Binary files a/html/whitebox.png and /dev/null differ
index 3c7da79472b4e950c644aacc8e26342366b2c219..a0b2744a7e2908d5991d34d150c83a638e6cfd8a 100644 (file)
@@ -9,10 +9,10 @@ Steps for making a release:
 6.  Copy distribution files into dists/
 7.  Update Eclipse project and commit files to SVN
 8.  Tag the version in SVN, URL:
-    https://openrocket.svn.sourceforge.net/svnroot/openrocket/tags/Release_0.9.x
+    https://openrocket.svn.sourceforge.net/svnroot/openrocket/tags/Release_1.1.x
 9.  Update updates.php and test various versions using a different name:
     scp updates.php plaa,openrocket@web.sourceforge.net:htdocs/actions/testupdates.php
-    java -Dopenrocket.debug.updateurl=http://openrocket.sourceforge.net/actions/testupdates.php -jar OpenRocket-0.9.4.jar
+    java -Dopenrocket.debug.updateurl=http://openrocket.sourceforge.net/actions/testupdates.php -jar OpenRocket-1.1.0.jar
 10. Upload JAR and source distribution and ReleaseNotes to Sourceforge 
      - Project Admin -> File Manager
      - create new version directory under /openrocket
index 1dc3329a5477030bf9bca29d0bf66cdaf9c5bbfc..c2246a4d3a61e195b31d627f924031a82dbc3173 100644 (file)
@@ -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 = 
                "<openrocket".getBytes(Charset.forName("US-ASCII"));
+    private static final byte[] ROCKSIM_SIGNATURE = 
+        "<RockSimDoc".getBytes(Charset.forName("US-ASCII"));
        
        private final OpenRocketLoader openRocketLoader = new OpenRocketLoader();
+    
+    private final RocksimLoader rocksimLoader = new RocksimLoader();
        
        @Override
        protected OpenRocketDocument loadFromStream(InputStream source) throws IOException,
@@ -68,7 +74,11 @@ public class GeneralRocketLoader extends RocketLoader {
                                match = 0;
                        }
                }
-               
+
+        byte[] typeIdentifier = Arrays.copyOf(buffer, ROCKSIM_SIGNATURE.length);
+        if (Arrays.equals(ROCKSIM_SIGNATURE, typeIdentifier)) {
+            return loadUsing(source, rocksimLoader);            
+        }
                throw new RocketLoadException("Unsupported or corrupt file.");
        }
        
diff --git a/src/net/sf/openrocket/file/rocksim/AttachedPartsHandler.java b/src/net/sf/openrocket/file/rocksim/AttachedPartsHandler.java
new file mode 100644 (file)
index 0000000..7608574
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * AttachedPartsHandler.java
+ */
+package net.sf.openrocket.file.rocksim;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.ElementHandler;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+
+import java.util.HashMap;
+
+/**
+ * A SAX handler for the Rocksim AttachedParts XML type.  
+ */
+class AttachedPartsHandler extends ElementHandler {
+    /** The parent component. */
+    private final RocketComponent component;
+
+    /**
+     * Constructor.
+     * 
+     * @param c  the parent
+     * 
+     * @throws IllegalArgumentException   thrown if <code>c</code> 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<String, String> 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 (file)
index 0000000..700c2f9
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * 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.
+ *
+ * @param <C>   the specific RocketComponent subtype for which the concrete handler can create
+ */
+public abstract class BaseHandler<C extends RocketComponent> 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 internal Rocksim density type.
+     */
+    private RocksimDensityType densityType = RocksimDensityType.ROCKSIM_BULK;
+
+    /**
+     * 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<String, String> 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) );
+            }
+            if ("KnownCG".equals(element)) {
+                cg = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH);
+            }
+            if ("UseKnownCG".equals(element)) {  //Rocksim sets UseKnownCG to true to control the override of both cg and mass
+                boolean override = "1".equals(content);
+                setOverride(component, override, mass, cg);
+            }
+            if ("DensityType".equals(element)) {
+                densityType = RocksimDensityType.fromCode(Integer.parseInt(content));
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void endHandler(String element, HashMap<String, String> 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.
+         */
+        density = computeDensity(densityType, density);
+        RocketComponent component = getComponent();
+        updateComponentMaterial(component, materialName, getMaterialType(), density);
+    }
+
+    /**
+     * Compute the density.  Rocksim does strange things with densities.  For some streamer material it's in cubic,
+     * rather than square, units.  In those cases it needs to be converted to an appropriate SURFACE material density.
+     * Some G10 fiberglass materials are in cubic units, other G10 fiberglass is in square units.  And due to a
+     * Rocksim bug, some densities are 0 when they clearly should not be.
+     *
+     * This may be overridden for specific component density computations.
+     *
+     * @param type       the rocksim density
+     * @param rawDensity the density as specified in the Rocksim design file
+     * @return a value in OpenRocket SURFACE density units
+     */
+    protected double computeDensity(RocksimDensityType type, double rawDensity) {
+        return rawDensity / type.asOpenRocket();
+    }
+
+    /**
+     * 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 (file)
index 0000000..6347d3b
--- /dev/null
@@ -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<BodyTube> {
+    /**
+     * The OpenRocket BodyTube.
+     */
+    private final BodyTube bodyTube;
+
+    /**
+     * Constructor.
+     *
+     * @param c parent component
+     * @throws IllegalArgumentException thrown if <code>c</code> 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<String, String> attributes, WarningSet warnings) {
+        if ("AttachedParts".equals(element)) {
+            return new AttachedPartsHandler(bodyTube);
+        }
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> 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 (file)
index 0000000..fb8add5
--- /dev/null
@@ -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, <code>asOpenRocket</code> 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 <code>c</code> 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<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> 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_BULK_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<String, String> 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:
+     *                  <pre>x0,y0|x1,y1|x2,y2|... </pre>
+     * @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<Coordinate> result = new ArrayList<Coordinate>();
+        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 (file)
index 0000000..1c7b41c
--- /dev/null
@@ -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<InnerTube> {
+
+    /**
+     * The OpenRocket InnerTube instance.
+     */
+    private final InnerTube bodyTube;
+
+    /**
+     * Constructor.
+     *
+     * @param c the parent component
+     * @throws IllegalArgumentException thrown if <code>c</code> 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<String, String> attributes, WarningSet warnings) {
+        if ("AttachedParts".equals(element)) {
+            return new AttachedPartsHandler(bodyTube);
+        }
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> 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 (file)
index 0000000..969cfdb
--- /dev/null
@@ -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<LaunchLug> {
+
+    /**
+     * The OpenRocket LaunchLug instance.
+     */
+    private final LaunchLug lug;
+
+    /**
+     * Constructor.
+     *
+     * @param c the parent
+     * @throws IllegalArgumentException thrown if <code>c</code> 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<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> 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 (file)
index 0000000..31ddef7
--- /dev/null
@@ -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<MassComponent> {
+
+    /** 
+     * 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 <code>c</code> 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<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> 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 (file)
index 0000000..6dc4efa
--- /dev/null
@@ -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<NoseCone> {
+
+    /**
+     * 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 <code>c</code> 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<String, String> 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<String, String> 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<String, String> 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 (file)
index 0000000..6cadaff
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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 RecoveryDeviceHandler<Parachute> {
+    /**
+     * 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 <code>c</code> 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);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void closeElement(String element, HashMap<String, String> 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) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LINE_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;
+    }
+
+}
+
diff --git a/src/net/sf/openrocket/file/rocksim/PositionDependentHandler.java b/src/net/sf/openrocket/file/rocksim/PositionDependentHandler.java
new file mode 100644 (file)
index 0000000..c65e1ae
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ *
+ * @param <C>   the specific position dependent RocketComponent subtype for which the concrete handler can create
+ */
+public abstract class PositionDependentHandler<C extends RocketComponent> extends BaseHandler<C> {
+
+    /** Temporary position value. */
+    private Double positionValue;
+
+    /** Temporary position. */
+    private RocketComponent.Position position;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void closeElement(String element, HashMap<String, String> 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<String, String> 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/RecoveryDeviceHandler.java b/src/net/sf/openrocket/file/rocksim/RecoveryDeviceHandler.java
new file mode 100644 (file)
index 0000000..387e29b
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * RecoveryDeviceHandler.java
+ */
+package net.sf.openrocket.file.rocksim;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.RecoveryDevice;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+
+/**
+ * A handler specific to streamers and parachutes.  This is done because Rocksim allows any type of material to be
+ * used as a recovery device, which causes oddities with respect to densities.  Density computation is overridden
+ * here to try to correctly compute a material's density in OpenRocket units.
+ *
+ * @param <C>  either a Streamer or Parachute
+ */
+public abstract class RecoveryDeviceHandler<C extends RecoveryDevice> extends PositionDependentHandler<C> {
+
+    /**
+     * The thickness.  Not used by every component, and some component handlers may parse it for their own purposes.
+     */
+    private double thickness = 0d;
+    /**
+     * The Rocksim calculated mass.  Used only when not overridden and when Rocksim says density == 0 (Rocksim bug).
+     */
+    private Double calcMass = 0d;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+            throws SAXException {
+        super.closeElement(element, attributes, content, warnings);
+
+        try {
+            if ("Thickness".equals(element)) {
+                thickness = Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_LENGTH;
+            }
+            if ("CalcMass".equals(element)) {
+                calcMass = Math.max(0d, Double.parseDouble(content) / RocksimHandler.ROCKSIM_TO_OPENROCKET_MASS);
+            }
+        }
+        catch (NumberFormatException nfe) {
+            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+        }
+    }
+
+
+    /**
+     * Compute the density.  Rocksim does strange things with densities.  For some streamer material it's in cubic,
+     * rather than square, units.  In those cases it needs to be converted to an appropriate SURFACE material density.
+     *
+     * @param type       the rocksim density
+     * @param rawDensity the density as specified in the Rocksim design file
+     * @return a value in OpenRocket SURFACE density units
+     */
+    protected double computeDensity(RocksimDensityType type, double rawDensity) {
+
+        double result;
+
+        if (rawDensity > 0d) {
+            //ROCKSIM_SURFACE is a square area density; compute normally
+            //ROCKSIM_LINE is a single length dimension (kg/m) but Rocksim ignores thickness for this type and treats
+            //it like a SURFACE.
+            if (RocksimDensityType.ROCKSIM_SURFACE.equals(type) || RocksimDensityType.ROCKSIM_LINE.equals(type)) {
+                result = rawDensity / RocksimDensityType.ROCKSIM_SURFACE.asOpenRocket();
+            }
+            //ROCKSIM_BULK is a cubic area density; multiple by thickness to make per square area; the result, when
+            //multiplied by the area will then equal Rocksim's computed mass.
+            else {
+                result = (rawDensity / type.asOpenRocket()) * thickness;
+            }
+        }
+        else {
+            result = calcMass / getComponent().getArea();
+            //A Rocksim bug on streamers/parachutes results in a 0 density at times.  When that is detected, try
+            //to compute an approximate density from Rocksim's computed mass.
+            if (RocksimDensityType.ROCKSIM_BULK.equals(type)) {
+                //ROCKSIM_BULK is a cubic area density; multiple by thickness to make per square area
+                result *= thickness;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 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) {
+        getComponent().setRelativePosition(position);
+    }
+
+    /**
+     * Get the required type of material for this component.  This is the OpenRocket type, which does NOT always
+     * correspond to Rocksim.  Some streamer material is defined as BULK in the Rocksim file.  In those cases
+     * it is adjusted in this handler.
+     *
+     * @return SURFACE
+     */
+    @Override
+    public Material.Type getMaterialType() {
+        return Material.Type.SURFACE;
+    }
+
+}
diff --git a/src/net/sf/openrocket/file/rocksim/RingHandler.java b/src/net/sf/openrocket/file/rocksim/RingHandler.java
new file mode 100644 (file)
index 0000000..ccfcfb0
--- /dev/null
@@ -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<CenteringRing> {
+
+    /**
+     * The OpenRocket Ring.
+     */
+    private final CenteringRing ring;
+
+    /**
+     * Constructor.
+     *
+     * @param c the parent component
+     * @throws IllegalArgumentException thrown if <code>c</code> 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<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> 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/RocksimDensityType.java b/src/net/sf/openrocket/file/rocksim/RocksimDensityType.java
new file mode 100644 (file)
index 0000000..c672b62
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * RocksimDensityType.java
+ */
+package net.sf.openrocket.file.rocksim;
+
+/**
+ * Models the nose cone shape of a rocket.  Maps from Rocksim's notion to OpenRocket's.
+ */
+enum RocksimDensityType {
+    ROCKSIM_BULK   (0, RocksimHandler.ROCKSIM_TO_OPENROCKET_BULK_DENSITY),
+    ROCKSIM_SURFACE(1, RocksimHandler.ROCKSIM_TO_OPENROCKET_SURFACE_DENSITY),
+    ROCKSIM_LINE   (2, RocksimHandler.ROCKSIM_TO_OPENROCKET_LINE_DENSITY);
+
+    /** The Rocksim enumeration value. Sent in XML. */
+    private final int ordinal;
+
+    /** The corresponding OpenRocket shape. */
+    private final double conversion;
+
+    /**
+     * Constructor.
+     *
+     * @param idx            the Rocksim shape code
+     * @param theConversion  the numerical conversion ratio to OpenRocket
+     */
+    private RocksimDensityType(int idx, double theConversion) {
+        ordinal = idx;
+        conversion = theConversion;
+    }
+
+    /**
+     * Get the OpenRocket shape that corresponds to the Rocksim value.
+     *
+     * @return a conversion
+     */
+    public double asOpenRocket() {
+        return conversion;
+    }
+
+    /**
+     * Lookup an instance of this enum based upon the Rocksim code.
+     *
+     * @param rocksimDensityType  the Rocksim code (from XML)
+     * @return an instance of this enum
+     */
+    public static RocksimDensityType fromCode(int rocksimDensityType) {
+        RocksimDensityType[] values = values();
+        for (RocksimDensityType value : values) {
+            if (value.ordinal == rocksimDensityType) {
+                return value;
+            }
+        }
+        return ROCKSIM_BULK; //Default
+    }
+}
+
diff --git a/src/net/sf/openrocket/file/rocksim/RocksimFinishCode.java b/src/net/sf/openrocket/file/rocksim/RocksimFinishCode.java
new file mode 100644 (file)
index 0000000..cf1748b
--- /dev/null
@@ -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 (file)
index 0000000..51c2051
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * 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.
+ * <p/>
+ * 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;
+
+    /**
+     * Bulk Density conversion.  Rocksim is in kilograms/cubic meter, OpenRocket in kilograms/cubic meter.
+     */
+    public static final int ROCKSIM_TO_OPENROCKET_BULK_DENSITY = 1;
+
+    /**
+     * Surface Density conversion.  Rocksim is in grams/sq centimeter, OpenRocket in kilograms/sq meter.  1000/(100*100) = 1/10
+     */
+    public static final double ROCKSIM_TO_OPENROCKET_SURFACE_DENSITY = 1/10d;
+
+    /**
+     * Line Density conversion.  Rocksim is in kilograms/meter, OpenRocket in kilograms/meter. 
+     */
+    public static final int ROCKSIM_TO_OPENROCKET_LINE_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 <code>null</code> 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<String, String> 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 <DesignInformation> 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<String, String> 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<String, String> 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<String, String> 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<String, String> 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 <code>c</code> 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<String, String> 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 (file)
index 0000000..7095341
--- /dev/null
@@ -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 (file)
index 0000000..4b30703
--- /dev/null
@@ -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 (file)
index 0000000..8cd7c82
--- /dev/null
@@ -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 (file)
index 0000000..d638f62
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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.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 RecoveryDeviceHandler<Streamer> {
+
+    /**
+     * The OpenRocket Streamer.
+     */
+    private final Streamer streamer;
+
+    /**
+     * Constructor.
+     *
+     * @param c the parent component
+     * @throws IllegalArgumentException thrown if <code>c</code> 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);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void closeElement(String element, HashMap<String, String> 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.");
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Streamer getComponent() {
+        return streamer;
+    }
+
+}
+
diff --git a/src/net/sf/openrocket/file/rocksim/TransitionHandler.java b/src/net/sf/openrocket/file/rocksim/TransitionHandler.java
new file mode 100644 (file)
index 0000000..1f3b02e
--- /dev/null
@@ -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<Transition> {
+    /**
+     * 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 <code>c</code> 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<String, String> attributes, WarningSet warnings) {
+        return PlainTextHandler.INSTANCE;
+    }
+
+    @Override
+    public void closeElement(String element, HashMap<String, String> 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<String, String> 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;
+    }
+
+
+}
+
index f8fb7370ed0cd20ec1adeba90a3998566a02a293..a2a18e14a369bf739a6bc116bb2de2c2420d1a46 100644 (file)
@@ -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)
index 702c3025cf5d866644f5a85dbf93d9e395f57bff..4099f019120d4c4942c5db5c1b795854ea96d29d 100644 (file)
@@ -103,14 +103,14 @@ public class ExceptionHandler implements Thread.UncaughtExceptionHandler {
         * @param exception             the exception that occurred.
         */
        public static void handleErrorCondition(final Exception exception) {
-               final ExceptionHandler handler;
+               final ExceptionHandler handler = instance;
 
                try {
 
-                       if (instance == null) {
-                               handler = new ExceptionHandler();
-                       } else {
-                               handler = instance;
+                       if (handler == null) {
+                               // Not initialized, simply print the exception
+                               exception.printStackTrace();
+                               return;
                        }
 
                        final Thread thread = Thread.currentThread();
diff --git a/src/net/sf/openrocket/gui/main/SimpleFileFilter.java b/src/net/sf/openrocket/gui/main/SimpleFileFilter.java
new file mode 100644 (file)
index 0000000..5fbcb1b
--- /dev/null
@@ -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 <sampo.niskanen@iki.fi>
+ */
+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; i<extensions.length; i++) {
+                       String ext = extensions[i].toLowerCase();
+                       if (ext.charAt(0) == '.') {
+                               this.extensions[i] = ext;
+                       } else {
+                               this.extensions[i] = '.' + ext;
+                       }
+               }
+       }
+       
+       
+       
+       @Override
+       public boolean accept(File file) {
+               if (file == null)
+                       return false;
+               if (file.isDirectory())
+                       return true;
+               
+               String filename = file.getName();
+               filename = filename.toLowerCase();
+               for (String ext: extensions) {
+                       if (filename.endsWith(ext))
+                               return true;
+               }
+               
+               return false;
+       }
+
+       @Override
+       public String getDescription() {
+               return description;
+       }
+
+}
index 10a8daa7ec22b74eb9ddb05ca408e6321f4721e0..45ff9e55b963fa0699d920e8c4dd121eeac2a103 100644 (file)
@@ -12,23 +12,42 @@ import java.util.List;
  */
 public class DelegatorLogger extends LogHelper {
 
-       private List<LogHelper> loggers = new ArrayList<LogHelper>();
+       /**
+        * List of loggers.  This list must not be modified, instead it should be
+        * replaced every time the list is changed.
+        */
+       private volatile ArrayList<LogHelper> loggers = new ArrayList<LogHelper>();
        
        @Override
        public void log(LogLine line) {
-               LogHelper[] array = loggers.toArray(new LogHelper[0]);
-               for (LogHelper l: array) {
+               // Must create local reference for thread safety
+               List<LogHelper> list = loggers;
+               for (LogHelper l: list) {
                        l.log(line);
                }
        }
        
        
-       public void addLogger(LogHelper logger) {
-               this.loggers.add(logger);
+       /**
+        * Add a logger from the delegation list.
+        * @param logger        the logger to add.
+        */
+       @SuppressWarnings("unchecked")
+       public synchronized void addLogger(LogHelper logger) {
+               ArrayList<LogHelper> newList = (ArrayList<LogHelper>) loggers.clone();
+               newList.add(logger);
+               this.loggers = newList;
        }
        
-       public void removeLogger(LogHelper logger) {
-               this.loggers.remove(logger);
+       /**
+        * Remove a logger from the delegation list.
+        * @param logger        the logger to be removed.
+        */
+       @SuppressWarnings("unchecked")
+       public synchronized void removeLogger(LogHelper logger) {
+               ArrayList<LogHelper> newList = (ArrayList<LogHelper>) loggers.clone();
+               newList.remove(logger);
+               this.loggers = newList;
        }
 
 }
index 8ddba5b69cbc37b1cbf48d52d9ce4bd904bfc0d1..838e8e7aaf50cac81a210fef7fde3564ae825027 100644 (file)
@@ -34,6 +34,12 @@ public abstract class LogHelper {
        
        
 
+       /**
+        * Log a LogLine object.  This method needs to be able to cope with multiple threads
+        * accessing it concurrently (for example being synchronized).
+        * 
+        * @param line  the LogLine to log.
+        */
        public abstract void log(LogLine line);
        
        
diff --git a/src/net/sf/openrocket/logging/PrintStreamLogger.java b/src/net/sf/openrocket/logging/PrintStreamLogger.java
new file mode 100644 (file)
index 0000000..16a7545
--- /dev/null
@@ -0,0 +1,34 @@
+package net.sf.openrocket.logging;
+
+import java.io.PrintStream;
+import java.util.EnumMap;
+
+/**
+ * A logger that output log lines to various print streams depending on the log level.
+ * By default output is logged nowhere.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class PrintStreamLogger extends LogHelper {
+
+       private static final EnumMap<LogLevel, PrintStream> output = 
+               new EnumMap<LogLevel, PrintStream>(LogLevel.class);
+       
+       
+       @Override
+       public void log(LogLine line) {
+               PrintStream stream = output.get(line.getLevel());
+               if (stream != null) {
+                       stream.println(line.toString());
+               }
+       }
+
+       
+       public void setOutput(LogLevel level, PrintStream stream) {
+               if (level == null) {
+                       throw new IllegalArgumentException("level="+level+" stream="+stream);
+               }
+               output.put(level, stream);
+       }
+       
+}
diff --git a/src/net/sf/openrocket/logging/StandardOutputLogger.java b/src/net/sf/openrocket/logging/StandardOutputLogger.java
deleted file mode 100644 (file)
index e87dd94..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-package net.sf.openrocket.logging;
-
-import java.io.PrintStream;
-
-public class StandardOutputLogger extends LogHelper {
-
-       private static final PrintStream[] output;
-       static {
-               LogLevel[] levels = LogLevel.values();
-               
-               output = new PrintStream[levels.length];
-               for (int i=0; i<levels.length; i++) {
-                       if (levels[i].atLeast(LogLevel.WARN))
-                               output[i] = System.err;
-                       else
-                               output[i] = System.out;
-               }
-       }
-       
-       
-       @Override
-       public void log(LogLine line) {
-               PrintStream stream = output[line.getLevel().ordinal()];
-               if (stream != null) {
-                       stream.println(line.toString());
-               }
-       }
-
-       
-       public void setOutput(LogLevel level, PrintStream stream) {
-               if (level == null || stream == null) {
-                       throw new IllegalArgumentException("level="+level+" stream="+stream);
-               }
-               output[level.ordinal()] = stream;
-       }
-       
-}
diff --git a/src/net/sf/openrocket/startup/Application.java b/src/net/sf/openrocket/startup/Application.java
new file mode 100644 (file)
index 0000000..876e1c0
--- /dev/null
@@ -0,0 +1,33 @@
+package net.sf.openrocket.startup;
+
+import net.sf.openrocket.logging.DelegatorLogger;
+import net.sf.openrocket.logging.LogHelper;
+
+/**
+ * A class that provides singleton instances / beans for other
+ * classes to utilize.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public final class Application {
+       
+       private static DelegatorLogger logger = null;
+
+       public static LogHelper getLogHelper() {
+               if (logger == null) {
+                       initializeLogging();
+               }
+               return logger;
+       }
+       
+       
+       /**
+        * Initializes the logging system and populates logHelper.
+        */
+       private static void initializeLogging() {
+               logger = new DelegatorLogger();
+               
+               
+       }
+       
+}
diff --git a/test/net/sf/openrocket/file/rocksim/BodyTubeHandlerTest.java b/test/net/sf/openrocket/file/rocksim/BodyTubeHandlerTest.java
new file mode 100644 (file)
index 0000000..915ed03
--- /dev/null
@@ -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 RocksimTestBase {
+
+    /**
+     * 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<String, String> 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<String, String> 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<String, String> attributes = new HashMap<String, String>();
+        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 (file)
index 0000000..5b02142
--- /dev/null
@@ -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<String, String> attributes = new HashMap<String, String>();
+        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 (file)
index 0000000..5a8827e
--- /dev/null
@@ -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 RocksimTestBase {
+
+    /**
+     * 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<String, String> 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<String, String> 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<String, String> attributes = new HashMap<String, String>();
+        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 (file)
index 0000000..6eb3263
--- /dev/null
@@ -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 RocksimTestBase {
+
+    /**
+     * 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<String, String> 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<String, String> 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<String, String> attributes = new HashMap<String, String>();
+        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 (file)
index 0000000..ce4bdde
--- /dev/null
@@ -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 RocksimTestBase {
+
+    /**
+     * 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<String, String> 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<String, String> attributes, String content, WarningSet warnings)
+     *
+     * @throws Exception  thrown if something goes awry
+     */
+    public void testCloseElement() throws Exception {
+        BodyTube tube = new BodyTube();
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        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 (file)
index 0000000..9cce15d
--- /dev/null
@@ -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 RocksimTestBase {
+
+    /**
+     * 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<String, String> 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<String, String> attributes, String content, WarningSet warnings)
+     *
+     * @throws Exception  thrown if something goes awry
+     */
+    public void testCloseElement() throws Exception {
+
+        Stage stage = new Stage();
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        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 (file)
index 0000000..f71461f
--- /dev/null
@@ -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 RocksimTestBase {
+
+    /**
+     * 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<String, String> 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<String, String> 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<String, String> attributes = new HashMap<String, String>();
+        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<String, String> attributes = new HashMap<String, String>();
+        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 (file)
index 0000000..5495d56
--- /dev/null
@@ -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 RocksimTestBase {
+
+    /**
+     * 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<String, String> 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<String, String> 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<String, String> attributes = new HashMap<String, String>();
+        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 (file)
index 0000000..d0820cf
--- /dev/null
@@ -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 (file)
index 0000000..45551ae
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * RocksimLoaderTest.java
+ *
+ */
+package net.sf.openrocket.file.rocksim;
+
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+
+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;
+
+/**
+ * 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");
+        assertNotNull("Could not open rocksimTestRocket1.rkt", stream);
+        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");
+        assertNotNull("Could not open rocksimTestRocket2.rkt", stream);
+        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");
+        assertNotNull("Could not open rocksimTestRocket3.rkt", stream);
+        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/RocksimTestBase.java b/test/net/sf/openrocket/file/rocksim/RocksimTestBase.java
new file mode 100644 (file)
index 0000000..394d385
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * BaseRocksimTest.java
+ */
+package net.sf.openrocket.file.rocksim;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.Field;
+
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+
+/**
+ * A base class for the Rocksim tests.  Includes code from the junitx.addons project.
+ */
+public abstract class RocksimTestBase extends TestCase {
+
+    /**
+     * Test constructor.
+     *
+     * @param name the name of the test to run.
+     */
+    public RocksimTestBase(String name) {
+        super(name);
+    }
+    
+    public void assertContains (RocketComponent child, RocketComponent[] components) {
+        for (int i = 0; i < components.length; i++) {
+            if (components[i].equals(child)) {
+                return;
+            }
+        }
+        fail("Component array did not contain child.");
+    }
+    
+    /**
+     * Returns the value of the field on the specified object.  The name
+     * parameter is a <code>String</code> specifying the simple name of the
+     * desired field.<p>
+     *
+     * 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 <code>String</code> specifying the simple name of the
+     * desired field.<p>
+     *
+     * 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/StreamerHandlerTest.java b/test/net/sf/openrocket/file/rocksim/StreamerHandlerTest.java
new file mode 100644 (file)
index 0000000..3051398
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * 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.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 RocksimTestBase {
+
+    /**
+     * 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<String, String> 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<String, String> 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<String, String> attributes = new HashMap<String, String>();
+        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<String, String> attributes = new HashMap<String, String>();
+        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);
+
+        handler.closeElement("Thickness", attributes, "0.02", warnings);
+        assertEquals(0.01848, handler.computeDensity(RocksimDensityType.ROCKSIM_BULK, 924d));
+
+        //Test Density Type 0 (Bulk)
+        handler.closeElement("Density", attributes, "924.0", warnings);
+        handler.closeElement("DensityType", attributes, "0", warnings);
+        handler.endHandler("Streamer", attributes, null, warnings);
+        assertEquals(0.01848d, component.getMaterial().getDensity());
+
+        //Test Density Type 1 (Surface)
+        handler.closeElement("Density", attributes, "0.006685", warnings);
+        handler.closeElement("DensityType", attributes, "1", warnings);
+        handler.endHandler("Streamer", attributes, null, warnings);
+        assertTrue(Math.abs(0.06685d - component.getMaterial().getDensity()) < 0.00001);
+
+        //Test Density Type 2 (Line)
+        handler.closeElement("Density", attributes, "0.223225", warnings);
+        handler.closeElement("DensityType", attributes, "2", warnings);
+        handler.closeElement("Len", attributes, "3810.", warnings);
+        handler.closeElement("Width", attributes, "203.2", warnings);
+        handler.endHandler("Streamer", attributes, null, warnings);
+
+        assertEquals(1.728190092, component.getMass());
+
+    }
+
+}
diff --git a/test/net/sf/openrocket/file/rocksim/TransitionHandlerTest.java b/test/net/sf/openrocket/file/rocksim/TransitionHandlerTest.java
new file mode 100644 (file)
index 0000000..f199f9a
--- /dev/null
@@ -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 RocksimTestBase {
+
+    /**
+     * 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<String, String> 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<String, String> attributes, String content, WarningSet warnings)
+     *
+     * @throws Exception thrown if something goes awry
+     */
+    public void testCloseElement() throws Exception {
+
+        Stage stage = new Stage();
+        HashMap<String, String> attributes = new HashMap<String, String>();
+        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 (file)
index 0000000..79f7b00
--- /dev/null
@@ -0,0 +1,743 @@
+<RockSimDocument>
+<FileVersion>3</FileVersion>
+<DesignInformation>
+<RocketDesign>
+    <Name>FooBar Test</Name>
+<CalculateCD>1</CalculateCD>
+<ProCalculateCD>1</ProCalculateCD>
+<ProCalculateCN>1</ProCalculateCN>
+<FixedCd>0.75</FixedCd>
+<FixedCd2>0.8</FixedCd2>
+<FixedCd3>0.81</FixedCd3>
+<FixedCd2Alone>0.95</FixedCd2Alone>
+<FixedCd3Alone>0.95</FixedCd3Alone>
+<StageCount>1</StageCount>
+<Stage3Mass>0.</Stage3Mass>
+<Stage2Mass>0.</Stage2Mass>
+<Stage1Mass>0.</Stage1Mass>
+<Stage321CG>0.</Stage321CG>
+<Stage32CG>0.</Stage32CG>
+<Stage3CG>0.</Stage3CG>
+<Stage2CGAlone>0.</Stage2CGAlone>
+<Stage1CGAlone>0.</Stage1CGAlone>
+<CPCalcFlags>1</CPCalcFlags>
+<LaunchGuideLength>914.4</LaunchGuideLength>
+<UseKnownMass>0</UseKnownMass>
+<DefaultFinish>0</DefaultFinish>
+<FinishMedium>0</FinishMedium>
+<FinishCoatCount>1</FinishCoatCount>
+<GlueType>0</GlueType>
+<CPSimFlags>1</CPSimFlags>
+<LastSerialNumber>11</LastSerialNumber>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<BarromanXN>0,1215.49,0,0</BarromanXN>
+<BarrowmanCNa>0,35.9506,0,0</BarrowmanCNa>
+<RockSimXN>0,1226.38,0,0</RockSimXN>
+<RockSimCNa>0,47.5027,0,0</RockSimCNa>
+<RockSimCNa90>0,0,0,0</RockSimCNa90>
+<RockSimXN90>0,0,0,0</RockSimXN90>
+<ViewType>0</ViewType>
+<ViewStageCount>1</ViewStageCount>
+<ViewTypeEdit>0</ViewTypeEdit>
+<ViewStageCountEdit>1</ViewStageCountEdit>
+<ZoomFactor>0.</ZoomFactor>
+<ZoomFactorEdit>0.</ZoomFactorEdit>
+<ScrollPosX>0</ScrollPosX>
+<ScrollPosY>0</ScrollPosY>
+<ScrollPosXEdit>0</ScrollPosXEdit>
+<ScrollPosYEdit>0</ScrollPosYEdit>
+<ThreeDFlags>0</ThreeDFlags>
+<ThreeDFlagsEdit>0</ThreeDFlagsEdit>
+<UseModelSprite>0</UseModelSprite>
+<StaticMarginRef>0</StaticMarginRef>
+<UserRefDiameter>0.</UserRefDiameter>
+<SideMarkerHeight>10.</SideMarkerHeight>
+<SideDimensionHeight>10.</SideDimensionHeight>
+<BaseMarkerHeight>10.</BaseMarkerHeight>
+<BaseDimensionHeight>10.</BaseDimensionHeight>
+<ShowGlideCP>0</ShowGlideCP>
+<ShowGridTypeSide>0</ShowGridTypeSide>
+<ShowGridTypeBase>0</ShowGridTypeBase>
+<GridSpacing>10.</GridSpacing>
+<GridOpacity>0.15</GridOpacity>
+<GridColor>black</GridColor>
+<MaxDiaWithFins>424.688</MaxDiaWithFins>
+<MaxDiaWithoutFins>66.04</MaxDiaWithoutFins>
+<MaxLenWithFins>1417.95</MaxLenWithFins>
+<MaxLenWithoutFins>1332.23</MaxLenWithoutFins>
+<MinXExtent>0.</MinXExtent>
+<MaxXExtent>1417.95</MaxXExtent>
+<CalculatedMaxStageDia>0,66.04,0,0</CalculatedMaxStageDia>
+<CalculatedStageLen>0,1332.23,0,0</CalculatedStageLen>
+<Cd3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd3>
+<Cd32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd32>
+<Cd321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd321>
+<Cb3>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb3>
+<Cb32>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb32>
+<Cb321>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb321>
+<CNa3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa3>
+<CNa32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa32>
+<CNa321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa321>
+<CP3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP3>
+<CP32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP32>
+<CP321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP321>
+<SimulationEventList>
+</SimulationEventList>
+<Stage3Parts>
+<NoseCone>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>24.1</KnownMass>
+<Density>1049.21</Density>
+<Material>Polystyrene PS</Material>
+<Name>Nose cone</Name>
+<KnownCG>65.3999</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>126.438</CalcMass>
+<CalcCG>348.443</CalcCG>
+<WettedSurface>0.0356487</WettedSurface>
+<PaintedSurface>0.0356487</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>19470</PartNo>
+<PartDesc>PNC-70A</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>2</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>2.</BarrowmanCNa>
+<BarrowmanXN>0.264319</BarrowmanXN>
+<RockSimCNa>2.</RockSimCNa>
+<RockSimXN>0.264319</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>0.</Station>
+<Len>396.875</Len>
+<BaseDia>57.15</BaseDia>
+<FinishCode>0</FinishCode>
+<ShapeCode>0</ShapeCode>
+<ConstructionType>1</ConstructionType>
+<ShoulderLen>58.3997</ShoulderLen>
+<WallThickness>2.159</WallThickness>
+<ShapeParameter>0.</ShapeParameter>
+<ShoulderOD>53.1012</ShoulderOD>
+<BaseExtensionLen>66.675</BaseExtensionLen>
+<CoreDia>0.</CoreDia>
+<CoreLen>0.</CoreLen>
+<AttachedParts>
+</AttachedParts>
+</NoseCone>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>10.636</CalcMass>
+<CalcCG>180.34</CalcCG>
+<WettedSurface>0.0748306</WettedSurface>
+<PaintedSurface>0.0748306</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3090</PartNo>
+<PartDesc>BT-80</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>3</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>463.55</Station>
+<OD>66.04</OD>
+<ID>65.786</ID>
+<Len>360.68</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+<Transition>
+<PartMfg>BalsaMachining.com</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Transition</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>39.355</CalcMass>
+<CalcCG>37.0332</CalcCG>
+<WettedSurface>0.0096001</WettedSurface>
+<PaintedSurface>0.0096001</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TA7080</PartNo>
+<PartDesc>Transition T70 to T80 2 in long</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>7</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>-0.92852</BarrowmanCNa>
+<BarrowmanXN>0.848729</BarrowmanXN>
+<RockSimCNa>-0.92852</RockSimCNa>
+<RockSimXN>0.848729</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>824.23</Station>
+<FrontDia>66.04</FrontDia>
+<RearDia>53.34</RearDia>
+<Len>50.8</Len>
+<FinishCode>0</FinishCode>
+<FrontShoulderLen>35.56</FrontShoulderLen>
+<RearShoulderLen>35.56</RearShoulderLen>
+<ConstructionType>0</ConstructionType>
+<WallThickness>0.</WallThickness>
+<FrontShoulderDia>55.118</FrontShoulderDia>
+<RearShoulderDia>53.34</RearShoulderDia>
+<CoreDia>0.</CoreDia>
+<ShapeCode>0</ShapeCode>
+<ShapeParameter>0.</ShapeParameter>
+<EquivNoseLen>264.12</EquivNoseLen>
+<EquivNoseOffset>213.32</EquivNoseOffset>
+<AttachedParts>
+</AttachedParts>
+</Transition>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>44.449</CalcMass>
+<CalcCG>222.25</CalcCG>
+<WettedSurface>0.0787423</WettedSurface>
+<PaintedSurface>0.0787423</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>Estes</PartNo>
+<PartDesc>BT-70</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>8</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>875.03</Station>
+<OD>56.388</OD>
+<ID>55.372</ID>
+<Len>444.5</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<FinSet>
+<PartMfg>Public Missiles</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1905.24</Density>
+<Material>G10 fiberglass</Material>
+<Name>Fin set</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>260.35</Xb>
+<CalcMass>153.85</CalcMass>
+<CalcCG>155.575</CalcCG>
+<WettedSurface>0.0339112</WettedSurface>
+<PaintedSurface>0.101734</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>FIN-A-01</PartNo>
+<PartDesc>Fins</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>9</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>34.8792</BarrowmanCNa>
+<BarrowmanXN>1.26026</BarrowmanXN>
+<RockSimCNa>46.4312</RockSimCNa>
+<RockSimXN>1.26026</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>1135.38</Station>
+<FinCount>3</FinCount>
+<RootChord>184.15</RootChord>
+<TipChord>0.</TipChord>
+<SemiSpan>184.15</SemiSpan>
+<MidChordLen>264.956</MidChordLen>
+<SweepDistance>282.575</SweepDistance>
+<Thickness>1.5875</Thickness>
+<ShapeCode>0</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>0</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.990003</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>89.5773</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>26.8071</RockSimCNaPerFin>
+<TaperRatio>0.</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>13.008</CalcMass>
+<CalcCG>228.6</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3086</PartNo>
+<PartDesc>BT-50</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>11</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>875.03</Station>
+<OD>24.7904</OD>
+<ID>24.13</ID>
+<Len>457.2</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>24.</MotorDia>
+<EngineOverhang>12.7</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</BodyTube>
+</Stage3Parts>
+<Stage2Parts>
+</Stage2Parts>
+<Stage1Parts>
+</Stage1Parts>
+<SideViewDims>
+</SideViewDims>
+<BaseViewDims>
+</BaseViewDims>
+<VertViewDims>
+</VertViewDims>
+</RocketDesign>
+</DesignInformation>
+<SimulationResultsList>
+<SimulationResults>
+<MaxAltitude>445.129</MaxAltitude>
+<MaxVelocity>68.7587</MaxVelocity>
+<MaxAcceleration>76.6476</MaxAcceleration>
+<TimeToApogee>10.8263</TimeToApogee>
+<OptimalDelay>4.765</OptimalDelay>
+<MultiDelayCount>1</MultiDelayCount>
+<VelocityAtDeplyment>33.4284</VelocityAtDeplyment>
+<AltitudeAtDeployment>405.535</AltitudeAtDeployment>
+<DelayTime>2</DelayTime>
+<EjectTime>8.06125</EjectTime>
+<FinalState>4</FinalState>
+<TimeToBurnout>6.06125</TimeToBurnout>
+<TimeToLanding>22.4787</TimeToLanding>
+<TimeToEject>8.06125</TimeToEject>
+<MinLaunchGuideLen>1.35915</MinLaunchGuideLen>
+<MaxVertVelocity>65.9349</MaxVertVelocity>
+<MaxHorzVelocity>1.0686</MaxHorzVelocity>
+<MaxVertAcceleration>76.5426</MaxVertAcceleration>
+<MaxHorzAcceleration>4.01173</MaxHorzAcceleration>
+<MaxRange>172.076</MaxRange>
+<LaunchStartVelocity>0.</LaunchStartVelocity>
+<LaunchStartRollRate>0.</LaunchStartRollRate>
+<LaunchGuideType>0</LaunchGuideType>
+<LaunchGuideLen>1828.8</LaunchGuideLen>
+<LaunchWindDirection>0</LaunchWindDirection>
+<LaunchWindSpeed>0.</LaunchWindSpeed>
+<LaunchDirection>0</LaunchDirection>
+<LaunchAngle>0.0523599</LaunchAngle>
+<LaunchGuideAzimuth>0.</LaunchGuideAzimuth>
+<LaunchGuideElevation>0.</LaunchGuideElevation>
+<LaunchBarometer>770.314</LaunchBarometer>
+<LaunchLatitude>43.</LaunchLatitude>
+<LaunchLongitude>0.</LaunchLongitude>
+<LaunchHumidity>70.</LaunchHumidity>
+<LaunchTemperature>7.22222</LaunchTemperature>
+<LaunchAltitude>304.8</LaunchAltitude>
+<LaunchLandingAltitude>0.</LaunchLandingAltitude>
+<CompStateMask>0</CompStateMask>
+<LaunchWindPreset>3</LaunchWindPreset>
+<LaunchWindLowSpeed>1.34112</LaunchWindLowSpeed>
+<LaunchWindHighSpeed>3.53162</LaunchWindHighSpeed>
+<LaunchWindTurbulencePreset>2</LaunchWindTurbulencePreset>
+<LaunchWindFrequency>0.01</LaunchWindFrequency>
+<LaunchWindDeltaFrequency>0.02</LaunchWindDeltaFrequency>
+<LaunchUseRandomConditions>0</LaunchUseRandomConditions>
+<LaunchCloudCoverPreset>5</LaunchCloudCoverPreset>
+<LaunchCCLow>0.</LaunchCCLow>
+<LaunchCCHigh>0.1</LaunchCCHigh>
+<LaunchThermalPosPreset>1</LaunchThermalPosPreset>
+<LaunchThermalPos>0.</LaunchThermalPos>
+<LaunchMultipleThermals>0</LaunchMultipleThermals>
+<LaunchMaxThermals>3</LaunchMaxThermals>
+<LaunchThermalDia>300.</LaunchThermalDia>
+<LaunchThermalHeight>2000.</LaunchThermalHeight>
+<LaunchThermalSpeedPreset>1</LaunchThermalSpeedPreset>
+<LaunchThermalSpeed>5.99999</LaunchThermalSpeed>
+<LaunchWindTableSize>0</LaunchWindTableSize>
+<LaunchWindAltTable>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</LaunchWindAltTable>
+<LaunchWindSpeedTable>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</LaunchWindSpeedTable>
+<LaunchWindDirectionTable>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</LaunchWindDirectionTable>
+<LaunchLossPreset>2</LaunchLossPreset>
+<LaunchLossPercent>0.99</LaunchLossPercent>
+<LaunchSiteDia>2000.</LaunchSiteDia>
+<LaunchDriftRangeToLoss>1500.</LaunchDriftRangeToLoss>
+<LaunchPayloadDamagePreset>2</LaunchPayloadDamagePreset>
+<LaunchPayloadDamagePercent>0.98</LaunchPayloadDamagePercent>
+<LaunchEngineMisfirePreset>1</LaunchEngineMisfirePreset>
+<LaunchEngineMisfirePercent>0.</LaunchEngineMisfirePercent>
+<LaunchVariableIgnitionDelay>0</LaunchVariableIgnitionDelay>
+<LaunchVariableIgnitionDelaySec>0.08</LaunchVariableIgnitionDelaySec>
+<LaunchRecDeviceFailurePreset>1</LaunchRecDeviceFailurePreset>
+<LaunchRecDeviceFailurePercent>0.</LaunchRecDeviceFailurePercent>
+<LaunchAriframeFailurePreset>1</LaunchAriframeFailurePreset>
+<LaunchAirframeFailurePercent>0.</LaunchAirframeFailurePercent>
+<LaunchTrackLossPreset>1</LaunchTrackLossPreset>
+<LaunchTeckLossPercent>0.</LaunchTeckLossPercent>
+<CNaMultiplier>1.</CNaMultiplier>
+<CdMultiplier>1.</CdMultiplier>
+<CPOffset>0.</CPOffset>
+<SaveSimAsText>0</SaveSimAsText>
+<OutputAtMaxRes>0</OutputAtMaxRes>
+<MaxSimTim>3600.</MaxSimTim>
+<MassUncertainty>0.</MassUncertainty>
+<MOIUncertainty>0.</MOIUncertainty>
+<CGUncertainty>0.</CGUncertainty>
+<CdUncertainty>0.</CdUncertainty>
+<CnaUncertainty>0.</CnaUncertainty>
+<CPUncertainty>0.</CPUncertainty>
+<FinCantUncertainty>0.</FinCantUncertainty>
+<TotImpulseUncertainty>0.</TotImpulseUncertainty>
+<PropellantUncertainty>0.</PropellantUncertainty>
+<ThrustAxisUncertainty>0.</ThrustAxisUncertainty>
+<WindDirectionUncertainty>0.</WindDirectionUncertainty>
+<WindVelocityUncertainty>0.</WindVelocityUncertainty>
+<LaunchGuideAzimuthUncertainty>0.</LaunchGuideAzimuthUncertainty>
+<LaunchGuideElevationUncertainty>0.</LaunchGuideElevationUncertainty>
+<IgnitionUncertainty>0.</IgnitionUncertainty>
+<CATOUncertainty>0.</CATOUncertainty>
+<DeploymentUncertainty>0.</DeploymentUncertainty>
+<RecoveryDeviceUncertainty>0.</RecoveryDeviceUncertainty>
+<SimulationName>[E6-2] </SimulationName>
+<VelocityAtLaunchGuideEnd>15.4098</VelocityAtLaunchGuideEnd>
+<WindStartAltitude>0.</WindStartAltitude>
+<TimeToWindShear>0.</TimeToWindShear>
+<TimeToFreeFlight>0.25875</TimeToFreeFlight>
+<TimeToMaxVelocity>5.69125</TimeToMaxVelocity>
+<TimeToMaxAcceleration>0.11125</TimeToMaxAcceleration>
+<Nsims>10</Nsims>
+<CalcResolution>1</CalcResolution>
+<SamplesPerSecond>800.</SamplesPerSecond>
+<SimulationType>0</SimulationType>
+<LocationDataServerName>Earth</LocationDataServerName>
+<LocationDataServerDisplayName>Standard earth condistions.</LocationDataServerDisplayName>
+<ExecutionTime>4.078</ExecutionTime>
+<RangeAtLanding>-172.076</RangeAtLanding>
+<DirectionAtLanding>0.</DirectionAtLanding>
+<VelocityAtLanding>56.537</VelocityAtLanding>
+<XVelcoityAtLanding>-3.38254</XVelcoityAtLanding>
+<YVelocityAtLanding>-56.4357</YVelocityAtLanding>
+<ZVelocityAtLanding>0.</ZVelocityAtLanding>
+<StageSeparationTime>0,0,8.06125,0,0</StageSeparationTime>
+<StageEjectTime>-1,-1,-1,-1,-1</StageEjectTime>
+<TimeToDeployment>0,0,0,0,0</TimeToDeployment>
+<DeploymentType>32,32,32,32,32</DeploymentType>
+<SamplesPerSecondDescent>1.</SamplesPerSecondDescent>
+<CalculationFlags>1</CalculationFlags>
+<Mass0>0.233111</Mass0>
+<CG0>0.739954</CG0>
+<LaterialMOI0>0.0208295</LaterialMOI0>
+<RadialMOI0>0.000194272</RadialMOI0>
+<GUID>{b33e529e-1ada-4524-9885-7382d7cf4d64}</GUID>
+<Booster1Staging>
+<SimulationEvent>
+<PartSerialNo>0</PartSerialNo>
+<Type>0</Type>
+<DeployAltitude>0.</DeployAltitude>
+<DeplyTime>0.</DeplyTime>
+<HasDeployed>0</HasDeployed>
+<DeployedAt_Altitude>0.</DeployedAt_Altitude>
+<DeployedAt_Velocity>0.</DeployedAt_Velocity>
+<DeployedAt_Range>0.</DeployedAt_Range>
+<DeployedAt_Time>0.</DeployedAt_Time>
+<DeviceID>-1</DeviceID>
+<TestType>0,0,0</TestType>
+<TestCondition>0,0,0</TestCondition>
+<TestValueAltitude>0,0,0</TestValueAltitude>
+<TestValueDegrees>0,0,0</TestValueDegrees>
+<TestValuePressure>0,0,0</TestValuePressure>
+<TestValueMach>0,0,0</TestValueMach>
+<TestValueTime>0,0,0</TestValueTime>
+<TestValueQ>0,0,0</TestValueQ>
+</SimulationEvent>
+</Booster1Staging>
+<Booster2Staging>
+<SimulationEvent>
+<PartSerialNo>0</PartSerialNo>
+<Type>0</Type>
+<DeployAltitude>0.</DeployAltitude>
+<DeplyTime>0.</DeplyTime>
+<HasDeployed>0</HasDeployed>
+<DeployedAt_Altitude>0.</DeployedAt_Altitude>
+<DeployedAt_Velocity>0.</DeployedAt_Velocity>
+<DeployedAt_Range>0.</DeployedAt_Range>
+<DeployedAt_Time>0.</DeployedAt_Time>
+<DeviceID>-1</DeviceID>
+<TestType>0,0,0</TestType>
+<TestCondition>0,0,0</TestCondition>
+<TestValueAltitude>0,0,0</TestValueAltitude>
+<TestValueDegrees>0,0,0</TestValueDegrees>
+<TestValuePressure>0,0,0</TestValuePressure>
+<TestValueMach>0,0,0</TestValueMach>
+<TestValueTime>0,0,0</TestValueTime>
+<TestValueQ>0,0,0</TestValueQ>
+</SimulationEvent>
+</Booster2Staging>
+<SimulationEvents>
+</SimulationEvents>
+<Stage1Engines>
+</Stage1Engines>
+<Stage2Engines>
+</Stage2Engines>
+<Stage3Engines>
+<EngineSet>
+<EngineCount>1</EngineCount>
+<EngineCode>E6</EngineCode>
+<IgnitionDelay>0.</IgnitionDelay>
+<EngineMfg>Apogee</EngineMfg>
+<EngineOverhang>0.50038</EngineOverhang>
+<CasingCG>0.</CasingCG>
+<MountSerialNo>5</MountSerialNo>
+<EjectionDelay>2.</EjectionDelay>
+<RotateXaboutY>0.</RotateXaboutY>
+<RotateEngineAxisAboutX>0.</RotateEngineAxisAboutX>
+</EngineSet>
+</Stage3Engines>
+<DropItems>
+</DropItems>
+</SimulationResults>
+</SimulationResultsList>
+</RockSimDocument>
diff --git a/test/net/sf/openrocket/file/rocksim/rocksimTestRocket2.rkt b/test/net/sf/openrocket/file/rocksim/rocksimTestRocket2.rkt
new file mode 100644 (file)
index 0000000..39b3411
--- /dev/null
@@ -0,0 +1,1583 @@
+<RockSimDocument>
+<FileVersion>3</FileVersion>
+<DesignInformation>
+<RocketDesign>
+<Name>Three Stage Everything Included Rocket</Name>
+<CalculateCD>1</CalculateCD>
+<ProCalculateCD>1</ProCalculateCD>
+<ProCalculateCN>1</ProCalculateCN>
+<FixedCd>0.75</FixedCd>
+<FixedCd2>0.8</FixedCd2>
+<FixedCd3>0.81</FixedCd3>
+<FixedCd2Alone>0.95</FixedCd2Alone>
+<FixedCd3Alone>0.95</FixedCd3Alone>
+<StageCount>3</StageCount>
+<Stage3Mass>0.</Stage3Mass>
+<Stage2Mass>0.</Stage2Mass>
+<Stage1Mass>0.</Stage1Mass>
+<Stage321CG>0.</Stage321CG>
+<Stage32CG>0.</Stage32CG>
+<Stage3CG>0.</Stage3CG>
+<Stage2CGAlone>0.</Stage2CGAlone>
+<Stage1CGAlone>0.</Stage1CGAlone>
+<CPCalcFlags>1</CPCalcFlags>
+<LaunchGuideLength>914.4</LaunchGuideLength>
+<UseKnownMass>0</UseKnownMass>
+<DefaultFinish>0</DefaultFinish>
+<FinishMedium>0</FinishMedium>
+<FinishCoatCount>1</FinishCoatCount>
+<GlueType>0</GlueType>
+<CPSimFlags>1</CPSimFlags>
+<LastSerialNumber>25</LastSerialNumber>
+<DisplayFlags>7</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<BarromanXN>0,29.6333,326.159,887.03</BarromanXN>
+<BarrowmanCNa>0,2,4.93008,33.0782</BarrowmanCNa>
+<RockSimXN>0,29.6333,384.174,883.929</RockSimXN>
+<RockSimCNa>0,2,6.91103,47.1184</RockSimCNa>
+<RockSimCNa90>0,0,0,0</RockSimCNa90>
+<RockSimXN90>0,0,0,0</RockSimXN90>
+<ViewType>0</ViewType>
+<ViewStageCount>3</ViewStageCount>
+<ViewTypeEdit>0</ViewTypeEdit>
+<ViewStageCountEdit>3</ViewStageCountEdit>
+<ZoomFactor>0.</ZoomFactor>
+<ZoomFactorEdit>0.</ZoomFactorEdit>
+<ScrollPosX>0</ScrollPosX>
+<ScrollPosY>0</ScrollPosY>
+<ScrollPosXEdit>0</ScrollPosXEdit>
+<ScrollPosYEdit>0</ScrollPosYEdit>
+<ThreeDFlags>0</ThreeDFlags>
+<ThreeDFlagsEdit>0</ThreeDFlagsEdit>
+<UseModelSprite>0</UseModelSprite>
+<StaticMarginRef>0</StaticMarginRef>
+<UserRefDiameter>0.</UserRefDiameter>
+<SideMarkerHeight>10.</SideMarkerHeight>
+<SideDimensionHeight>10.</SideDimensionHeight>
+<BaseMarkerHeight>10.</BaseMarkerHeight>
+<BaseDimensionHeight>10.</BaseDimensionHeight>
+<ShowGlideCP>0</ShowGlideCP>
+<ShowGridTypeSide>0</ShowGridTypeSide>
+<ShowGridTypeBase>0</ShowGridTypeBase>
+<GridSpacing>10.</GridSpacing>
+<GridOpacity>0.15</GridOpacity>
+<GridColor>black</GridColor>
+<MaxDiaWithFins>339.43</MaxDiaWithFins>
+<MaxDiaWithoutFins>66.3</MaxDiaWithoutFins>
+<MaxLenWithFins>2104.53</MaxLenWithFins>
+<MaxLenWithoutFins>2104.53</MaxLenWithoutFins>
+<MinXExtent>0.</MinXExtent>
+<MaxXExtent>1150.33</MaxXExtent>
+<CalculatedMaxStageDia>0,66.3,66.3,66.3</CalculatedMaxStageDia>
+<CalculatedStageLen>0,296.8,954.2,2104.53</CalculatedStageLen>
+<Cd3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd3>
+<Cd32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd32>
+<Cd321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd321>
+<Cb3>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb3>
+<Cb32>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb32>
+<Cb321>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb321>
+<CNa3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa3>
+<CNa32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa32>
+<CNa321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa321>
+<CP3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP3>
+<CP32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP32>
+<CP321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP321>
+<SimulationEventList>
+</SimulationEventList>
+<Stage3Parts>
+<NoseCone>
+<PartMfg>Aerospace Speciality Products</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Nose cone</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>42.0747</CalcMass>
+<CalcCG>75.3029</CalcCG>
+<WettedSurface>0.0152945</WettedSurface>
+<PaintedSurface>0.0152945</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>BNC80S</PartNo>
+<PartDesc><![CDATA[T-80H Balsa Nose Cone "S"]]></PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>1</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>2.</BarrowmanCNa>
+<BarrowmanXN>0.0296333</BarrowmanXN>
+<RockSimCNa>2.</RockSimCNa>
+<RockSimXN>0.0296333</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>0.</Station>
+<Len>88.9</Len>
+<BaseDia>66.3</BaseDia>
+<FinishCode>0</FinishCode>
+<ShapeCode>3</ShapeCode>
+<ConstructionType>0</ConstructionType>
+<ShoulderLen>38.1</ShoulderLen>
+<WallThickness>0.</WallThickness>
+<ShapeParameter>0.</ShapeParameter>
+<ShoulderOD>64.3</ShoulderOD>
+<BaseExtensionLen>0.</BaseExtensionLen>
+<CoreDia>0.</CoreDia>
+<CoreLen>0.</CoreLen>
+<AttachedParts>
+<MassObject>
+<PartMfg>Custom</PartMfg>
+<KnownMass>20.</KnownMass>
+<Density>0.</Density>
+<Material>Custom</Material>
+<Name>Clay</Name>
+<KnownCG>17.8</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>17.8</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>0.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>2</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>17.8</Station>
+<TypeCode>0</TypeCode>
+<Len>0.</Len>
+<AttachedParts>
+</AttachedParts>
+</MassObject>
+<BodyTube>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Attachment Rod</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>6.1</Xb>
+<CalcMass>2.47301</CalcMass>
+<CalcCG>78.85</CalcCG>
+<WettedSurface>0.00684683</WettedSurface>
+<PaintedSurface>0.00684683</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>10062</PartNo>
+<PartDesc>13 mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>3</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>6.1</Station>
+<OD>13.82</OD>
+<ID>13.16</ID>
+<Len>157.7</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Plate</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>78.9</Xb>
+<CalcMass>7.86272</CalcMass>
+<CalcCG>1.585</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-(2)0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>4</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>85.</Station>
+<OD>66.</OD>
+<ID>13.82</ID>
+<Len>3.17</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>Custom</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1400.</Density>
+<Material>Carbon Fiber</Material>
+<Name>Sleeve </Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>17.5527</CalcMass>
+<CalcCG>13.85</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>5</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>2</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>136.1</Station>
+<OD>27.7</OD>
+<ID>13.82</ID>
+<Len>27.7</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>3</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Parachute>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>170.</KnownMass>
+<Density>0.006685</Density>
+<Material>Rip stop nylon</Material>
+<Name>Nose Cone Parachute</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>142.6</Xb>
+<CalcMass>15.8812</CalcMass>
+<CalcCG>34.5417</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>1</DensityType>
+<PartNo>LP-50</PartNo>
+<PartDesc>50 In. 16 lines</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>6</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>148.7</Station>
+<Dia>414.5</Dia>
+<SpillHoleDia>0.</SpillHoleDia>
+<SideCount>15</SideCount>
+<ShroudLineCount>16</ShroudLineCount>
+<Thickness>0.05</Thickness>
+<ShroudLineLen>1350.</ShroudLineLen>
+<ChuteCount>1</ChuteCount>
+<ShroudLineMassPerMM>0.00032972</ShroudLineMassPerMM>
+<ShroudLineMaterial>Carpet String (Apogee 29500)</ShroudLineMaterial>
+<DragCoefficient>0.95</DragCoefficient>
+<AttachedParts>
+</AttachedParts>
+</Parachute>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</NoseCone>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>15.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>100.</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>5.80486</CalcMass>
+<CalcCG>100.</CalcCG>
+<WettedSurface>0.0414942</WettedSurface>
+<PaintedSurface>0.0414942</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3090</PartNo>
+<PartDesc>BT-80</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>7</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>88.9</Station>
+<OD>66.04</OD>
+<ID>65.79</ID>
+<Len>200.</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>190.2</Xb>
+<CalcMass>7.65502</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>8</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>279.1</Station>
+<OD>65.02</OD>
+<ID>25.4</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>165.</Xb>
+<CalcMass>7.62626</CalcMass>
+<CalcCG>1.585</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-(2)0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>9</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>253.9</Station>
+<OD>65.</OD>
+<ID>25.4</ID>
+<Len>3.17</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<BodyTube>
+<PartMfg>Public Missiles Ltd.</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>958.705</Density>
+<Material>Kraft phenolic</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>137.9</Xb>
+<CalcMass>9.8818</CalcMass>
+<CalcCG>35.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>KS-1.1</PartNo>
+<PartDesc>KwikSwitch MMT 29mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>-1.58371</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>10</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>226.8</Station>
+<OD>32.26</OD>
+<ID>29.21</ID>
+<Len>70.</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>29.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</BodyTube>
+</Stage3Parts>
+<Stage2Parts>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>2nd Stage Tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>10.4685</CalcMass>
+<CalcCG>180.34</CalcCG>
+<WettedSurface>0.0748306</WettedSurface>
+<PaintedSurface>0.0748306</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3090</PartNo>
+<PartDesc>BT-80</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>11</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>288.9</Station>
+<OD>66.04</OD>
+<ID>65.79</ID>
+<Len>360.68</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>15.025</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Tube coupler</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>-10.</Xb>
+<CalcMass>20.465</CalcMass>
+<CalcCG>35.45</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TC-2.56</PartNo>
+<PartDesc>Tube Coupler</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>12</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>278.9</Station>
+<OD>65.79</OD>
+<ID>63.25</ID>
+<Len>70.9</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>4</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<MassObject>
+<PartMfg>Custom</PartMfg>
+<KnownMass>40.</KnownMass>
+<Density>0.</Density>
+<Material>Custom</Material>
+<Name>Electronics</Name>
+<KnownCG>138.3</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>138.3</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>0.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>13</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>427.2</Station>
+<TypeCode>0</TypeCode>
+<Len>0.</Len>
+<AttachedParts>
+</AttachedParts>
+</MassObject>
+<FinSet>
+<PartMfg>Quest</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Fin set</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>228.6</Xb>
+<CalcMass>1.32269</CalcMass>
+<CalcCG>19.05</CalcCG>
+<WettedSurface>0.0028791</WettedSurface>
+<PaintedSurface>0.0086373</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>Payloader One</PartNo>
+<PartDesc>Fin</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.0830777</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>14</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>2.93008</BarrowmanCNa>
+<BarrowmanXN>0.52856</BarrowmanXN>
+<RockSimCNa>5.49629</RockSimCNa>
+<RockSimXN>0.52856</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>517.5</Station>
+<FinCount>3</FinCount>
+<RootChord>38.1</RootChord>
+<TipChord>24.9</TipChord>
+<SemiSpan>45.7</SemiSpan>
+<MidChordLen>45.7</MidChordLen>
+<SweepDistance>6.6</SweepDistance>
+<Thickness>2.39</Thickness>
+<ShapeCode>0</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>2</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.139993</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>54.2741</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>2.83538</RockSimCNaPerFin>
+<TaperRatio>0.653543</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>302.</Xb>
+<CalcMass>7.65502</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>15</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>590.9</Station>
+<OD>65.02</OD>
+<ID>25.4</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>335.5</Xb>
+<CalcMass>7.62626</CalcMass>
+<CalcCG>1.585</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-(2)0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>16</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>624.4</Station>
+<OD>65.</OD>
+<ID>25.4</ID>
+<Len>3.17</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<BodyTube>
+<PartMfg>Public Missiles Ltd.</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>958.705</Density>
+<Material>Kraft phenolic</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>587.4</Xb>
+<CalcMass>9.8818</CalcMass>
+<CalcCG>35.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>KS-1.1</PartNo>
+<PartDesc>KwikSwitch MMT 29mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>-1.58371</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>17</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>1</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>587.4</Station>
+<OD>32.26</OD>
+<ID>29.21</ID>
+<Len>70.</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>29.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>Semroc</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Engine block</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>2.69315</CalcMass>
+<CalcCG>2.39</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TB-7</PartNo>
+<PartDesc>Thrust Block</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>18</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>587.4</Station>
+<OD>29.21</OD>
+<ID>14.61</ID>
+<Len>4.78</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>2</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</BodyTube>
+</Stage2Parts>
+<Stage1Parts>
+<Transition>
+<PartMfg>BalsaMachining.com</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Transition</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>8.62096</CalcMass>
+<CalcCG>25.1578</CalcCG>
+<WettedSurface>0.00986655</WettedSurface>
+<PaintedSurface>0.00986655</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TA6080</PartNo>
+<PartDesc>Transition T60 to T80 2.25 in long</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>19</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>-1.20451</BarrowmanCNa>
+<BarrowmanXN>0.675971</BarrowmanXN>
+<RockSimCNa>-1.20451</RockSimCNa>
+<RockSimXN>0.675971</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>649.58</Station>
+<FrontDia>66.04</FrontDia>
+<RearDia>41.4</RearDia>
+<Len>57.15</Len>
+<FinishCode>0</FinishCode>
+<FrontShoulderLen>20.</FrontShoulderLen>
+<RearShoulderLen>38.1</RearShoulderLen>
+<ConstructionType>1</ConstructionType>
+<WallThickness>3.</WallThickness>
+<FrontShoulderDia>64.77</FrontShoulderDia>
+<RearShoulderDia>41.38</RearShoulderDia>
+<CoreDia>0.</CoreDia>
+<ShapeCode>0</ShapeCode>
+<ShapeParameter>0.</ShapeParameter>
+<EquivNoseLen>153.172</EquivNoseLen>
+<EquivNoseOffset>96.022</EquivNoseOffset>
+<AttachedParts>
+</AttachedParts>
+</Transition>
+<BodyTube>
+<PartMfg>LOC/Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>33.5306</CalcMass>
+<CalcCG>209.2</CalcCG>
+<WettedSurface>0.0604643</WettedSurface>
+<PaintedSurface>0.0604643</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC BT-2.14</PartNo>
+<PartDesc>Airframe tube</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>20</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>706.73</Station>
+<OD>46.</OD>
+<ID>45.</ID>
+<Len>418.4</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<FinSet>
+<PartMfg>Quest</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Elliptical Fins</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>69.7</Xb>
+<CalcMass>36.2048</CalcMass>
+<CalcCG>46.</CalcCG>
+<WettedSurface>0.00676907</WettedSurface>
+<PaintedSurface>0.0203072</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>-0.519061</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>21</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>3.64017</BarrowmanCNa>
+<BarrowmanXN>0.802926</BarrowmanXN>
+<RockSimCNa>6.19583</RockSimCNa>
+<RockSimXN>0.802926</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>776.43</Station>
+<FinCount>3</FinCount>
+<RootChord>92.</RootChord>
+<TipChord>46.</TipChord>
+<SemiSpan>46.9</SemiSpan>
+<MidChordLen>46.9</MidChordLen>
+<SweepDistance>33.49</SweepDistance>
+<Thickness>3.18</Thickness>
+<ShapeCode>1</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>0</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.349066</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>43.8444</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>3.30201</RockSimCNaPerFin>
+<TaperRatio>0.5</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+<CustomFinSet>
+<PartMfg>Public Missiles</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1905.24</Density>
+<Material>G10 fiberglass</Material>
+<Name>Custom Fins</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>241.7</Xb>
+<CalcMass>256.292</CalcMass>
+<CalcCG>78.9922</CalcCG>
+<WettedSurface>0.0355266</WettedSurface>
+<PaintedSurface>0.10658</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>FIN-C-02</PartNo>
+<PartDesc>Fins</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.357967</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>22</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>25.7124</BarrowmanCNa>
+<BarrowmanXN>0.996591</BarrowmanXN>
+<RockSimCNa>34.6308</RockSimCNa>
+<RockSimXN>0.996926</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>948.43</Station>
+<FinCount>3</FinCount>
+<RootChord>152.4</RootChord>
+<TipChord>83.83</TipChord>
+<SemiSpan>146.72</SemiSpan>
+<MidChordLen>146.81</MidChordLen>
+<SweepDistance>39.42</SweepDistance>
+<Thickness>2.38</Thickness>
+<ShapeCode>2</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>2</TipShapeCode>
+<TabLength>101.6</TabLength>
+<TabDepth>10.6</TabDepth>
+<TabOffset>35.6</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>89.2598</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>19.9941</RockSimCNaPerFin>
+<TaperRatio>0.550066</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AverageChord>121.07</AverageChord>
+<EffectiveTipChord>83.8257</EffectiveTipChord>
+<PointList>152.4,0|126.202,146.715|36.455,146.715|0,0|</PointList>
+<AutoCalcGridStepX>0,0,0,0,0,0,0</AutoCalcGridStepX>
+<GridStepCountX>10,10,10,10,10,10,10</GridStepCountX>
+<UseAbsoluteGridStepsX>0,0,0,0,0,0,0</UseAbsoluteGridStepsX>
+<GridStepSizeX>0.5,10,0.5,0.5,0.00018939,0.001,1</GridStepSizeX>
+<SnapToSizeX>0.25,5,0.1,0.1,0.00018939,0.001,1</SnapToSizeX>
+<AutoCalcGridStepY>0,0,0,0,0,0,0</AutoCalcGridStepY>
+<GridStepCountY>10,10,10,10,10,10,10</GridStepCountY>
+<UseAbsoluteGridStepsY>0,0,0,0,0,0,0</UseAbsoluteGridStepsY>
+<GridStepSizeY>0.5,10,0.5,0.5,0.00018939,0.001,1</GridStepSizeY>
+<SnapToSizeY>0.25,5,0.1,0.1,0.00018939,0.001,1</SnapToSizeY>
+<AttachedParts>
+</AttachedParts>
+</CustomFinSet>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>379.5</Xb>
+<CalcMass>2.55395</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC FCR-1.52-1.14</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>23</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>1086.23</Station>
+<OD>45.</OD>
+<ID>24.79</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>272.</Xb>
+<CalcMass>2.55395</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC FCR-1.52-1.14</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>24</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>978.73</Station>
+<OD>45.</OD>
+<ID>24.79</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>259.7</Xb>
+<CalcMass>5.22902</CalcMass>
+<CalcCG>91.95</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3086</PartNo>
+<PartDesc>BT-50</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>25</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>966.43</Station>
+<OD>24.79</OD>
+<ID>24.13</ID>
+<Len>183.9</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>24.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</BodyTube>
+</Stage1Parts>
+<SideViewDims>
+</SideViewDims>
+<BaseViewDims>
+</BaseViewDims>
+<VertViewDims>
+</VertViewDims>
+</RocketDesign>
+</DesignInformation>
+<SimulationResultsList>
+</SimulationResultsList>
+</RockSimDocument>
diff --git a/test/net/sf/openrocket/file/rocksim/rocksimTestRocket3.rkt b/test/net/sf/openrocket/file/rocksim/rocksimTestRocket3.rkt
new file mode 100644 (file)
index 0000000..a7c46da
--- /dev/null
@@ -0,0 +1,1961 @@
+<RockSimDocument>
+<FileVersion>3</FileVersion>
+<DesignInformation>
+<RocketDesign>
+<Name>Three Stage Everything Included Rocket - Override Total Mass/CG</Name>
+<CalculateCD>1</CalculateCD>
+<ProCalculateCD>1</ProCalculateCD>
+<ProCalculateCN>1</ProCalculateCN>
+<FixedCd>0.75</FixedCd>
+<FixedCd2>0.8</FixedCd2>
+<FixedCd3>0.81</FixedCd3>
+<FixedCd2Alone>0.95</FixedCd2Alone>
+<FixedCd3Alone>0.95</FixedCd3Alone>
+<StageCount>3</StageCount>
+<Stage3Mass>185.</Stage3Mass>
+<Stage2Mass>210.</Stage2Mass>
+<Stage1Mass>330.</Stage1Mass>
+<Stage321CG>0.</Stage321CG>
+<Stage32CG>0.</Stage32CG>
+<Stage3CG>300.</Stage3CG>
+<Stage2CGAlone>400.</Stage2CGAlone>
+<Stage1CGAlone>500.</Stage1CGAlone>
+<CPCalcFlags>1</CPCalcFlags>
+<LaunchGuideLength>914.4</LaunchGuideLength>
+<UseKnownMass>0</UseKnownMass>
+<DefaultFinish>0</DefaultFinish>
+<FinishMedium>0</FinishMedium>
+<FinishCoatCount>1</FinishCoatCount>
+<GlueType>0</GlueType>
+<CPSimFlags>1</CPSimFlags>
+<LastSerialNumber>32</LastSerialNumber>
+<DisplayFlags>7</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<BarromanXN>0,29.6333,327.236,966.855</BarromanXN>
+<BarrowmanCNa>0,2,4.95647,83.562</BarrowmanCNa>
+<RockSimXN>0,29.6333,385.082,953.76</RockSimXN>
+<RockSimCNa>0,2,6.95476,97.0629</RockSimCNa>
+<RockSimCNa90>0,0,0,0</RockSimCNa90>
+<RockSimXN90>0,0,0,0</RockSimXN90>
+<ViewType>0</ViewType>
+<ViewStageCount>3</ViewStageCount>
+<ViewTypeEdit>0</ViewTypeEdit>
+<ViewStageCountEdit>3</ViewStageCountEdit>
+<ZoomFactor>0.</ZoomFactor>
+<ZoomFactorEdit>0.</ZoomFactorEdit>
+<ScrollPosX>0</ScrollPosX>
+<ScrollPosY>0</ScrollPosY>
+<ScrollPosXEdit>0</ScrollPosXEdit>
+<ScrollPosYEdit>0</ScrollPosYEdit>
+<ThreeDFlags>0</ThreeDFlags>
+<ThreeDFlagsEdit>0</ThreeDFlagsEdit>
+<UseModelSprite>0</UseModelSprite>
+<StaticMarginRef>0</StaticMarginRef>
+<UserRefDiameter>0.</UserRefDiameter>
+<SideMarkerHeight>10.</SideMarkerHeight>
+<SideDimensionHeight>10.</SideDimensionHeight>
+<BaseMarkerHeight>10.</BaseMarkerHeight>
+<BaseDimensionHeight>10.</BaseDimensionHeight>
+<ShowGlideCP>0</ShowGlideCP>
+<ShowGridTypeSide>0</ShowGridTypeSide>
+<ShowGridTypeBase>0</ShowGridTypeBase>
+<GridSpacing>10.</GridSpacing>
+<GridOpacity>0.15</GridOpacity>
+<GridColor>black</GridColor>
+<MaxDiaWithFins>334.83</MaxDiaWithFins>
+<MaxDiaWithoutFins>66.</MaxDiaWithoutFins>
+<MaxLenWithFins>2155.23</MaxLenWithFins>
+<MaxLenWithoutFins>2155.23</MaxLenWithoutFins>
+<MinXExtent>0.</MinXExtent>
+<MaxXExtent>1150.33</MaxXExtent>
+<CalculatedMaxStageDia>0,66,66,66</CalculatedMaxStageDia>
+<CalculatedStageLen>0,347.5,1004.9,2155.23</CalculatedStageLen>
+<Cd3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd3>
+<Cd32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd32>
+<Cd321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cd321>
+<Cb3>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb3>
+<Cb32>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb32>
+<Cb321>
+<PolyData  useXYOnly="1" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</Cb321>
+<CNa3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa3>
+<CNa32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa32>
+<CNa321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CNa321>
+<CP3>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP3>
+<CP32>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP32>
+<CP321>
+<PolyData  useXYOnly="0" useSmoothCurveEvaluation="0" count="0">
+<X-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</X-data>
+<A-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</A-data>
+<B-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</B-data>
+<C-data>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</C-data>
+</PolyData>
+</CP321>
+<SimulationEventList>
+</SimulationEventList>
+<Stage3Parts>
+<NoseCone>
+<PartMfg>Aerospace Speciality Products</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Nose cone</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>42.6368</CalcMass>
+<CalcCG>76.0242</CalcCG>
+<WettedSurface>0.0152192</WettedSurface>
+<PaintedSurface>0.0152192</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>BNC80S</PartNo>
+<PartDesc><![CDATA[T-80H Balsa Nose Cone "S"]]></PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>1</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>2.</BarrowmanCNa>
+<BarrowmanXN>0.0296333</BarrowmanXN>
+<RockSimCNa>2.</RockSimCNa>
+<RockSimXN>0.0296333</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>0.</Station>
+<Len>88.9</Len>
+<BaseDia>66.</BaseDia>
+<FinishCode>0</FinishCode>
+<ShapeCode>3</ShapeCode>
+<ConstructionType>0</ConstructionType>
+<ShoulderLen>38.1</ShoulderLen>
+<WallThickness>0.</WallThickness>
+<ShapeParameter>0.</ShapeParameter>
+<ShoulderOD>65.9</ShoulderOD>
+<BaseExtensionLen>0.</BaseExtensionLen>
+<CoreDia>0.</CoreDia>
+<CoreLen>0.</CoreLen>
+<AttachedParts>
+<MassObject>
+<PartMfg>Custom</PartMfg>
+<KnownMass>20.</KnownMass>
+<Density>0.</Density>
+<Material>Custom</Material>
+<Name>Clay</Name>
+<KnownCG>17.8</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>17.8</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>0.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>2</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>17.8</Station>
+<TypeCode>0</TypeCode>
+<Len>0.</Len>
+<AttachedParts>
+</AttachedParts>
+</MassObject>
+<BodyTube>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Attachment Rod</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>6.1</Xb>
+<CalcMass>2.47301</CalcMass>
+<CalcCG>78.85</CalcCG>
+<WettedSurface>0.00684683</WettedSurface>
+<PaintedSurface>0.00684683</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>10062</PartNo>
+<PartDesc>13 mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>3</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>6.1</Station>
+<OD>13.82</OD>
+<ID>13.16</ID>
+<Len>157.7</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Plate</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>78.9</Xb>
+<CalcMass>7.86272</CalcMass>
+<CalcCG>1.585</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-(2)0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>4</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>85.</Station>
+<OD>66.</OD>
+<ID>13.82</ID>
+<Len>3.17</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>Custom</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1400.</Density>
+<Material>Carbon Fiber</Material>
+<Name>Sleeve </Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>17.5527</CalcMass>
+<CalcCG>13.85</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>5</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>2</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>136.1</Station>
+<OD>27.7</OD>
+<ID>13.82</ID>
+<Len>27.7</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>3</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Parachute>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>170.</KnownMass>
+<Density>0.006685</Density>
+<Material>Rip stop nylon</Material>
+<Name>Nose Cone Parachute</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>142.6</Xb>
+<CalcMass>15.8812</CalcMass>
+<CalcCG>34.5417</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>1</DensityType>
+<PartNo>LP-50</PartNo>
+<PartDesc>50 In. 16 lines</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>6</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>148.7</Station>
+<Dia>414.5</Dia>
+<SpillHoleDia>0.</SpillHoleDia>
+<SideCount>15</SideCount>
+<ShroudLineCount>16</ShroudLineCount>
+<Thickness>0.05</Thickness>
+<ShroudLineLen>1350.</ShroudLineLen>
+<ChuteCount>1</ChuteCount>
+<ShroudLineMassPerMM>0.00032972</ShroudLineMassPerMM>
+<ShroudLineMaterial>Carpet String (Apogee 29500)</ShroudLineMaterial>
+<DragCoefficient>0.95</DragCoefficient>
+<AttachedParts>
+</AttachedParts>
+</Parachute>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</NoseCone>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>15.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>100.</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>5.805</CalcMass>
+<CalcCG>100.</CalcCG>
+<WettedSurface>0.0414942</WettedSurface>
+<PaintedSurface>0.0414942</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3090</PartNo>
+<PartDesc>BT-80</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>7</SerialNo>
+<DisplayFlags>1</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>88.9</Station>
+<OD>66.</OD>
+<ID>65.79</ID>
+<Len>200.</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>190.2</Xb>
+<CalcMass>7.65502</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>8</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>279.1</Station>
+<OD>65.02</OD>
+<ID>25.4</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>165.</Xb>
+<CalcMass>7.62626</CalcMass>
+<CalcCG>1.585</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-(2)0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>9</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>253.9</Station>
+<OD>65.</OD>
+<ID>25.4</ID>
+<Len>3.17</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<BodyTube>
+<PartMfg>Public Missiles Ltd.</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>958.705</Density>
+<Material>Kraft phenolic</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>137.9</Xb>
+<CalcMass>9.8818</CalcMass>
+<CalcCG>35.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>KS-1.1</PartNo>
+<PartDesc>KwikSwitch MMT 29mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>-1.58371</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>10</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>226.8</Station>
+<OD>32.26</OD>
+<ID>29.21</ID>
+<Len>70.</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>29.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+<LaunchLug>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Launch lug</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>77.2</Xb>
+<CalcMass>1.11942</CalcMass>
+<CalcCG>38.1</CalcCG>
+<WettedSurface>0.00374518</WettedSurface>
+<PaintedSurface>0.00199411</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>13056</PartNo>
+<PartDesc><![CDATA[1/4" X 3]]></PartDesc>
+<RadialLoc>37.185</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>26</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>166.1</Station>
+<OD>8.33</OD>
+<ID>7.26</ID>
+<Len>76.2</Len>
+<FinishCode>0</FinishCode>
+<AttachedParts>
+</AttachedParts>
+</LaunchLug>
+<ExternalPod>
+<PartMfg>Custom</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>0.</Density>
+<Name>Pod</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>200.</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>0.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>36.175</RadialLoc>
+<RadialAngle>-1.50735</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>29</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>288.9</Station>
+<Detachable>1</Detachable>
+<AutoCalcRadialDistance>1</AutoCalcRadialDistance>
+<AutoCalcRadialAngle>1</AutoCalcRadialAngle>
+<AttachedParts>
+<BodyTube>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>958.705</Density>
+<Material>Kraft phenolic</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>0.400397</CalcMass>
+<CalcCG>29.3</CalcCG>
+<WettedSurface>0.00116902</WettedSurface>
+<PaintedSurface>0.00116902</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>9601</PartNo>
+<PartDesc>6 mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>30</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>288.9</Station>
+<OD>6.35</OD>
+<ID>5.59</ID>
+<Len>58.6</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+</AttachedParts>
+</ExternalPod>
+</AttachedParts>
+</BodyTube>
+</Stage3Parts>
+<Stage2Parts>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>2nd Stage Tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>10.468</CalcMass>
+<CalcCG>180.34</CalcCG>
+<WettedSurface>0.0748306</WettedSurface>
+<PaintedSurface>0.0748306</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3090</PartNo>
+<PartDesc>BT-80</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>11</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>288.9</Station>
+<OD>66.</OD>
+<ID>65.79</ID>
+<Len>360.68</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>15.025</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Tube coupler</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>-10.</Xb>
+<CalcMass>20.465</CalcMass>
+<CalcCG>35.45</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TC-2.56</PartNo>
+<PartDesc>Tube Coupler</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>12</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>278.9</Station>
+<OD>65.79</OD>
+<ID>63.25</ID>
+<Len>70.9</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>4</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<MassObject>
+<PartMfg>Custom</PartMfg>
+<KnownMass>40.</KnownMass>
+<Density>0.</Density>
+<Material>Custom</Material>
+<Name>Electronics</Name>
+<KnownCG>138.3</KnownCG>
+<UseKnownCG>1</UseKnownCG>
+<Xb>138.3</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>0.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>13</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>427.2</Station>
+<TypeCode>0</TypeCode>
+<Len>0.</Len>
+<AttachedParts>
+</AttachedParts>
+</MassObject>
+<FinSet>
+<PartMfg>Quest</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Fin set</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>228.6</Xb>
+<CalcMass>1.32269</CalcMass>
+<CalcCG>19.05</CalcCG>
+<WettedSurface>0.0028791</WettedSurface>
+<PaintedSurface>0.0086373</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>Payloader One</PartNo>
+<PartDesc>Fin</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.0830777</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>14</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>2.95647</BarrowmanCNa>
+<BarrowmanXN>0.52856</BarrowmanXN>
+<RockSimCNa>5.54523</RockSimCNa>
+<RockSimXN>0.52856</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>517.5</Station>
+<FinCount>3</FinCount>
+<RootChord>38.1</RootChord>
+<TipChord>24.9</TipChord>
+<SemiSpan>45.7</SemiSpan>
+<MidChordLen>45.7</MidChordLen>
+<SweepDistance>6.6</SweepDistance>
+<Thickness>2.39</Thickness>
+<ShapeCode>0</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>2</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.139993</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>54.2541</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>2.86063</RockSimCNaPerFin>
+<TaperRatio>0.653543</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>302.</Xb>
+<CalcMass>7.65502</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>15</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>590.9</Station>
+<OD>65.02</OD>
+<ID>25.4</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>335.5</Xb>
+<CalcMass>7.62626</CalcMass>
+<CalcCG>1.585</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC CR-2.56-(2)0.95</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>16</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>624.4</Station>
+<OD>65.</OD>
+<ID>25.4</ID>
+<Len>3.17</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>0</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<BodyTube>
+<PartMfg>Public Missiles Ltd.</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>958.705</Density>
+<Material>Kraft phenolic</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>587.4</Xb>
+<CalcMass>9.8818</CalcMass>
+<CalcCG>35.</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>KS-1.1</PartNo>
+<PartDesc>KwikSwitch MMT 29mm</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>-1.58371</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>17</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>1</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>587.4</Station>
+<OD>32.26</OD>
+<ID>29.21</ID>
+<Len>70.</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>29.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<Ring>
+<PartMfg>Semroc</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Engine block</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>2.69315</CalcMass>
+<CalcCG>2.39</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TB-7</PartNo>
+<PartDesc>Thrust Block</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>18</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>587.4</Station>
+<OD>29.21</OD>
+<ID>14.61</ID>
+<Len>4.78</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>2</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+</AttachedParts>
+</BodyTube>
+<LaunchLug>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Launch lug</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>265.8</Xb>
+<CalcMass>1.11942</CalcMass>
+<CalcCG>38.1</CalcCG>
+<WettedSurface>0.00374518</WettedSurface>
+<PaintedSurface>0.00199411</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>13056</PartNo>
+<PartDesc><![CDATA[1/4" X 3]]></PartDesc>
+<RadialLoc>37.185</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>27</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>554.7</Station>
+<OD>8.33</OD>
+<ID>7.26</ID>
+<Len>76.2</Len>
+<FinishCode>0</FinishCode>
+<AttachedParts>
+</AttachedParts>
+</LaunchLug>
+</AttachedParts>
+</BodyTube>
+</Stage2Parts>
+<Stage1Parts>
+<Transition>
+<PartMfg>BalsaMachining.com</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>128.148</Density>
+<Material>Balsa</Material>
+<Name>Transition</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>8.61936</CalcMass>
+<CalcCG>25.1551</CalcCG>
+<WettedSurface>0.0098623</WettedSurface>
+<PaintedSurface>0.0098623</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>TA6080</PartNo>
+<PartDesc>Transition T60 to T80 2.25 in long</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>19</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>-1.213</BarrowmanCNa>
+<BarrowmanXN>0.675973</BarrowmanXN>
+<RockSimCNa>-1.213</RockSimCNa>
+<RockSimXN>0.675973</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>649.58</Station>
+<FrontDia>66.</FrontDia>
+<RearDia>41.4</RearDia>
+<Len>57.15</Len>
+<FinishCode>0</FinishCode>
+<FrontShoulderLen>20.</FrontShoulderLen>
+<RearShoulderLen>38.1</RearShoulderLen>
+<ConstructionType>1</ConstructionType>
+<WallThickness>3.</WallThickness>
+<FrontShoulderDia>64.77</FrontShoulderDia>
+<RearShoulderDia>41.38</RearShoulderDia>
+<CoreDia>0.</CoreDia>
+<ShapeCode>0</ShapeCode>
+<ShapeParameter>0.</ShapeParameter>
+<EquivNoseLen>153.339</EquivNoseLen>
+<EquivNoseOffset>96.1895</EquivNoseOffset>
+<AttachedParts>
+</AttachedParts>
+</Transition>
+<BodyTube>
+<PartMfg>LOC/Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>0.</CalcMass>
+<CalcCG>nan.</CalcCG>
+<WettedSurface>0.0544179</WettedSurface>
+<PaintedSurface>0.0544179</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC BT-2.14</PartNo>
+<PartDesc>Airframe tube</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>20</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(54,250,21)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>706.73</Station>
+<OD>41.4</OD>
+<ID>41.</ID>
+<Len>418.4</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>0</IsMotorMount>
+<MotorDia>0.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>0</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+<FinSet>
+<PartMfg>Quest</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Elliptical Fins</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>69.7</Xb>
+<CalcMass>36.2048</CalcMass>
+<CalcCG>46.</CalcCG>
+<WettedSurface>0.00676907</WettedSurface>
+<PaintedSurface>0.0203072</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>-0.519061</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>21</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>3.61024</BarrowmanCNa>
+<BarrowmanXN>0.802926</BarrowmanXN>
+<RockSimCNa>6.03948</RockSimCNa>
+<RockSimXN>0.802926</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>776.43</Station>
+<FinCount>3</FinCount>
+<RootChord>92.</RootChord>
+<TipChord>46.</TipChord>
+<SemiSpan>46.9</SemiSpan>
+<MidChordLen>46.9</MidChordLen>
+<SweepDistance>33.49</SweepDistance>
+<Thickness>3.18</Thickness>
+<ShapeCode>1</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>0</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.349066</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>41.5444</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>3.21868</RockSimCNaPerFin>
+<TaperRatio>0.5</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AttachedParts>
+</AttachedParts>
+</FinSet>
+<CustomFinSet>
+<PartMfg>Public Missiles</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1905.24</Density>
+<Material>G10 fiberglass</Material>
+<Name>Custom Fins</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>241.7</Xb>
+<CalcMass>256.292</CalcMass>
+<CalcCG>78.9922</CalcCG>
+<WettedSurface>0.0355266</WettedSurface>
+<PaintedSurface>0.10658</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>FIN-C-02</PartNo>
+<PartDesc>Fins</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.357967</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>22</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>25.7037</BarrowmanCNa>
+<BarrowmanXN>0.996526</BarrowmanXN>
+<RockSimCNa>34.1865</RockSimCNa>
+<RockSimXN>0.996822</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>948.43</Station>
+<FinCount>3</FinCount>
+<RootChord>152.4</RootChord>
+<TipChord>84.53</TipChord>
+<SemiSpan>146.72</SemiSpan>
+<MidChordLen>146.81</MidChordLen>
+<SweepDistance>39.07</SweepDistance>
+<Thickness>2.38</Thickness>
+<ShapeCode>2</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>2</TipShapeCode>
+<TabLength>101.6</TabLength>
+<TabDepth>10.6</TabDepth>
+<TabOffset>35.6</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>87.0529</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>19.7376</RockSimCNaPerFin>
+<TaperRatio>0.554659</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<AverageChord>121.39</AverageChord>
+<EffectiveTipChord>84.5261</EffectiveTipChord>
+<PointList>152.4,0|126.202,146.715|36.455,146.715|0,0|</PointList>
+<AutoCalcGridStepX>0,0,0,0,0,0,0</AutoCalcGridStepX>
+<GridStepCountX>10,10,10,10,10,10,10</GridStepCountX>
+<UseAbsoluteGridStepsX>0,0,0,0,0,0,0</UseAbsoluteGridStepsX>
+<GridStepSizeX>0.5,10,0.5,0.5,0.00018939,0.001,1</GridStepSizeX>
+<SnapToSizeX>0.25,5,0.1,0.1,0.00018939,0.001,1</SnapToSizeX>
+<AutoCalcGridStepY>0,0,0,0,0,0,0</AutoCalcGridStepY>
+<GridStepCountY>10,10,10,10,10,10,10</GridStepCountY>
+<UseAbsoluteGridStepsY>0,0,0,0,0,0,0</UseAbsoluteGridStepsY>
+<GridStepSizeY>0.5,10,0.5,0.5,0.00018939,0.001,1</GridStepSizeY>
+<SnapToSizeY>0.25,5,0.1,0.1,0.00018939,0.001,1</SnapToSizeY>
+<AttachedParts>
+</AttachedParts>
+</CustomFinSet>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>379.5</Xb>
+<CalcMass>1.99074</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC FCR-1.52-1.14</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>23</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>1086.23</Station>
+<OD>41.4</OD>
+<ID>24.79</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<Ring>
+<PartMfg>LOC Precision</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>724.996</Density>
+<Material>Aircraft plywood (LOC)</Material>
+<Name>Centering ring</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>272.</Xb>
+<CalcMass>1.99074</CalcMass>
+<CalcCG>1.59</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>LOC FCR-1.52-1.14</PartNo>
+<PartDesc>Centering Ring</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>24</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>978.73</Station>
+<OD>41.4</OD>
+<ID>24.79</ID>
+<Len>3.18</Len>
+<FinishCode>0</FinishCode>
+<UsageCode>0</UsageCode>
+<AutoSize>1</AutoSize>
+<AttachedParts>
+</AttachedParts>
+</Ring>
+<BodyTube>
+<PartMfg>Estes</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Body tube</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>259.7</Xb>
+<CalcMass>5.22902</CalcMass>
+<CalcCG>91.95</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>EST 3086</PartNo>
+<PartDesc>BT-50</PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>rgb(0,0,250)</AbientColor>
+<DiffuseColor>rgb(0,0,250)</DiffuseColor>
+<SpecularColor>rgb(255,255,255)</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>25</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>rgb(0,0,250)</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>966.43</Station>
+<OD>24.79</OD>
+<ID>24.13</ID>
+<Len>183.9</Len>
+<FinishCode>0</FinishCode>
+<IsMotorMount>1</IsMotorMount>
+<MotorDia>24.</MotorDia>
+<EngineOverhang>0.5</EngineOverhang>
+<FrontExtension>0.</FrontExtension>
+<RearExtension>0.</RearExtension>
+<IsInsideTube>1</IsInsideTube>
+<isStrapOnTube>0</isStrapOnTube>
+<AttachedParts>
+</AttachedParts>
+</BodyTube>
+<TubeFinSet>
+<PartMfg>Custom</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1121.29</Density>
+<Material>Paper</Material>
+<Name>Tube fins</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>12.6878</CalcMass>
+<CalcCG>24.79</CalcCG>
+<WettedSurface>0.0688063</WettedSurface>
+<PaintedSurface>0.0688063</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>35.395</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>28</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>10.866</BarrowmanCNa>
+<BarrowmanXN>0.707815</BarrowmanXN>
+<RockSimCNa>10.866</RockSimCNa>
+<RockSimXN>0.707815</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>706.73</Station>
+<OD>24.79</OD>
+<ID>24.13</ID>
+<Len>49.58</Len>
+<FinishCode>0</FinishCode>
+<TubeCount>9</TubeCount>
+<MinTubeAngle>0.715549</MinTubeAngle>
+<MaxTubesAllowed>9</MaxTubesAllowed>
+<AttachedParts>
+</AttachedParts>
+</TubeFinSet>
+<RingTail>
+<PartMfg>Custom</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>688.794</Density>
+<Material>Cardboard</Material>
+<Name>Ringtail</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>0.</Xb>
+<CalcMass>2.93707</CalcMass>
+<CalcCG>10.</CalcCG>
+<WettedSurface>0.00474229</WettedSurface>
+<PaintedSurface>0.00444249</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>31</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>2</LocationMode>
+<Color>rgb(255,9,18)</Color>
+<BarrowmanCNa>39.6386</BarrowmanCNa>
+<BarrowmanXN>1.10463</BarrowmanXN>
+<RockSimCNa>39.6386</RockSimCNa>
+<RockSimXN>1.10463</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>1105.13</Station>
+<FinCount>3</FinCount>
+<RootChord>20.</RootChord>
+<TipChord>20.</TipChord>
+<SemiSpan>7.495</SemiSpan>
+<MidChordLen>7.495</MidChordLen>
+<SweepDistance>0.</SweepDistance>
+<Thickness>3.</Thickness>
+<ShapeCode>0</ShapeCode>
+<FinishCode>0</FinishCode>
+<TipShapeCode>0</TipShapeCode>
+<TabLength>0.</TabLength>
+<TabDepth>0.</TabDepth>
+<TabOffset>0.</TabOffset>
+<SweepMode>1</SweepMode>
+<SweepAngle>0.</SweepAngle>
+<RockSimXNPerFin>0.</RockSimXNPerFin>
+<RockSimRadialXNPerFin>0.</RockSimRadialXNPerFin>
+<RockSimCNaPerFin>0.</RockSimCNaPerFin>
+<TaperRatio>0.</TaperRatio>
+<CantAngle>0.</CantAngle>
+<CantPivotPoint>0.</CantPivotPoint>
+<OD>56.39</OD>
+<ID>55.37</ID>
+<Len>20.</Len>
+<TubeDensity>1121.29</TubeDensity>
+<TubeDensityType>0</TubeDensityType>
+<TubeMaterial>Paper</TubeMaterial>
+<AttachedParts>
+</AttachedParts>
+</RingTail>
+<Streamer>
+<PartMfg>Apogee</PartMfg>
+<KnownMass>0.</KnownMass>
+<Density>1309.</Density>
+<Material>Mylar</Material>
+<Name>Streamer</Name>
+<KnownCG>0.</KnownCG>
+<UseKnownCG>0</UseKnownCG>
+<Xb>149.4</Xb>
+<CalcMass>5.67514</CalcMass>
+<CalcCG>50.8</CalcCG>
+<WettedSurface>0.</WettedSurface>
+<PaintedSurface>0.</PaintedSurface>
+<GlueJointLength>0.</GlueJointLength>
+<DensityType>0</DensityType>
+<PartNo>29006</PartNo>
+<PartDesc><![CDATA[4" Wide Mylar]]></PartDesc>
+<RadialLoc>0.</RadialLoc>
+<RadialAngle>0.</RadialAngle>
+<Texture>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)</Texture>
+<Opacity>1.</Opacity>
+<Specular>0.</Specular>
+<SpecularPower>1.</SpecularPower>
+<Ambient>0.</Ambient>
+<Diffuse>1.</Diffuse>
+<AbientColor>blue</AbientColor>
+<DiffuseColor>blue</DiffuseColor>
+<SpecularColor>white</SpecularColor>
+<UseSingleColor>1</UseSingleColor>
+<SerialNo>32</SerialNo>
+<DisplayFlags>0</DisplayFlags>
+<MetricsFlags>0</MetricsFlags>
+<LocationMode>0</LocationMode>
+<Color>blue</Color>
+<BarrowmanCNa>0.</BarrowmanCNa>
+<BarrowmanXN>0.</BarrowmanXN>
+<RockSimCNa>0.</RockSimCNa>
+<RockSimXN>0.</RockSimXN>
+<SimpleColorModel>1</SimpleColorModel>
+<ProduceTemplate>0</ProduceTemplate>
+<TemplateUnits>8</TemplateUnits>
+<Removed>0</Removed>
+<Station>856.13</Station>
+<Len>1422.4</Len>
+<Width>101.6</Width>
+<Thickness>0.03</Thickness>
+<StreamerCount>1</StreamerCount>
+<DragCoefficient>0.127</DragCoefficient>
+<IsFolded>0</IsFolded>
+<AutoCalcCd>1</AutoCalcCd>
+<AttachedParts>
+</AttachedParts>
+</Streamer>
+</AttachedParts>
+</BodyTube>
+</Stage1Parts>
+<SideViewDims>
+</SideViewDims>
+<BaseViewDims>
+</BaseViewDims>
+<VertViewDims>
+</VertViewDims>
+</RocketDesign>
+</DesignInformation>
+<SimulationResultsList>
+</SimulationResultsList>
+</RockSimDocument>
index f47c4f3e4bd082af1c7170dbf175f36742e1ddcb..1260fa5abad097ea4e958f5d0d66ec2cae82c629 100644 (file)
@@ -51,7 +51,7 @@ public class LoggingTest {
        }
        
        public static void main(String[] args) {
-               StandardOutputLogger logger = new StandardOutputLogger();
+               PrintStreamLogger logger = new PrintStreamLogger();
                
                logger.debug("a debug message");
                logger.info("an info message");