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