From f37d07a1822177caa3740f2792b297401a3545b8 Mon Sep 17 00:00:00 2001 From: Bill Kuker Date: Wed, 9 Sep 2009 01:50:59 +0000 Subject: [PATCH] Added ENG export --- .../rocketry/motorsim/GraphSimplifier.java | 127 ++++++++++++++++++ .../rocketry/motorsim/io/ENGExporter.java | 87 ++++++++++++ .../visual/workbench/MotorWorkbench.java | 29 ++++ 3 files changed, 243 insertions(+) create mode 100644 src/com/billkuker/rocketry/motorsim/GraphSimplifier.java create mode 100644 src/com/billkuker/rocketry/motorsim/io/ENGExporter.java diff --git a/src/com/billkuker/rocketry/motorsim/GraphSimplifier.java b/src/com/billkuker/rocketry/motorsim/GraphSimplifier.java new file mode 100644 index 0000000..921a36d --- /dev/null +++ b/src/com/billkuker/rocketry/motorsim/GraphSimplifier.java @@ -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 { + Method f; + + private class Entry { + Amount x; + Amount y; + } + + private Map, Amount> out = new HashMap, Amount>(); + private List> outDomain = new Vector>(); + + public Amount value(Amount x) { + return out.get(x); + } + + public Iterable> getDomain() { + return outDomain; + } + + public GraphSimplifier(Object source, String method, + Iterator> domain) throws NoSuchMethodException, + IllegalArgumentException, IllegalAccessException, + InvocationTargetException { + f = source.getClass().getMethod(method, Amount.class); + + Vector oldEntries = new Vector(); + + Amount max = null, min = null, range = null, err = null; + while (domain.hasNext()) { + Amount x = domain.next(); + Amount y = (Amount) 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 newEntries = new Vector(); + 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 dx = high.x.minus(low.x); + Amount dy = high.y.minus(low.y); + + Amount ddx = middle.x.minus(low.x); + Amount lin = low.y.plus(dy.times(ddx.divide(dx))); + + Amount 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 c = new Chart(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 gs = new GraphSimplifier(g, + "surfaceArea", c.new IntervalDomain(Amount.valueOf(0, + SI.CENTIMETER), g.webThickness()).iterator()); + + Chart d = new Chart(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 index 0000000..5233205 --- /dev/null +++ b/src/com/billkuker/rocketry/motorsim/io/ENGExporter.java @@ -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 bb, File f) throws IOException { + export(bb, new FileOutputStream(f)); + } + + public static void export(Iterable 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 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 gs = null; + try { + gs = new GraphSimplifier(b, "thrust", b.getData() + .keySet().iterator()); + } catch (Exception e) { + e.printStackTrace(); + return; + } + + int cnt = 0; + for (Amount 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()); + } +} diff --git a/src/com/billkuker/rocketry/motorsim/visual/workbench/MotorWorkbench.java b/src/com/billkuker/rocketry/motorsim/visual/workbench/MotorWorkbench.java index 11fc3d3..8886f5e 100644 --- a/src/com/billkuker/rocketry/motorsim/visual/workbench/MotorWorkbench.java +++ b/src/com/billkuker/rocketry/motorsim/visual/workbench/MotorWorkbench.java @@ -7,6 +7,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.HashMap; +import java.util.Vector; import javax.swing.ButtonGroup; import javax.swing.JFileChooser; @@ -29,8 +30,10 @@ import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; +import com.billkuker.rocketry.motorsim.Burn; import com.billkuker.rocketry.motorsim.Motor; import com.billkuker.rocketry.motorsim.RocketScience.UnitPreference; +import com.billkuker.rocketry.motorsim.io.ENGExporter; import com.billkuker.rocketry.motorsim.io.MotorIO; public class MotorWorkbench extends JFrame implements TreeSelectionListener { @@ -205,7 +208,33 @@ public class MotorWorkbench extends JFrame implements TreeSelectionListener { }); } }); + add(new JSeparator()); + add(new JMenuItem("Export .ENG"){ + private static final long serialVersionUID = 1L; + + { + addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + final FileDialog fd = new FileDialog(MotorWorkbench.this, "Export .ENG File", FileDialog.SAVE); + fd.setFile("motorsim.eng"); + fd.setVisible(true); + if (fd.getFile() != null ) { + File file = new File(fd.getDirectory() + fd.getFile()); + Vector bb = new Vector(); + for( MotorEditor me : m2e.values() ) + bb.add(me.burn); + try{ + ENGExporter.export(bb, file); + } catch ( Exception e ){ + e.printStackTrace(); + } + } + } + }); + } + }); } }); add(new JMenu("Settings") { -- 2.47.2