130038fbef19430c668e265e71b97924f75c9acc
[sw/motorsim] / src / com / billkuker / rocketry / motorsim / io / HTMLExporter.java
1 package com.billkuker.rocketry.motorsim.io;\r
2 \r
3 import java.io.File;\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
13 \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
19 \r
20 import org.jscience.physics.amount.Amount;\r
21 \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
28 \r
29 public class HTMLExporter {\r
30 \r
31         @SuppressWarnings("deprecation")\r
32         private static String encode(String s) {\r
33                 return URLEncoder.encode(s).replace("%B2", "%C2%B2");\r
34         }\r
35 \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
44 \r
45                 double xMin = 0, xMax = 0;\r
46                 double yMin = 0, yMax = 0;\r
47 \r
48                 StringBuffer xVals = new StringBuffer();\r
49                 StringBuffer yVals = new StringBuffer();\r
50 \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
60 \r
61                         xVals.append(nf.format(x));\r
62                         xVals.append(",");\r
63                         yVals.append(nf.format(y));\r
64                         yVals.append(",");\r
65                 }\r
66                 xVals.deleteCharAt(xVals.length() - 1);\r
67                 yVals.deleteCharAt(yVals.length() - 1);\r
68 \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
77 \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
86 \r
87                 boolean x2 = !xUnit.equals(xUnit2);\r
88                 boolean y2 = x2 || !yUnit.equals(yUnit2);\r
89 \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
99                 if (y2)\r
100                         sb.append("|4," + nf.format(y2Min) + "," + nf.format(y2Max));\r
101                 if (x2)\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
106                 if (y2)\r
107                         sb.append("|5:|" + encode(yUnit2.toString()));\r
108                 if (x2)\r
109                         sb.append("|7:|" + encode(xUnit2.toString()));\r
110                 sb.append("&chxp=1,50|3,50");\r
111                 if (y2)\r
112                         sb.append("|5,50");\r
113                 if (x2)\r
114                         sb.append("|7,50");\r
115                 sb.append("&chtt=" + title);\r
116                 sb.append("' width='640' height='240' alt='" + title + "' />");\r
117 \r
118                 return sb.toString();\r
119         }\r
120 \r
121         public static void export(Burn b, OutputStream os) throws Exception {\r
122                 PrintWriter out = new PrintWriter(os);\r
123 \r
124                 BurnSummary bs = new BurnSummary(b);\r
125                 \r
126                 out.println("<!--Begin motor " + b.getMotor().getName() + " HTML export from MotorSim-->");\r
127                 out.print("<table class='motor'>");\r
128 \r
129                 out.print("<tr>");\r
130                 out.print("<th colspan='6' class='title'>" + b.getMotor().getName() + "</th>");\r
131                 out.print("</tr>");\r
132 \r
133                 out.print("<tr class='summary'>");\r
134                 out.print("<th>Rating:</th>");\r
135                 \r
136                 out.print("<td>" + bs.getRating() + "</td>");\r
137                 out.print("<th>Total Impulse:</th>");\r
138         \r
139                 out.print("<td>"\r
140                                 + RocketScience.ammountToRoundedString(bs.totalImpulse())\r
141                                 + "</td>");\r
142                 out.print("<th>Specific Impulse:</th>");\r
143                 out.print("<td>"\r
144                                 + RocketScience.ammountToRoundedString(bs.specificImpulse())\r
145                                 + "</td>");\r
146                 out.print("</tr>");\r
147                 \r
148                 \r
149                 out.print("<tr class='summary'>");\r
150                 out.print("<th>Max Thrust:</th>");\r
151                 \r
152                 \r
153                 out.print("<td>"\r
154                                 + RocketScience.ammountToRoundedString(bs.maxThrust())\r
155                                 + "</td>");\r
156                 out.print("<th>Average Thrust:</th>");\r
157         \r
158                 out.print("<td>"\r
159                                 + RocketScience.ammountToRoundedString(bs.averageThrust())\r
160                                 + "</td>");\r
161                 out.print("<th>Max Pressure:</th>");\r
162                 out.print("<td>"\r
163                                 + RocketScience.ammountToRoundedString(bs.maxPressure())\r
164                                 + "</td>");\r
165                 out.print("</tr>");\r
166 \r
167                 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
171 \r
172                 out.print(toChart(SI.SECOND, SI.NEWTON, thrust, "value", thrust\r
173                                 .getDomain().iterator(), "Thrust"));\r
174                 out.print("</td>");\r
175                 /*\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
179 \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
183 \r
184                 out.print("</td>");\r
185                 */\r
186                 out.print("</tr>");\r
187                 \r
188                 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
192                 out.print("<tr>");\r
193                 out.print("<td colspan='3'>");\r
194                 out.print("<textarea>");\r
195                 out.flush();\r
196                 os.flush();\r
197                 ENGExporter.export(b, os);\r
198                 os.flush();\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("<", "&lt;").replace(">", "&gt;"));\r
204                 out.print("</textarea>");\r
205                 out.print("</td>");\r
206                 out.print("</tr>");\r
207                 \r
208                 out.print("</table>");\r
209 \r
210                 out.println("\n<!--End motor " + b.getMotor().getName() + "-->");\r
211                 out.flush();\r
212                 out.close();\r
213         }\r
214 \r
215         public static void main(String args[]) throws Exception {\r
216 \r
217                 Motor m = new PVC9();\r
218                 Burn b = new Burn(m);\r
219 \r
220                 File f = new File("test.html");\r
221                 export(b, System.out);\r
222                 export(b, new FileOutputStream(f));\r
223 \r
224                 /*\r
225                  * \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
230                  * \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
235                  * \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
239                  * \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
243                  */\r
244         }\r
245 \r
246 }\r