1 package com.billkuker.rocketry.motorsim.io;
\r
4 import java.io.FileOutputStream;
\r
5 import java.io.OutputStream;
\r
6 import java.io.PrintWriter;
\r
7 import java.lang.reflect.InvocationTargetException;
\r
8 import java.lang.reflect.Method;
\r
9 import java.net.URLEncoder;
\r
10 import java.text.DecimalFormat;
\r
11 import java.text.NumberFormat;
\r
12 import java.util.Iterator;
\r
14 import javax.measure.quantity.Duration;
\r
15 import javax.measure.quantity.Force;
\r
16 import javax.measure.quantity.Quantity;
\r
17 import javax.measure.unit.SI;
\r
18 import javax.measure.unit.Unit;
\r
20 import org.jscience.physics.amount.Amount;
\r
22 import com.billkuker.rocketry.motorsim.Burn;
\r
23 import com.billkuker.rocketry.motorsim.BurnSummary;
\r
24 import com.billkuker.rocketry.motorsim.GraphSimplifier;
\r
25 import com.billkuker.rocketry.motorsim.Motor;
\r
26 import com.billkuker.rocketry.motorsim.RocketScience;
\r
27 import com.billkuker.rocketry.motorsim.motors.kuker.PVC9;
\r
29 public class HTMLExporter {
\r
31 @SuppressWarnings("deprecation")
\r
32 private static String encode(String s) {
\r
33 return URLEncoder.encode(s).replace("%B2", "%C2%B2");
\r
36 private static <X extends Quantity, Y extends Quantity> String toChart(
\r
37 final Unit<X> xUnit, final Unit<Y> yUnit, final Object source,
\r
38 final String method, final Iterator<Amount<X>> domain, String title)
\r
39 throws SecurityException, NoSuchMethodException,
\r
40 IllegalArgumentException, IllegalAccessException,
\r
41 InvocationTargetException {
\r
42 NumberFormat nf = new DecimalFormat("#.##");
\r
43 Method f = source.getClass().getMethod(method, Amount.class);
\r
45 double xMin = 0, xMax = 0;
\r
46 double yMin = 0, yMax = 0;
\r
48 StringBuffer xVals = new StringBuffer();
\r
49 StringBuffer yVals = new StringBuffer();
\r
51 while (domain.hasNext()) {
\r
52 Amount<X> aX = domain.next();
\r
53 double x = aX.doubleValue(xUnit);
\r
54 @SuppressWarnings("unchecked")
\r
55 double y = ((Amount<Y>) f.invoke(source, aX)).doubleValue(yUnit);
\r
56 xMin = x < xMin ? x : xMin;
\r
57 xMax = x > xMax ? x : xMax;
\r
58 yMin = y < yMin ? y : yMin;
\r
59 yMax = y > yMax ? y : yMax;
\r
61 xVals.append(nf.format(x));
\r
63 yVals.append(nf.format(y));
\r
66 xVals.deleteCharAt(xVals.length() - 1);
\r
67 yVals.deleteCharAt(yVals.length() - 1);
\r
69 // Get the non-preferred Y Unit
\r
70 Unit<Y> yUnit2 = RocketScience.UnitPreference.SI
\r
71 .getPreferredUnit(yUnit);
\r
72 // if ( yUnit2.equals(yUnit) )
\r
73 yUnit2 = RocketScience.UnitPreference.NONSI.getPreferredUnit(yUnit);
\r
74 double y2Min, y2Max;
\r
75 y2Min = Amount.valueOf(yMin, yUnit).doubleValue(yUnit2);
\r
76 y2Max = Amount.valueOf(yMax, yUnit).doubleValue(yUnit2);
\r
78 // Get the non-preferred X Unit
\r
79 Unit<X> xUnit2 = RocketScience.UnitPreference.SI
\r
80 .getPreferredUnit(xUnit);
\r
81 // if ( xUnit2.equals(xUnit) )
\r
82 xUnit2 = RocketScience.UnitPreference.NONSI.getPreferredUnit(xUnit);
\r
83 double x2Min, x2Max;
\r
84 x2Min = Amount.valueOf(xMin, xUnit).doubleValue(xUnit2);
\r
85 x2Max = Amount.valueOf(xMax, xUnit).doubleValue(xUnit2);
\r
87 boolean x2 = !xUnit.equals(xUnit2);
\r
88 boolean y2 = x2 || !yUnit.equals(yUnit2);
\r
90 StringBuffer sb = new StringBuffer();
\r
91 sb.append("<img src='");
\r
92 sb.append("http://chart.apis.google.com/chart?chxt=x,x,y,y"
\r
93 + (y2 ? ",r,r" : "") + (x2 ? ",t,t" : "")
\r
94 + "&chs=640x240&cht=lxy&chco=3072F3");
\r
95 sb.append("&chds=" + nf.format(xMin) + "," + nf.format(xMax) + ","
\r
96 + nf.format(yMin) + "," + nf.format(yMax));
\r
97 sb.append("&chxr=" + "0," + nf.format(xMin) + "," + nf.format(xMax)
\r
98 + "|2," + nf.format(yMin) + "," + nf.format(yMax));
\r
100 sb.append("|4," + nf.format(y2Min) + "," + nf.format(y2Max));
\r
102 sb.append("|6," + nf.format(x2Min) + "," + nf.format(x2Max));
\r
103 sb.append("&chd=t:" + xVals.toString() + "|" + yVals.toString());
\r
104 sb.append("&chxl=1:|" + encode(xUnit.toString()) + "|3:|"
\r
105 + encode(yUnit.toString()));
\r
107 sb.append("|5:|" + encode(yUnit2.toString()));
\r
109 sb.append("|7:|" + encode(xUnit2.toString()));
\r
110 sb.append("&chxp=1,50|3,50");
\r
112 sb.append("|5,50");
\r
114 sb.append("|7,50");
\r
115 sb.append("&chtt=" + title);
\r
116 sb.append("' width='640' height='240' alt='" + title + "' />");
\r
118 return sb.toString();
\r
121 public static void export(Burn b, OutputStream os) throws Exception {
\r
122 PrintWriter out = new PrintWriter(os);
\r
124 BurnSummary bs = new BurnSummary(b);
\r
126 out.println("<!--Begin motor " + b.getMotor().getName() + " HTML export from MotorSim-->");
\r
127 out.print("<table class='motor'>");
\r
130 out.print("<th colspan='6' class='title'>" + b.getMotor().getName() + "</th>");
\r
131 out.print("</tr>");
\r
133 out.print("<tr class='summary'>");
\r
134 out.print("<th>Rating:</th>");
\r
136 out.print("<td>" + bs.getRating() + "</td>");
\r
137 out.print("<th>Total Impulse:</th>");
\r
140 + RocketScience.ammountToRoundedString(bs.totalImpulse())
\r
142 out.print("<th>Specific Impulse:</th>");
\r
144 + RocketScience.ammountToRoundedString(bs.specificImpulse())
\r
146 out.print("</tr>");
\r
149 out.print("<tr class='summary'>");
\r
150 out.print("<th>Max Thrust:</th>");
\r
154 + RocketScience.ammountToRoundedString(bs.maxThrust())
\r
156 out.print("<th>Average Thrust:</th>");
\r
159 + RocketScience.ammountToRoundedString(bs.averageThrust())
\r
161 out.print("<th>Max Pressure:</th>");
\r
163 + RocketScience.ammountToRoundedString(bs.maxPressure())
\r
165 out.print("</tr>");
\r
168 out.print("<td colspan='6' class='thrust'>");
\r
169 GraphSimplifier<Duration, Force> thrust = new GraphSimplifier<Duration, Force>(
\r
170 b, "thrust", b.getData().keySet().iterator());
\r
172 out.print(toChart(SI.SECOND, SI.NEWTON, thrust, "value", thrust
\r
173 .getDomain().iterator(), "Thrust"));
\r
174 out.print("</td>");
\r
176 out.print("<td colspan='3' class='pressure'>");
\r
177 GraphSimplifier<Duration, Pressure> pressure = new GraphSimplifier<Duration, Pressure>(
\r
178 b, "pressure", b.getData().keySet().iterator());
\r
180 out.print(toChart(SI.SECOND,
\r
181 javax.measure.unit.SI.MEGA(javax.measure.unit.SI.PASCAL),
\r
182 pressure, "value", pressure.getDomain().iterator(), "Pressure"));
\r
184 out.print("</td>");
\r
186 out.print("</tr>");
\r
189 out.print("<th colspan='3'>.ENG File</th>");
\r
190 out.print("<th colspan='3'>MotorSim File</th>");
\r
191 out.print("</tr>");
\r
193 out.print("<td colspan='3'>");
\r
194 out.print("<textarea>");
\r
197 ENGExporter.export(b, os);
\r
199 out.print("</textarea>");
\r
200 out.print("</td>");
\r
201 out.print("<td colspan='3'>");
\r
202 out.print("<textarea>");
\r
203 out.print(MotorIO.writeMotor(b.getMotor()).replace("<", "<").replace(">", ">"));
\r
204 out.print("</textarea>");
\r
205 out.print("</td>");
\r
206 out.print("</tr>");
\r
208 out.print("</table>");
\r
210 out.println("\n<!--End motor " + b.getMotor().getName() + "-->");
\r
215 public static void main(String args[]) throws Exception {
\r
217 Motor m = new PVC9();
\r
218 Burn b = new Burn(m);
\r
220 File f = new File("test.html");
\r
221 export(b, System.out);
\r
222 export(b, new FileOutputStream(f));
\r
226 * EndBurner g = new EndBurner(); g.setLength(Amount.valueOf(70,
\r
227 * SI.MILLIMETER)); g.setoD(Amount.valueOf(30, SI.MILLIMETER));
\r
228 * g.setPuntDepth(Amount.valueOf(10, SI.MILLIMETER));
\r
229 * g.setPuntDiameter(Amount.valueOf(10, SI.MILLIMETER));
\r
231 * Chart<Length, Area> c = new Chart<Length, Area>(SI.MILLIMETER,
\r
232 * SI.MILLIMETER.pow(2).asType(Area.class), g, "surfaceArea");
\r
233 * c.setDomain(c.new IntervalDomain(Amount.valueOf(0, SI.CENTIMETER), g
\r
234 * .webThickness()));
\r
236 * GraphSimplifier<Length, Area> gs = new GraphSimplifier<Length,
\r
237 * Area>(g, "surfaceArea", c.new IntervalDomain(Amount.valueOf(0,
\r
238 * SI.CENTIMETER), g.webThickness()).iterator());
\r
240 * System.out.print(toChart(SI.MILLIMETER,
\r
241 * SI.MILLIMETER.pow(2).asType(Area.class), gs, "value", gs
\r
242 * .getDomain().iterator(), "Area"));
\r