1 package com.billkuker.rocketry.motorsim.visual;
\r
3 import java.awt.BorderLayout;
\r
4 import java.awt.Color;
\r
5 import java.awt.Dimension;
\r
6 import java.awt.GridLayout;
\r
7 import java.text.DecimalFormat;
\r
8 import java.text.NumberFormat;
\r
10 import javax.measure.quantity.Duration;
\r
11 import javax.measure.quantity.Force;
\r
12 import javax.measure.quantity.Pressure;
\r
13 import javax.measure.quantity.Velocity;
\r
14 import javax.measure.unit.SI;
\r
15 import javax.swing.JFrame;
\r
16 import javax.swing.JLabel;
\r
17 import javax.swing.JPanel;
\r
18 import javax.swing.JSlider;
\r
19 import javax.swing.JSplitPane;
\r
20 import javax.swing.WindowConstants;
\r
21 import javax.swing.event.ChangeEvent;
\r
22 import javax.swing.event.ChangeListener;
\r
24 import org.jscience.physics.amount.Amount;
\r
26 import com.billkuker.rocketry.motorsim.Burn;
\r
27 import com.billkuker.rocketry.motorsim.BurnSummary;
\r
28 import com.billkuker.rocketry.motorsim.RocketScience;
\r
30 public class BurnPanel extends JPanel {
\r
31 private static final long serialVersionUID = 1L;
\r
33 Chart<Duration, Pressure> pressure;
\r
34 Chart<Duration, Force> thrust;
\r
35 Chart<Pressure, Velocity> burnRate;
\r
37 Amount<Duration> displayedTime = Amount.valueOf(0, SI.SECOND);
\r
39 private static final Color RED = new Color(196, 0, 0);
\r
40 private static final Color GREEN = new Color(0, 196, 0);
\r
41 private static final Color ORANGE = new Color(160, 96, 0);
\r
43 public BurnPanel(Burn b){
\r
44 super( new BorderLayout() );
\r
48 pressure = new Chart<Duration, Pressure>(
\r
53 pressure.setDomain(burn.getData().keySet());
\r
55 thrust = new Chart<Duration, Force>(
\r
60 thrust.setDomain(burn.getData().keySet());
\r
62 burnRate = new Chart<Pressure, Velocity>(
\r
64 SI.METERS_PER_SECOND,
\r
65 burn.getMotor().getFuel(),
\r
68 burnRate.new IntervalDomain(
\r
69 Amount.valueOf(0, SI.MEGA(SI.PASCAL)),
\r
70 Amount.valueOf(11, SI.MEGA(SI.PASCAL)),
\r
75 JSplitPane tp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, thrust, pressure);
\r
76 tp.setDividerLocation(.5);
\r
77 tp.setResizeWeight(.5);
\r
79 grain = new GrainPanel(burn.getMotor().getGrain()){
\r
80 private static final long serialVersionUID = 1L;
\r
81 @Override protected void addComponents(java.awt.Component crossSection, java.awt.Component slider, java.awt.Component label, java.awt.Component area, java.awt.Component volume) {
\r
82 JSplitPane h = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, crossSection, area);
\r
83 add(h, BorderLayout.CENTER);
\r
84 h.resetToPreferredSizes();
\r
88 JSplitPane grains = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, grain, burnRate);
\r
89 grains.setDividerLocation(.5);
\r
90 grains.setResizeWeight(.5);
\r
92 JSplitPane main = new JSplitPane(JSplitPane.VERTICAL_SPLIT, grains, tp);
\r
93 Dimension minimumSize = new Dimension(800, 200);
\r
94 grains.setMinimumSize(minimumSize);
\r
95 tp.setMinimumSize(minimumSize);
\r
96 main.setDividerLocation(.5);
\r
97 main.setResizeWeight(.5);
\r
99 add( main, BorderLayout.CENTER );
\r
101 add( new SL(), BorderLayout.SOUTH);
\r
106 BurnSummary bi = new BurnSummary(burn);
\r
107 JPanel text = new JPanel(new GridLayout(2, 5));
\r
109 text.add(new JLabel("Rating"));
\r
110 text.add(new JLabel("Total Impulse"));
\r
111 text.add(new JLabel("ISP"));
\r
112 text.add(new JLabel("Max Thrust"));
\r
113 text.add(new JLabel("Average Thust"));
\r
114 text.add(new JLabel("Max Pressure"));
\r
116 text.add(new JLabel("Safty Factor"));
\r
118 text.add(new JLabel(bi.getRating()));
\r
119 text.add(new JLabel(RocketScience.ammountToRoundedString(bi.totalImpulse())));
\r
120 text.add(new JLabel(RocketScience.ammountToRoundedString(bi.specificImpulse())));
\r
121 text.add(new JLabel(RocketScience
\r
122 .ammountToRoundedString(bi.maxThrust())));
\r
123 text.add(new JLabel(RocketScience
\r
124 .ammountToRoundedString(bi.averageThrust())));
\r
125 text.add(new JLabel(RocketScience
\r
126 .ammountToRoundedString(bi.maxPressure())));
\r
129 if ( bi.getSaftyFactor() == null ){
\r
131 saftyColor = Color.BLACK;
\r
132 text.add(new JLabel("NA"));
\r
134 double d = bi.getSaftyFactor();
\r
136 saftyColor = GREEN;
\r
137 } else if ( d > 1 ){
\r
138 saftyColor = ORANGE;
\r
142 JLabel l = new JLabel( new DecimalFormat("##########.#").format(bi.getSaftyFactor()));
\r
144 l.setBackground(saftyColor);
\r
145 l.setForeground(Color.WHITE);
\r
150 add(text, BorderLayout.NORTH);
\r
152 thrust.addRangeMarker(bi.maxThrust(), "Max", Color.BLACK);
\r
153 thrust.addRangeMarker(bi.averageThrust(), "Average", Color.BLACK);
\r
154 pressure.addRangeMarker(bi.maxPressure(), "Max", Color.BLACK);
\r
155 burnRate.addDomainMarker(bi.maxPressure(), "Max", RED);
\r
157 Amount<Pressure> burst = b.getMotor().getChamber().getBurstPressure();
\r
158 if ( burst != null ){
\r
159 pressure.addRangeMarker(burst, "Burst", saftyColor);
\r
164 } catch (NoSuchMethodException e){
\r
165 throw new Error(e);
\r
171 private class SL extends JSlider implements ChangeListener{
\r
172 private static final long serialVersionUID = 1L;
\r
173 private static final int STEPS = 80;
\r
175 addChangeListener(this);
\r
181 public void stateChanged(ChangeEvent e) {
\r
182 double t = ((SL)e.getSource()).getValue();
\r
183 displayedTime = burn.burnTime().divide(STEPS).times(t);
\r
185 //Find the nearest key in the data set
\r
186 displayedTime =burn.getData().tailMap(displayedTime).firstKey();
\r
188 NumberFormat nf = NumberFormat.getInstance();
\r
189 nf.setMaximumFractionDigits(2);
\r
191 pressure.mark(displayedTime);
\r
192 thrust.mark(displayedTime);
\r
194 grain.setDisplayedRegression(burn.getData().get(displayedTime).regression);
\r
196 burnRate.mark(burn.getData().get(displayedTime).chamberPressure);
\r
200 double r = ((SL)e.getSource()).getValue();
\r
201 displayedRegression = grain.webThickness().divide(STEPS).times(r);
\r
202 NumberFormat nf = NumberFormat.getInstance();
\r
203 nf.setMaximumFractionDigits(2);
\r
204 l.setText("Regression: " + nf.format(displayedRegression.doubleValue(SI.MILLIMETER)) + "mm");
\r
205 area.mark(displayedRegression);
\r
206 volume.mark(displayedRegression);
\r
213 public void showAsWindow(){
\r
214 JFrame f = new JFrame();
\r
215 f.setTitle(burn.getMotor().getName());
\r
216 f.setSize(1280,720);
\r
217 f.setLocation(0, 0);
\r
218 f.setContentPane(this);
\r
219 f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
\r
220 f.setVisible(true);
\r