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