1 package com.billkuker.rocketry.motorsim.visual;
\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
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
29 import org.apache.log4j.Logger;
\r
30 import org.jscience.physics.amount.Amount;
\r
32 import com.billkuker.rocketry.motorsim.ChangeListening;
\r
33 import com.billkuker.rocketry.motorsim.Grain;
\r
35 public class GrainPanel extends JPanel {
\r
36 private static Logger log = Logger.getLogger(GrainPanel.class);
\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
44 private Grain grain;
\r
46 public GrainPanel(Grain g){
\r
47 super(new BorderLayout());
\r
51 if ( g instanceof ChangeListening.Subject ){
\r
52 ((ChangeListening.Subject)g).addPropertyChangeListener(new PropertyChangeListener(){
\r
53 public void propertyChange(PropertyChangeEvent evt) {
\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
64 area = new Chart<Length, Area>(
\r
66 SI.MILLIMETER.pow(2).asType(Area.class),
\r
69 area.setDomain(area.new IntervalDomain(Amount.valueOf(0, SI.MILLIMETER), grain.webThickness()));
\r
71 volume = new Chart<Length, Volume>(
\r
73 SI.MILLIMETER.pow(3).asType(Volume.class),
\r
76 volume.setDomain(volume.new IntervalDomain(Amount.valueOf(0, SI.MILLIMETER), grain.webThickness()));
\r
78 area.setMaximumSize(new Dimension(200,100));
\r
79 volume.setMaximumSize(new Dimension(200,100));
\r
82 } catch (ClassCastException e) {
\r
84 } catch (NoSuchMethodException e) {
\r
97 protected void addComponents(
\r
98 Component crossSection,
\r
105 JSplitPane v = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
\r
106 JSplitPane h = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
\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
113 v.setTopComponent(h);
\r
114 v.setBottomComponent(area);
\r
115 h.setLeftComponent(graphics);
\r
116 h.setRightComponent(volume);
\r
119 h.resetToPreferredSizes();
\r
120 v.resetToPreferredSizes();
\r
124 public void setDisplayedRegression( Amount<Length> r ){
\r
125 displayedRegression = r;
\r
127 NumberFormat nf = NumberFormat.getInstance();
\r
128 nf.setMaximumFractionDigits(2);
\r
129 l.setText("Regression: " + nf.format(displayedRegression.doubleValue(SI.MILLIMETER)) + "mm");
\r
131 area.mark(displayedRegression);
\r
132 volume.mark(displayedRegression);
\r
137 private class XC extends JPanel{
\r
138 private static final long serialVersionUID = 1L;
\r
140 public XC(Grain g){
\r
142 java.awt.geom.Area unburnt = grain.getSideView(Amount.valueOf(0, SI.MILLIMETER));
\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
152 Dimension sz = new Dimension(240+w, 250);
\r
153 setMinimumSize(sz);
\r
154 setPreferredSize(sz);
\r
155 setMaximumSize(sz);
\r
157 public void paint(Graphics g){
\r
159 Graphics2D g2d = (Graphics2D)g;
\r
160 g2d.translate(10, 30);
\r
162 grain.draw(g2d, displayedRegression );
\r
166 AffineTransform t = g2d.getTransform();
\r
167 java.awt.geom.Area unburnt = grain.getCrossSection(Amount.valueOf(0, SI.MILLIMETER));
\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
173 //Draw the fuel that is left
\r
174 java.awt.geom.Area burning = grain.getCrossSection(displayedRegression);
\r
175 g2d.setColor(Color.RED);
\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
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
186 g2d.setTransform(t);
\r
189 AffineTransform t = g2d.getTransform();
\r
190 java.awt.geom.Area unburnt = grain.getSideView(Amount.valueOf(0, SI.MILLIMETER));
\r
192 Rectangle bounds = unburnt.getBounds();
\r
193 g2d.translate(220, 0);
\r
195 double max = bounds.getWidth();
\r
196 if ( bounds.getHeight() > max )
\r
197 max = bounds.getHeight();
\r
199 g2d.scale(200 / max, 200 / max);
\r
200 g2d.translate(-bounds.getX(), -bounds.getY());
\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
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
210 //Draw the outline of the unburnt grain
\r
211 g2d.setColor(Color.BLACK);
\r
214 g2d.setTransform(t);
\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
224 addChangeListener(this);
\r
230 public void stateChanged(ChangeEvent e) {
\r
231 double r = ((SL)e.getSource()).getValue();
\r
233 setDisplayedRegression(grain.webThickness().divide(STEPS).times(r));
\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