cleared some minor TODOs
[sw/motorsim] / gui / com / billkuker / rocketry / motorsim / visual / GrainPanel.java
1 package com.billkuker.rocketry.motorsim.visual;\r
2 \r
3 import java.awt.BasicStroke;\r
4 import java.awt.BorderLayout;\r
5 import java.awt.Color;\r
6 import java.awt.Component;\r
7 import java.awt.Dimension;\r
8 import java.awt.Graphics;\r
9 import java.awt.Graphics2D;\r
10 import java.awt.Rectangle;\r
11 import java.awt.geom.AffineTransform;\r
12 import java.beans.PropertyChangeEvent;\r
13 import java.beans.PropertyChangeListener;\r
14 import java.text.NumberFormat;\r
15 \r
16 import javax.measure.quantity.Area;\r
17 import javax.measure.quantity.Length;\r
18 import javax.measure.quantity.Volume;\r
19 import javax.measure.unit.SI;\r
20 import javax.swing.JFrame;\r
21 import javax.swing.JLabel;\r
22 import javax.swing.JPanel;\r
23 import javax.swing.JSlider;\r
24 import javax.swing.JSplitPane;\r
25 import javax.swing.WindowConstants;\r
26 import javax.swing.event.ChangeEvent;\r
27 import javax.swing.event.ChangeListener;\r
28 \r
29 import org.apache.log4j.Logger;\r
30 import org.jscience.physics.amount.Amount;\r
31 \r
32 import com.billkuker.rocketry.motorsim.ChangeListening;\r
33 import com.billkuker.rocketry.motorsim.Grain;\r
34 \r
35 public class GrainPanel extends JPanel {\r
36         private static Logger log = Logger.getLogger(GrainPanel.class);\r
37                         \r
38         private static final long serialVersionUID = 1L;\r
39         private Amount<Length> displayedRegression = Amount.valueOf(0, SI.MILLIMETER);\r
40         private JLabel l = new JLabel();\r
41         private Chart<Length,Area> area;\r
42         Chart<Length, Volume> volume;\r
43         private XC xc;\r
44         private Grain grain;\r
45         \r
46         public GrainPanel(Grain g){\r
47                 super(new BorderLayout());\r
48 \r
49                 grain = g;\r
50                 \r
51                 if ( g instanceof ChangeListening.Subject ){\r
52                         ((ChangeListening.Subject)g).addPropertyChangeListener(new PropertyChangeListener(){\r
53                                 public void propertyChange(PropertyChangeEvent evt) {\r
54                                         repaint();\r
55                                         area.setDomain(area.new IntervalDomain(Amount.valueOf(0, SI.MILLIMETER), grain.webThickness()));\r
56                                         volume.setDomain(volume.new IntervalDomain(Amount.valueOf(0, SI.MILLIMETER), grain.webThickness()));\r
57                                 }\r
58                         });\r
59                 }\r
60 \r
61 \r
62                 try {\r
63 \r
64                         area = new Chart<Length, Area>(\r
65                                         SI.MILLIMETER,\r
66                                         SI.MILLIMETER.pow(2).asType(Area.class),\r
67                                         grain,\r
68                                         "surfaceArea");\r
69                         area.setDomain(area.new IntervalDomain(Amount.valueOf(0, SI.MILLIMETER), grain.webThickness()));\r
70                         \r
71                         volume = new Chart<Length, Volume>(\r
72                                         SI.MILLIMETER,\r
73                                         SI.MILLIMETER.pow(3).asType(Volume.class),\r
74                                         grain,\r
75                                         "volume");\r
76                         volume.setDomain(volume.new IntervalDomain(Amount.valueOf(0, SI.MILLIMETER), grain.webThickness()));\r
77 \r
78                         area.setMaximumSize(new Dimension(200,100));\r
79                         volume.setMaximumSize(new Dimension(200,100));\r
80                         \r
81 \r
82                 } catch (ClassCastException e) {\r
83                         log.error(e);\r
84                 } catch (NoSuchMethodException e) {\r
85                         log.error(e);\r
86                 }\r
87                 \r
88                 addComponents(\r
89                                 xc = new XC(grain),\r
90                                 new SL(),\r
91                                 l,\r
92                                 area,\r
93                                 volume\r
94                 );\r
95         }\r
96         \r
97         protected void addComponents(\r
98                         Component crossSection,\r
99                         Component slider,\r
100                         Component label,\r
101                         Component area,\r
102                         Component volume\r
103         ){\r
104                 \r
105                 JSplitPane v = new JSplitPane(JSplitPane.VERTICAL_SPLIT);\r
106                 JSplitPane h = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);\r
107                 \r
108                 JPanel graphics = new JPanel(new BorderLayout());\r
109                 graphics.add(crossSection, BorderLayout.CENTER);\r
110                 graphics.add(label, BorderLayout.NORTH);\r
111                 graphics.add(slider, BorderLayout.SOUTH);\r
112         \r
113                 v.setTopComponent(h);\r
114                 v.setBottomComponent(area);\r
115                 h.setLeftComponent(graphics);\r
116                 h.setRightComponent(volume);\r
117                 add(v);\r
118                 \r
119                 h.resetToPreferredSizes();\r
120                 v.resetToPreferredSizes();\r
121 \r
122         }\r
123         \r
124         public void setDisplayedRegression( Amount<Length> r ){\r
125                 displayedRegression = r;\r
126                 \r
127                 NumberFormat nf = NumberFormat.getInstance();\r
128                 nf.setMaximumFractionDigits(2);\r
129                 l.setText("Regression: " + nf.format(displayedRegression.doubleValue(SI.MILLIMETER)) + "mm");\r
130                 \r
131                 area.mark(displayedRegression);\r
132                 volume.mark(displayedRegression);\r
133                 if ( xc != null )\r
134                         xc.repaint();\r
135         }\r
136         \r
137         private class XC extends JPanel{\r
138                 private static final long serialVersionUID = 1L;\r
139                 Grain grain;\r
140                 public XC(Grain g){\r
141                         grain = g;\r
142                         java.awt.geom.Area unburnt = grain.getSideView(Amount.valueOf(0, SI.MILLIMETER));\r
143                         \r
144                         Rectangle bounds = unburnt.getBounds();\r
145                         double max = bounds.getWidth();\r
146                         if ( bounds.getHeight() > max )\r
147                                 max = bounds.getHeight();\r
148                         int w = (int)(bounds.getWidth() * 200.0 / max);\r
149                         if ( w < 40 )\r
150                                 w = 40;\r
151                         \r
152                         Dimension sz = new Dimension(240+w, 250);\r
153                         setMinimumSize(sz);\r
154                         setPreferredSize(sz);\r
155                         setMaximumSize(sz);\r
156                 }\r
157                 public void paint(Graphics g){\r
158                         super.paint(g);\r
159                         Graphics2D g2d = (Graphics2D)g;\r
160                         g2d.translate(10, 30);\r
161                         /*\r
162                         grain.draw(g2d, displayedRegression );\r
163                         */\r
164                         \r
165                         {\r
166                                 AffineTransform t = g2d.getTransform();\r
167                                 java.awt.geom.Area unburnt = grain.getCrossSection(Amount.valueOf(0, SI.MILLIMETER));\r
168                                 \r
169                                 Rectangle bounds = unburnt.getBounds();\r
170                                 g2d.scale(200 / bounds.getWidth(), 200 / bounds.getHeight());\r
171                                 g2d.translate(-bounds.getX(), -bounds.getY());\r
172         \r
173                                 //Draw the fuel that is left\r
174                                 java.awt.geom.Area burning = grain.getCrossSection(displayedRegression);\r
175                                 g2d.setColor(Color.RED);\r
176                                 g2d.fill(burning);\r
177                                 //Draw the fuel that is left\r
178                                 java.awt.geom.Area left = grain.getCrossSection(displayedRegression.plus(grain.webThickness().divide(30)));\r
179                                 g2d.setColor(Color.GRAY);\r
180                                 g2d.fill(left);\r
181                                 //Draw the outline of the unburnt grain\r
182                                 g2d.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND));\r
183                                 g2d.setColor(Color.BLACK);\r
184                                 g2d.draw(unburnt);\r
185                                 //untranslate\r
186                                 g2d.setTransform(t);\r
187                         }\r
188                         {\r
189                                 AffineTransform t = g2d.getTransform();\r
190                                 java.awt.geom.Area unburnt = grain.getSideView(Amount.valueOf(0, SI.MILLIMETER));\r
191                                 \r
192                                 Rectangle bounds = unburnt.getBounds();\r
193                                 g2d.translate(220, 0);\r
194                                 \r
195                                 double max = bounds.getWidth();\r
196                                 if ( bounds.getHeight() > max )\r
197                                         max = bounds.getHeight();\r
198                                 \r
199                                 g2d.scale(200 / max, 200 / max);\r
200                                 g2d.translate(-bounds.getX(), -bounds.getY());\r
201         \r
202                                 //Draw the fuel that is left\r
203                                 java.awt.geom.Area burning = grain.getSideView(displayedRegression);\r
204                                 g2d.setColor(Color.RED);\r
205                                 g2d.fill(burning);\r
206                                 //Draw the fuel that is left\r
207                                 java.awt.geom.Area left = grain.getSideView(displayedRegression.plus(grain.webThickness().divide(30)));\r
208                                 g2d.setColor(Color.GRAY);\r
209                                 g2d.fill(left);\r
210                                 //Draw the outline of the unburnt grain\r
211                                 g2d.setColor(Color.BLACK);\r
212                                 g2d.draw(unburnt);\r
213                                 //untranslate\r
214                                 g2d.setTransform(t);\r
215                         }\r
216                         \r
217                 }\r
218         }\r
219         \r
220         private class SL extends JSlider implements ChangeListener{\r
221                 private static final long serialVersionUID = 1L;\r
222                 private static final int STEPS = 60;\r
223                 public SL(){\r
224                         addChangeListener(this);\r
225                         setMinimum(0);\r
226                         setMaximum(STEPS);\r
227                         setValue(0);\r
228                 }\r
229                 \r
230                 public void stateChanged(ChangeEvent e) {\r
231                         double r = ((SL)e.getSource()).getValue();\r
232 \r
233                         setDisplayedRegression(grain.webThickness().divide(STEPS).times(r));\r
234                 }\r
235         }\r
236         \r
237         public void showAsWindow(){\r
238                 JFrame f = new JFrame();\r
239                 f.setTitle(grain.getClass().getName());\r
240                 f.setSize(1024,600);\r
241                 f.setContentPane(this);\r
242                 f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);\r
243                 f.setVisible(true);\r
244         }\r
245 \r
246 }\r