added svn:ignores
[debian/openrocket] / src / net / sf / openrocket / gui / figureelements / RocketInfo.java
1 package net.sf.openrocket.gui.figureelements;
2
3 import net.sf.openrocket.aerodynamics.Warning;
4 import net.sf.openrocket.aerodynamics.WarningSet;
5 import net.sf.openrocket.rocketcomponent.Configuration;
6 import net.sf.openrocket.simulation.FlightData;
7 import net.sf.openrocket.unit.Unit;
8 import net.sf.openrocket.unit.UnitGroup;
9 import net.sf.openrocket.util.MathUtil;
10 import net.sf.openrocket.util.Prefs;
11
12 import java.awt.Color;
13 import java.awt.Font;
14 import java.awt.Graphics2D;
15 import java.awt.Rectangle;
16 import java.awt.font.GlyphVector;
17 import java.awt.geom.Rectangle2D;
18
19 import static net.sf.openrocket.util.Chars.ALPHA;
20 import static net.sf.openrocket.util.Chars.THETA;
21
22
23 /**
24  * A <code>FigureElement</code> that draws text at different positions in the figure
25  * with general data about the rocket.
26  * 
27  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
28  */
29 public class RocketInfo implements FigureElement {
30         
31         // Margin around the figure edges, pixels
32         private static final int MARGIN = 8;
33
34         // Font to use
35         private static final Font FONT = new Font(Font.SANS_SERIF, Font.PLAIN, 11);
36         private static final Font SMALLFONT = new Font(Font.SANS_SERIF, Font.PLAIN, 9);
37
38         
39         private final Caret cpCaret = new CPCaret(0,0);
40         private final Caret cgCaret = new CGCaret(0,0);
41         
42         private final Configuration configuration;
43         private final UnitGroup stabilityUnits;
44         
45         private double cg = 0, cp = 0;
46         private double length = 0, diameter = 0;
47         private double mass = 0;
48         private double aoa = Double.NaN, theta = Double.NaN, mach = Prefs.getDefaultMach();
49         
50         private WarningSet warnings = null;
51         
52         private boolean calculatingData = false;
53         private FlightData flightData = null;
54         
55         private Graphics2D g2 = null;
56         private float line = 0;
57         private float x1, x2, y1, y2;
58         
59         
60         
61         
62         
63         public RocketInfo(Configuration configuration) {
64                 this.configuration = configuration;
65                 this.stabilityUnits = UnitGroup.stabilityUnits(configuration);
66         }
67         
68         
69         @Override
70         public void paint(Graphics2D g2, double scale) {
71                 throw new UnsupportedOperationException("paint() must be called with coordinates");
72         }
73
74         @Override
75         public void paint(Graphics2D g2, double scale, Rectangle visible) {
76                 this.g2 = g2;
77                 this.line = FONT.getLineMetrics("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
78                                 g2.getFontRenderContext()).getHeight();
79                 
80                 x1 = visible.x + MARGIN;
81                 x2 = visible.x + visible.width - MARGIN;
82                 y1 = visible.y + line ;
83                 y2 = visible.y + visible.height - MARGIN;
84
85                 drawMainInfo();
86                 drawStabilityInfo();
87                 drawWarnings();
88                 drawFlightInformation();
89         }
90         
91         
92         public void setCG(double cg) {
93                 this.cg = cg;
94         }
95         
96         public void setCP(double cp) {
97                 this.cp = cp;
98         }
99         
100         public void setLength(double length) {
101                 this.length = length;
102         }
103         
104         public void setDiameter(double diameter) {
105                 this.diameter = diameter;
106         }
107         
108         public void setMass(double mass) {
109                 this.mass = mass;
110         }
111         
112         public void setWarnings(WarningSet warnings) {
113                 this.warnings = warnings.clone();
114         }
115         
116         public void setAOA(double aoa) {
117                 this.aoa = aoa;
118         }
119         
120         public void setTheta(double theta) {
121                 this.theta = theta;
122         }
123         
124         public void setMach(double mach) {
125                 this.mach = mach;
126         }
127         
128         
129         public void setFlightData(FlightData data) {
130                 this.flightData = data;
131         }
132         
133         public void setCalculatingData(boolean calc) {
134                 this.calculatingData = calc;
135         }
136         
137         
138         
139         
140         private void drawMainInfo() {
141                 GlyphVector name = createText(configuration.getRocket().getName());
142                 GlyphVector lengthLine = createText(
143                                 "Length " + UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(length) +
144                                 ", max. diameter " + 
145                                 UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(diameter));
146                 
147                 String massText;
148                 if (configuration.hasMotors())
149                         massText = "Mass with motors ";
150                 else
151                         massText = "Mass with no motors ";
152                 
153                 massText += UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(mass);
154                 
155                 GlyphVector massLine = createText(massText);
156
157                 
158                 g2.setColor(Color.BLACK);
159
160                 g2.drawGlyphVector(name, x1, y1);
161                 g2.drawGlyphVector(lengthLine, x1, y1+line);
162                 g2.drawGlyphVector(massLine, x1, y1+2*line);
163
164         }
165         
166         
167         private void drawStabilityInfo() {
168                 String at;
169                 
170                 at = "at M="+UnitGroup.UNITS_COEFFICIENT.getDefaultUnit().toStringUnit(mach);
171                 if (!Double.isNaN(aoa)) {
172                         at += " "+ALPHA+"=" + UnitGroup.UNITS_ANGLE.getDefaultUnit().toStringUnit(aoa);
173                 }
174                 if (!Double.isNaN(theta)) {
175                         at += " "+THETA+"=" + UnitGroup.UNITS_ANGLE.getDefaultUnit().toStringUnit(theta);
176                 }
177                 
178                 GlyphVector cgValue = createText(
179                 getCg());
180                 GlyphVector cpValue = createText(
181                 getCp());
182                 GlyphVector stabValue = createText(
183                 getStability());
184                                 
185                 GlyphVector cgText = createText("CG:  ");
186                 GlyphVector cpText = createText("CP:  ");
187                 GlyphVector stabText = createText("Stability:  ");
188                 GlyphVector atText = createSmallText(at);
189
190                 Rectangle2D cgRect = cgValue.getVisualBounds();
191                 Rectangle2D cpRect = cpValue.getVisualBounds();
192                 Rectangle2D cgTextRect = cgText.getVisualBounds();
193                 Rectangle2D cpTextRect = cpText.getVisualBounds();
194                 Rectangle2D stabRect = stabValue.getVisualBounds();
195                 Rectangle2D stabTextRect = stabText.getVisualBounds();
196                 Rectangle2D atTextRect = atText.getVisualBounds();
197                 
198                 double unitWidth = MathUtil.max(cpRect.getWidth(), cgRect.getWidth(),
199                                 stabRect.getWidth());
200                 double textWidth = Math.max(cpTextRect.getWidth(), cgTextRect.getWidth());
201                 
202
203                 g2.setColor(Color.BLACK);
204
205                 g2.drawGlyphVector(stabValue, (float)(x2-stabRect.getWidth()), y1);
206                 g2.drawGlyphVector(cgValue, (float)(x2-cgRect.getWidth()), y1+line);
207                 g2.drawGlyphVector(cpValue, (float)(x2-cpRect.getWidth()), y1+2*line);
208
209                 g2.drawGlyphVector(stabText, (float)(x2-unitWidth-stabTextRect.getWidth()), y1);
210                 g2.drawGlyphVector(cgText, (float)(x2-unitWidth-cgTextRect.getWidth()), y1+line);
211                 g2.drawGlyphVector(cpText, (float)(x2-unitWidth-cpTextRect.getWidth()), y1+2*line);
212                                 
213                 cgCaret.setPosition(x2 - unitWidth - textWidth - 10, y1+line-0.3*line);
214                 cgCaret.paint(g2, 1.7);
215
216                 cpCaret.setPosition(x2 - unitWidth - textWidth - 10, y1+2*line-0.3*line);
217                 cpCaret.paint(g2, 1.7);
218                 
219                 float atPos;
220                 if (unitWidth + textWidth + 10 > atTextRect.getWidth()) {
221                         atPos = (float)(x2-(unitWidth+textWidth+10+atTextRect.getWidth())/2);
222                 } else {
223                         atPos = (float)(x2 - atTextRect.getWidth());
224                 }
225                 
226                 g2.setColor(Color.GRAY);
227                 g2.drawGlyphVector(atText, atPos, y1 + 3*line);
228
229         }
230
231     /**
232      * Get the mass, in default mass units.
233      * 
234      * @return the mass
235      */
236     public double getMass() {
237         return mass;
238     }
239
240     /**
241      * Get the mass in specified mass units.
242      * 
243      * @param u UnitGroup.MASS
244      * 
245      * @return the mass
246      */
247     public String getMass(Unit u) {
248         return u.toStringUnit(mass);
249     }
250     
251     /**
252      * Get the stability, in calibers.
253      * 
254      * @return  the current stability margin
255      */
256     public String getStability () {
257         return stabilityUnits.getDefaultUnit().toStringUnit(cp-cg);
258     }
259
260     /**
261      * Get the center of pressure in default length units.
262      * 
263      * @return  the distance from the tip to the center of pressure, in default length units
264      */
265     public String getCp () {
266         return getCp(UnitGroup.UNITS_LENGTH.getDefaultUnit());
267     }
268
269     /**
270      * Get the center of pressure in default length units.
271      * 
272      * @param u UnitGroup.LENGTH 
273      * 
274      * @return  the distance from the tip to the center of pressure, in default length units
275      */
276     public String getCp (Unit u) {
277         return u.toStringUnit(cp);
278     }
279
280     /**
281      * Get the center of gravity in default length units.
282      * 
283      * @return  the distance from the tip to the center of gravity, in default length units
284      */
285     public String getCg () {
286         return getCg(UnitGroup.UNITS_LENGTH.getDefaultUnit());
287     }
288
289     /**
290      * Get the center of gravity in specified length units.
291      * 
292      * @param u UnitGroup.LENGTH 
293      * @return  the distance from the tip to the center of gravity, in specified units
294      */
295     public String getCg (Unit u) {
296         return u.toStringUnit(cg);
297     }
298
299     /**
300      * Get the flight data for the current motor configuration.
301      * 
302      * @return flight data, or null
303      */
304     public FlightData getFlightData () {
305         return flightData;
306     }
307     
308     private void drawWarnings() {
309                 if (warnings == null || warnings.isEmpty())
310                         return;
311                 
312                 GlyphVector[] texts = new GlyphVector[warnings.size()+1];
313                 double max = 0;
314                 
315                 texts[0] = createText("Warning:");
316                 int i=1;
317                 for (Warning w: warnings) {
318                         texts[i] = createText(w.toString());
319                         i++;
320                 }
321                 
322                 for (GlyphVector v: texts) {
323                         Rectangle2D rect = v.getVisualBounds();
324                         if (rect.getWidth() > max)
325                                 max = rect.getWidth();
326                 }
327                 
328
329                 float y = y2 - line * warnings.size();
330                 g2.setColor(new Color(255,0,0,130));
331
332                 for (GlyphVector v: texts) {
333                         Rectangle2D rect = v.getVisualBounds();
334                         g2.drawGlyphVector(v, (float)(x2 - max/2 - rect.getWidth()/2), y);
335                         y += line;
336                 }
337         }
338         
339         
340         private void drawFlightInformation() {
341                 double height = drawFlightData();
342                 
343                 if (calculatingData) {
344                         GlyphVector calculating = createText("Calculating...");
345                         g2.setColor(Color.BLACK);
346                         g2.drawGlyphVector(calculating, x1, (float)(y2-height));
347                 }
348         }
349         
350         
351         private double drawFlightData() {
352                 if (flightData == null)
353                         return 0;
354                 
355                 double width=0;
356                 
357                 GlyphVector apogee = createText("Apogee: ");
358                 GlyphVector maxVelocity = createText("Max. velocity: ");
359                 GlyphVector maxAcceleration = createText("Max. acceleration: ");
360
361                 GlyphVector apogeeValue, velocityValue, accelerationValue;
362                 if (!Double.isNaN(flightData.getMaxAltitude())) {
363                         apogeeValue = createText(
364                                         UnitGroup.UNITS_DISTANCE.toStringUnit(flightData.getMaxAltitude()));
365                 } else {
366                         apogeeValue = createText("N/A");
367                 }
368                 if (!Double.isNaN(flightData.getMaxVelocity())) {
369                         velocityValue = createText(
370                                         UnitGroup.UNITS_VELOCITY.toStringUnit(flightData.getMaxVelocity()) +
371                                         "  (Mach " + 
372                                         UnitGroup.UNITS_COEFFICIENT.toString(flightData.getMaxMachNumber()) + ")");
373                 } else {
374                         velocityValue = createText("N/A");
375                 }
376                 if (!Double.isNaN(flightData.getMaxAcceleration())) {
377                         accelerationValue = createText(
378                                         UnitGroup.UNITS_ACCELERATION.toStringUnit(flightData.getMaxAcceleration()));
379                 } else {
380                         accelerationValue = createText("N/A");
381                 }
382                 
383                 Rectangle2D rect;
384                 rect = apogee.getVisualBounds();
385                 width = MathUtil.max(width, rect.getWidth());
386                 
387                 rect = maxVelocity.getVisualBounds();
388                 width = MathUtil.max(width, rect.getWidth());
389                 
390                 rect = maxAcceleration.getVisualBounds();
391                 width = MathUtil.max(width, rect.getWidth());
392                 
393                 width += 5;
394
395                 if (!calculatingData) 
396                         g2.setColor(new Color(0,0,127));
397                 else
398                         g2.setColor(new Color(0,0,127,127));
399
400                 
401                 g2.drawGlyphVector(apogee, (float)x1, (float)(y2-2*line));
402                 g2.drawGlyphVector(maxVelocity, (float)x1, (float)(y2-line));
403                 g2.drawGlyphVector(maxAcceleration, (float)x1, (float)(y2));
404
405                 g2.drawGlyphVector(apogeeValue, (float)(x1+width), (float)(y2-2*line));
406                 g2.drawGlyphVector(velocityValue, (float)(x1+width), (float)(y2-line));
407                 g2.drawGlyphVector(accelerationValue, (float)(x1+width), (float)(y2));
408                 
409                 return 3*line;
410         }
411         
412         
413         
414         private GlyphVector createText(String text) {
415                 return FONT.createGlyphVector(g2.getFontRenderContext(), text);
416         }
417
418         private GlyphVector createSmallText(String text) {
419                 return SMALLFONT.createGlyphVector(g2.getFontRenderContext(), text);
420         }
421
422 }