]> git.gag.com Git - sw/motorsim/blob - src/com/billkuker/rocketry/motorsim/visual/Chart.java
Added asynchronous rendering
[sw/motorsim] / src / com / billkuker / rocketry / motorsim / visual / Chart.java
1 package com.billkuker.rocketry.motorsim.visual;\r
2 import java.awt.BorderLayout;\r
3 import java.awt.Color;\r
4 import java.lang.reflect.InvocationTargetException;\r
5 import java.lang.reflect.Method;\r
6 import java.util.Collection;\r
7 import java.util.Iterator;\r
8 import java.util.concurrent.ExecutorService;\r
9 import java.util.concurrent.Executors;\r
10 \r
11 import javax.measure.quantity.Area;\r
12 import javax.measure.quantity.Length;\r
13 import javax.measure.quantity.Quantity;\r
14 import javax.measure.quantity.Volume;\r
15 import javax.measure.unit.SI;\r
16 import javax.measure.unit.Unit;\r
17 import javax.swing.JFrame;\r
18 import javax.swing.JPanel;\r
19 \r
20 import org.jfree.chart.ChartFactory;\r
21 import org.jfree.chart.ChartPanel;\r
22 import org.jfree.chart.JFreeChart;\r
23 import org.jfree.chart.plot.Marker;\r
24 import org.jfree.chart.plot.PlotOrientation;\r
25 import org.jfree.chart.plot.ValueMarker;\r
26 import org.jfree.data.xy.XYSeries;\r
27 import org.jfree.data.xy.XYSeriesCollection;\r
28 import org.jscience.physics.amount.Amount;\r
29 \r
30 import com.billkuker.rocketry.motorsim.RocketScience;\r
31 import com.billkuker.rocketry.motorsim.grain.CoredCylindricalGrain;\r
32 \r
33 public class Chart<X extends Quantity, Y extends Quantity> extends JPanel  {\r
34         private static final long serialVersionUID = 1L;\r
35         \r
36         private static ExecutorService fast = Executors.newFixedThreadPool(2) ;\r
37         private static ExecutorService slow = Executors.newFixedThreadPool(2);\r
38 \r
39         public class IntervalDomain implements Iterable<Amount<X>>{\r
40                 \r
41                 Amount<X> low, high, delta;\r
42                 int steps = 100;\r
43 \r
44                 public IntervalDomain(Amount<X> low, Amount<X> high) {\r
45                         this.low = low;\r
46                         this.high = high;\r
47                         delta = high.minus(low).divide(steps);\r
48                 }\r
49 \r
50                 public IntervalDomain(Amount<X> low, Amount<X> high, int steps) {\r
51                         this.steps = steps;\r
52                         this.low = low;\r
53                         this.high = high;\r
54                         delta = high.minus(low).divide(steps);\r
55                 }\r
56 \r
57 \r
58                 public Iterator<Amount<X>> iterator() {\r
59                         return new Iterator<Amount<X>>(){\r
60                                 Amount<X> current = low;\r
61                                 \r
62                                 public boolean hasNext() {\r
63                                         return current.isLessThan(high.plus(delta));\r
64                                 }\r
65 \r
66                                 public Amount<X> next() {\r
67                                         Amount<X> ret = current;\r
68                                         current = current.plus(delta);\r
69                                         return ret;\r
70                                 }\r
71                                 \r
72                                 public final void remove() {\r
73                                         throw new UnsupportedOperationException("Chart domain iterators are not modifiable.");\r
74                                 }\r
75                         };\r
76                 }\r
77                 \r
78         }\r
79         \r
80 \r
81         XYSeries series;\r
82         XYSeriesCollection dataset = new XYSeriesCollection();\r
83         JFreeChart chart;\r
84 \r
85         Unit<X> xUnit;\r
86         Unit<Y> yUnit;\r
87 \r
88         Object source;\r
89         Method f;\r
90 \r
91 \r
92         @SuppressWarnings("unchecked")\r
93         public Chart(Unit<X> xUnit, Unit<Y> yUnit, Object source, String method)\r
94                         throws NoSuchMethodException {\r
95                 super(new BorderLayout());\r
96                 f = source.getClass().getMethod(method, Amount.class);\r
97 \r
98                 series = new XYSeries(f.getName());\r
99                 this.source = source;\r
100 \r
101                 dataset.addSeries(series);\r
102 \r
103                 this.xUnit = RocketScience.UnitPreference.preference.getPreferredUnit(xUnit);\r
104                 this.yUnit = RocketScience.UnitPreference.preference.getPreferredUnit(yUnit);\r
105                 \r
106                 chart = ChartFactory.createXYLineChart(\r
107                                 method.substring(0,1).toUpperCase() + method.substring(1), // Title\r
108                                 this.xUnit.toString(), // x-axis Label\r
109                                 this.yUnit.toString(), // y-axis Label\r
110                                 dataset,\r
111                                 PlotOrientation.VERTICAL, // Plot Orientation\r
112                                 false, // Show Legend\r
113                                 true, // Use tool tips\r
114                                 false // Configure chart to generate URLs?\r
115                                 );\r
116                 add(new ChartPanel(chart));\r
117         }\r
118         \r
119         private Marker marker;\r
120         public void mark(Amount<X> m){\r
121                 if ( marker != null )\r
122                         chart.getXYPlot().removeDomainMarker(marker);\r
123                 if ( m != null ){\r
124                marker = new ValueMarker(m.doubleValue(xUnit));\r
125                marker.setPaint(Color.blue);\r
126                marker.setAlpha(0.8f);\r
127                         chart.getXYPlot().addDomainMarker(marker);\r
128                 }\r
129         }\r
130 \r
131 \r
132         public void setDomain(final Iterable<Amount<X>> d) {\r
133                 series.clear();\r
134                 fill(d, 100);\r
135                 fast.submit(new Thread(){\r
136                         public void run(){\r
137                                 fill(d, 10);\r
138                         }\r
139                 });\r
140                 slow.submit(new Thread(){\r
141                         public void run(){\r
142                                 fill(d, 1);\r
143                         }\r
144                 });\r
145         }\r
146         \r
147         @SuppressWarnings("unchecked")\r
148         private void fill(Iterable<Amount<X>> d, int skip) {\r
149                 int sz = 0;\r
150                 if (d instanceof Collection) {\r
151                         sz = ((Collection) d).size();\r
152                         int sk2 = sz / 200;\r
153                         if (skip < sk2)\r
154                                 skip = sk2;\r
155                 }\r
156                 // series.clear();\r
157                 int cnt = 0;\r
158 \r
159                 try {\r
160                         Amount<X> last = null;\r
161                         for (Amount<X> ax : d) {\r
162                                 last = ax;\r
163                                 if (cnt % skip == 0) {\r
164                                         Amount<Y> y = (Amount<Y>) f.invoke(source, ax);\r
165                                         add(ax, y);\r
166                                 }\r
167                                 cnt++;\r
168                         }\r
169                         Amount<Y> y = (Amount<Y>) f.invoke(source, last);\r
170                         add(last, y);\r
171                 } catch (IllegalArgumentException e) {\r
172                         // TODO Auto-generated catch block\r
173                         e.printStackTrace();\r
174                 } catch (IllegalAccessException e) {\r
175                         // TODO Auto-generated catch block\r
176                         e.printStackTrace();\r
177                 } catch (InvocationTargetException e) {\r
178                         // TODO Auto-generated catch block\r
179                         e.printStackTrace();\r
180                 }\r
181         }\r
182 \r
183         private void add(Amount<X> x, Amount<Y> y) {\r
184                 series.add(x.doubleValue(xUnit), y.doubleValue(yUnit));\r
185         }\r
186         \r
187         public void show(){\r
188                 new JFrame(){\r
189                         private static final long serialVersionUID = 1L;\r
190                         {\r
191                                 setContentPane(Chart.this);\r
192                                 setSize(640,480);\r
193                                 setDefaultCloseOperation(DISPOSE_ON_CLOSE);\r
194                         }\r
195                 }.setVisible(true);\r
196         }\r
197 \r
198         public static void main(String args[]) throws Exception {\r
199                 CoredCylindricalGrain g = new CoredCylindricalGrain();\r
200                 g.setLength(Amount.valueOf(70, SI.MILLIMETER));\r
201                 g.setOD(Amount.valueOf(30, SI.MILLIMETER));\r
202                 g.setID(Amount.valueOf(10, SI.MILLIMETER));\r
203 \r
204                 Chart<Length, Area> c = new Chart<Length, Area>(SI.MILLIMETER,\r
205                                 SI.MILLIMETER.pow(2).asType(Area.class), g, "surfaceArea");\r
206 \r
207                 c.setDomain(c.new IntervalDomain(Amount.valueOf(0, SI.CENTIMETER), g\r
208                                 .webThickness()));\r
209 \r
210                 c.show();\r
211                 \r
212                 Chart<Length, Volume> v = new Chart<Length, Volume>(SI.MILLIMETER,\r
213                                 SI.MILLIMETER.pow(3).asType(Volume.class), g, "volume");\r
214 \r
215                 v.setDomain(c.new IntervalDomain(Amount.valueOf(0, SI.CENTIMETER), g\r
216                                 .webThickness()));\r
217 \r
218                 v.show();\r
219         }\r
220 \r
221 }\r