Added ENG export
authorBill Kuker <bkuker@billkuker.com>
Wed, 9 Sep 2009 01:50:59 +0000 (01:50 +0000)
committerBill Kuker <bkuker@billkuker.com>
Wed, 9 Sep 2009 01:50:59 +0000 (01:50 +0000)
src/com/billkuker/rocketry/motorsim/GraphSimplifier.java [new file with mode: 0644]
src/com/billkuker/rocketry/motorsim/io/ENGExporter.java [new file with mode: 0644]
src/com/billkuker/rocketry/motorsim/visual/workbench/MotorWorkbench.java

diff --git a/src/com/billkuker/rocketry/motorsim/GraphSimplifier.java b/src/com/billkuker/rocketry/motorsim/GraphSimplifier.java
new file mode 100644 (file)
index 0000000..921a36d
--- /dev/null
@@ -0,0 +1,127 @@
+package com.billkuker.rocketry.motorsim;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.measure.quantity.Area;
+import javax.measure.quantity.Length;
+import javax.measure.quantity.Quantity;
+import javax.measure.unit.SI;
+
+import org.jscience.physics.amount.Amount;
+
+import com.billkuker.rocketry.motorsim.grain.CoredCylindricalGrain;
+import com.billkuker.rocketry.motorsim.visual.Chart;
+
+public class GraphSimplifier<X extends Quantity, Y extends Quantity> {
+       Method f;
+
+       private class Entry {
+               Amount<X> x;
+               Amount<Y> y;
+       }
+
+       private Map<Amount<X>, Amount<Y>> out = new HashMap<Amount<X>, Amount<Y>>();
+       private List<Amount<X>> outDomain = new Vector<Amount<X>>();
+
+       public Amount<Y> value(Amount<X> x) {
+               return out.get(x);
+       }
+
+       public Iterable<Amount<X>> getDomain() {
+               return outDomain;
+       }
+
+       public GraphSimplifier(Object source, String method,
+                       Iterator<Amount<X>> domain) throws NoSuchMethodException,
+                       IllegalArgumentException, IllegalAccessException,
+                       InvocationTargetException {
+               f = source.getClass().getMethod(method, Amount.class);
+
+               Vector<Entry> oldEntries = new Vector<Entry>();
+
+               Amount<Y> max = null, min = null, range = null, err = null;
+               while (domain.hasNext()) {
+                       Amount<X> x = domain.next();
+                       Amount<Y> y = (Amount<Y>) f.invoke(source, x);
+                       Entry e = new Entry();
+                       e.x = x;
+                       e.y = y;
+                       oldEntries.add(e);
+
+                       if (max == null || max.isLessThan(y))
+                               max = y;
+                       if (min == null || min.isGreaterThan(y))
+                               min = y;
+               }
+               range = max.minus(min).abs();
+               err = range.divide(50);
+
+               for (int j = 0; j < 10 && oldEntries.size() > 30; j++) {
+                       Vector<Entry> newEntries = new Vector<Entry>();
+                       newEntries.add(oldEntries.firstElement());
+                       for (int i = 1; i < oldEntries.size() - 1; i = i + 2) {
+                               Entry low = oldEntries.elementAt(i - 1);
+                               Entry middle = oldEntries.elementAt(i);
+                               Entry high = oldEntries.elementAt(i + 1);
+
+                               Amount<X> dx = high.x.minus(low.x);
+                               Amount<Y> dy = high.y.minus(low.y);
+
+                               Amount<X> ddx = middle.x.minus(low.x);
+                               Amount<Y> lin = low.y.plus(dy.times(ddx.divide(dx)));
+
+                               Amount<Y> dif = middle.y.minus(lin).abs();
+
+                               // System.out.println(middle.x + "\t" + middle.y + "\t" + lin +
+                               // "\t" + dif + "\t"
+                               // + dy);
+
+                               if (dif.isGreaterThan(err)) {
+                                       newEntries.add(middle);
+                               }
+                               newEntries.add(high);
+                       }
+                       newEntries.add(oldEntries.lastElement());
+
+                       System.out.println("Size " + oldEntries.size() + " -> "
+                                       + newEntries.size());
+
+                       oldEntries = newEntries;
+               }
+
+               for (Entry ee : oldEntries) {
+                       if (out.get(ee.x) == null) {
+                               out.put(ee.x, ee.y);
+                               outDomain.add(ee.x);
+                       }
+               }
+       }
+
+       public static void main(String args[]) throws Exception {
+               CoredCylindricalGrain g = new CoredCylindricalGrain();
+               g.setLength(Amount.valueOf(70, SI.MILLIMETER));
+               g.setOD(Amount.valueOf(30, SI.MILLIMETER));
+               g.setID(Amount.valueOf(10, SI.MILLIMETER));
+
+               Chart<Length, Area> c = new Chart<Length, Area>(SI.MILLIMETER,
+                               SI.MILLIMETER.pow(2).asType(Area.class), g, "surfaceArea");
+               c.setDomain(c.new IntervalDomain(Amount.valueOf(0, SI.CENTIMETER), g
+                               .webThickness()));
+               c.show();
+
+               GraphSimplifier<Length, Area> gs = new GraphSimplifier(g,
+                               "surfaceArea", c.new IntervalDomain(Amount.valueOf(0,
+                                               SI.CENTIMETER), g.webThickness()).iterator());
+
+               Chart<Length, Area> d = new Chart<Length, Area>(SI.MILLIMETER,
+                               SI.MILLIMETER.pow(2).asType(Area.class), gs, "value");
+               d.setDomain(gs.getDomain());
+               d.show();
+       }
+}
diff --git a/src/com/billkuker/rocketry/motorsim/io/ENGExporter.java b/src/com/billkuker/rocketry/motorsim/io/ENGExporter.java
new file mode 100644 (file)
index 0000000..5233205
--- /dev/null
@@ -0,0 +1,87 @@
+package com.billkuker.rocketry.motorsim.io;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Collection;
+import java.util.Set;
+
+import javax.measure.quantity.Duration;
+import javax.measure.quantity.Force;
+import javax.measure.quantity.Mass;
+import javax.measure.unit.SI;
+
+import org.jscience.physics.amount.Amount;
+
+import com.billkuker.rocketry.motorsim.Burn;
+import com.billkuker.rocketry.motorsim.CylindricalChamber;
+import com.billkuker.rocketry.motorsim.GraphSimplifier;
+
+public class ENGExporter {
+
+       public static void export(Iterable<Burn> bb, File f) throws IOException {
+               export(bb, new FileOutputStream(f));
+       }
+
+       public static void export(Iterable<Burn> bb, OutputStream os) throws IOException {
+               for (Burn b : bb) {
+                       export(b, os);
+               }
+       }
+
+       public static void export(Burn b, OutputStream os) throws IOException {
+
+               CylindricalChamber cha = (CylindricalChamber) b.getMotor().getChamber();
+
+               NumberFormat nf = new DecimalFormat("00.###");
+
+               StringBuffer out = new StringBuffer();
+
+               out.append(";Output from Motorsim, motorsim@billkuker.com\n");
+               out.append(";You must fill in Delays and Total Weight\n");
+               out.append(";Name Diameter Length Delays ProWt Wt Manufacturer\n");
+               out.append(b.getMotor().getName().replace(" ", "-") + " ");
+
+               double dia = cha.getOD().doubleValue(SI.MILLIMETER);
+               double len = cha.getLength().doubleValue(SI.MILLIMETER);
+
+               Amount<Mass> prop = b.getMotor().getGrain().volume(
+                               Amount.valueOf(0, SI.MILLIMETER)).times(
+                               b.getMotor().getFuel().getIdealDensity().times(
+                                               b.getMotor().getFuel().getDensityRatio())).to(
+                               SI.KILOGRAM);
+               double wt = prop.doubleValue(SI.KILOGRAM);
+
+               out.append(nf.format(dia) + " " + nf.format(len) + " 0-0-0 "
+                               + nf.format(wt) + " " + nf.format(wt) + " MF\n");
+
+               GraphSimplifier<Duration, Force> gs = null;
+               try {
+                       gs = new GraphSimplifier<Duration, Force>(b, "thrust", b.getData()
+                                       .keySet().iterator());
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       return;
+               }
+
+               int cnt = 0;
+               for (Amount<Duration> t : gs.getDomain()) {
+                       cnt++;
+                       double thrust = gs.value(t).doubleValue(SI.NEWTON);
+                       if (cnt < 10 && thrust == 0.0) {
+                               continue; // This is a hack to ignore 0 thrust early in burn
+                       }
+                       out.append("   ");
+                       out.append(nf.format(t.doubleValue(SI.SECOND)));
+                       out.append(" ");
+                       out.append(nf.format(thrust));
+                       out.append("\n");
+               }
+               out.append(";\n\n");
+
+               os.write(out.toString().getBytes());
+       }
+}
index 11fc3d379e9cad0aca7207ce32585d59f61a624a..8886f5e1b6250454c33c10517b79e7f013029126 100644 (file)
@@ -7,6 +7,7 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;\r
 import java.io.File;\r
 import java.util.HashMap;\r
+import java.util.Vector;\r
 \r
 import javax.swing.ButtonGroup;\r
 import javax.swing.JFileChooser;\r
@@ -29,8 +30,10 @@ import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.TreePath;\r
 import javax.swing.tree.TreeSelectionModel;\r
 \r
+import com.billkuker.rocketry.motorsim.Burn;\r
 import com.billkuker.rocketry.motorsim.Motor;\r
 import com.billkuker.rocketry.motorsim.RocketScience.UnitPreference;\r
+import com.billkuker.rocketry.motorsim.io.ENGExporter;\r
 import com.billkuker.rocketry.motorsim.io.MotorIO;\r
 \r
 public class MotorWorkbench extends JFrame implements TreeSelectionListener {\r
@@ -205,7 +208,33 @@ public class MotorWorkbench extends JFrame implements TreeSelectionListener {
                                                                });\r
                                                        }\r
                                                });\r
+                                               add(new JSeparator());\r
+                                               add(new JMenuItem("Export .ENG"){\r
+                                                       private static final long serialVersionUID = 1L;\r
+\r
+                                                       {\r
+                                                               addActionListener(new ActionListener() {\r
+                                                                       @Override\r
+                                                                       public void actionPerformed(ActionEvent arg0) {\r
 \r
+                                                                               final FileDialog fd = new FileDialog(MotorWorkbench.this, "Export .ENG File", FileDialog.SAVE);\r
+                                                                               fd.setFile("motorsim.eng");\r
+                                                                               fd.setVisible(true);\r
+                                                                               if (fd.getFile() != null ) {\r
+                                                                                       File file = new File(fd.getDirectory() + fd.getFile());\r
+                                                                                       Vector<Burn> bb = new Vector<Burn>();\r
+                                                                                       for( MotorEditor me : m2e.values() )\r
+                                                                                               bb.add(me.burn);\r
+                                                                                       try{\r
+                                                                                               ENGExporter.export(bb, file);\r
+                                                                                       } catch ( Exception e ){\r
+                                                                                               e.printStackTrace();\r
+                                                                                       }\r
+                                                                               }\r
+                                                                       }\r
+                                                               });\r
+                                                       }\r
+                                               });\r
                                        }\r
                                });\r
                                add(new JMenu("Settings") {\r