1 package net.sf.openrocket.gui.figureelements;
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;
14 import java.awt.Color;
16 import java.awt.Graphics2D;
17 import java.awt.Rectangle;
18 import java.awt.font.GlyphVector;
19 import java.awt.geom.Rectangle2D;
21 import static net.sf.openrocket.util.Chars.ALPHA;
22 import static net.sf.openrocket.util.Chars.THETA;
26 * A <code>FigureElement</code> that draws text at different positions in the figure
27 * with general data about the rocket.
29 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
31 public class RocketInfo implements FigureElement {
33 private static final Translator trans = Application.getTranslator();
34 // Margin around the figure edges, pixels
35 private static final int MARGIN = 8;
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);
42 private final Caret cpCaret = new CPCaret(0,0);
43 private final Caret cgCaret = new CGCaret(0,0);
45 private final Configuration configuration;
46 private final UnitGroup stabilityUnits;
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();
53 private WarningSet warnings = null;
55 private boolean calculatingData = false;
56 private FlightData flightData = null;
58 private Graphics2D g2 = null;
59 private float line = 0;
60 private float x1, x2, y1, y2;
66 public RocketInfo(Configuration configuration) {
67 this.configuration = configuration;
68 this.stabilityUnits = UnitGroup.stabilityUnits(configuration);
73 public void paint(Graphics2D g2, double scale) {
74 throw new UnsupportedOperationException("paint() must be called with coordinates");
78 public void paint(Graphics2D g2, double scale, Rectangle visible) {
80 this.line = FONT.getLineMetrics("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
81 g2.getFontRenderContext()).getHeight();
83 x1 = visible.x + MARGIN;
84 x2 = visible.x + visible.width - MARGIN;
85 y1 = visible.y + line ;
86 y2 = visible.y + visible.height - MARGIN;
91 drawFlightInformation();
95 public void setCG(double cg) {
99 public void setCP(double cp) {
103 public void setLength(double length) {
104 this.length = length;
107 public void setDiameter(double diameter) {
108 this.diameter = diameter;
111 public void setMass(double mass) {
115 public void setWarnings(WarningSet warnings) {
116 this.warnings = warnings.clone();
119 public void setAOA(double aoa) {
123 public void setTheta(double theta) {
127 public void setMach(double mach) {
132 public void setFlightData(FlightData data) {
133 this.flightData = data;
136 public void setCalculatingData(boolean calc) {
137 this.calculatingData = calc;
143 private void drawMainInfo() {
144 GlyphVector name = createText(configuration.getRocket().getName());
145 GlyphVector lengthLine = createText(
147 trans.get("RocketInfo.lengthLine.Length") +" " + UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(length) +
149 trans.get("RocketInfo.lengthLine.maxdiameter") +" " +
150 UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(diameter));
153 if (configuration.hasMotors())
154 //// Mass with motors
155 massText = trans.get("RocketInfo.massText1") +" ";
157 //// Mass with no motors
158 massText = trans.get("RocketInfo.massText2") +" ";
160 massText += UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(mass);
162 GlyphVector massLine = createText(massText);
165 g2.setColor(Color.BLACK);
167 g2.drawGlyphVector(name, x1, y1);
168 g2.drawGlyphVector(lengthLine, x1, y1+line);
169 g2.drawGlyphVector(massLine, x1, y1+2*line);
174 private void drawStabilityInfo() {
177 at = trans.get("RocketInfo.at")+UnitGroup.UNITS_COEFFICIENT.getDefaultUnit().toStringUnit(mach);
178 if (!Double.isNaN(aoa)) {
179 at += " "+ALPHA+"=" + UnitGroup.UNITS_ANGLE.getDefaultUnit().toStringUnit(aoa);
181 if (!Double.isNaN(theta)) {
182 at += " "+THETA+"=" + UnitGroup.UNITS_ANGLE.getDefaultUnit().toStringUnit(theta);
185 GlyphVector cgValue = createText(
187 GlyphVector cpValue = createText(
189 GlyphVector stabValue = createText(
192 GlyphVector cgText = createText(trans.get("RocketInfo.cgText") +" ");
194 GlyphVector cpText = createText(trans.get("RocketInfo.cpText") +" ");
196 GlyphVector stabText = createText(trans.get("RocketInfo.stabText") + " ");
197 GlyphVector atText = createSmallText(at);
199 Rectangle2D cgRect = cgValue.getVisualBounds();
200 Rectangle2D cpRect = cpValue.getVisualBounds();
201 Rectangle2D cgTextRect = cgText.getVisualBounds();
202 Rectangle2D cpTextRect = cpText.getVisualBounds();
203 Rectangle2D stabRect = stabValue.getVisualBounds();
204 Rectangle2D stabTextRect = stabText.getVisualBounds();
205 Rectangle2D atTextRect = atText.getVisualBounds();
207 double unitWidth = MathUtil.max(cpRect.getWidth(), cgRect.getWidth(),
208 stabRect.getWidth());
209 double textWidth = Math.max(cpTextRect.getWidth(), cgTextRect.getWidth());
212 g2.setColor(Color.BLACK);
214 g2.drawGlyphVector(stabValue, (float)(x2-stabRect.getWidth()), y1);
215 g2.drawGlyphVector(cgValue, (float)(x2-cgRect.getWidth()), y1+line);
216 g2.drawGlyphVector(cpValue, (float)(x2-cpRect.getWidth()), y1+2*line);
218 g2.drawGlyphVector(stabText, (float)(x2-unitWidth-stabTextRect.getWidth()), y1);
219 g2.drawGlyphVector(cgText, (float)(x2-unitWidth-cgTextRect.getWidth()), y1+line);
220 g2.drawGlyphVector(cpText, (float)(x2-unitWidth-cpTextRect.getWidth()), y1+2*line);
222 cgCaret.setPosition(x2 - unitWidth - textWidth - 10, y1+line-0.3*line);
223 cgCaret.paint(g2, 1.7);
225 cpCaret.setPosition(x2 - unitWidth - textWidth - 10, y1+2*line-0.3*line);
226 cpCaret.paint(g2, 1.7);
229 if (unitWidth + textWidth + 10 > atTextRect.getWidth()) {
230 atPos = (float)(x2-(unitWidth+textWidth+10+atTextRect.getWidth())/2);
232 atPos = (float)(x2 - atTextRect.getWidth());
235 g2.setColor(Color.GRAY);
236 g2.drawGlyphVector(atText, atPos, y1 + 3*line);
241 * Get the mass, in default mass units.
245 public double getMass() {
250 * Get the mass in specified mass units.
252 * @param u UnitGroup.MASS
256 public String getMass(Unit u) {
257 return u.toStringUnit(mass);
261 * Get the stability, in calibers.
263 * @return the current stability margin
265 public String getStability () {
266 return stabilityUnits.getDefaultUnit().toStringUnit(cp-cg);
270 * Get the center of pressure in default length units.
272 * @return the distance from the tip to the center of pressure, in default length units
274 public String getCp () {
275 return getCp(UnitGroup.UNITS_LENGTH.getDefaultUnit());
279 * Get the center of pressure in default length units.
281 * @param u UnitGroup.LENGTH
283 * @return the distance from the tip to the center of pressure, in default length units
285 public String getCp (Unit u) {
286 return u.toStringUnit(cp);
290 * Get the center of gravity in default length units.
292 * @return the distance from the tip to the center of gravity, in default length units
294 public String getCg () {
295 return getCg(UnitGroup.UNITS_LENGTH.getDefaultUnit());
299 * Get the center of gravity in specified length units.
301 * @param u UnitGroup.LENGTH
302 * @return the distance from the tip to the center of gravity, in specified units
304 public String getCg (Unit u) {
305 return u.toStringUnit(cg);
309 * Get the flight data for the current motor configuration.
311 * @return flight data, or null
313 public FlightData getFlightData () {
317 private void drawWarnings() {
318 if (warnings == null || warnings.isEmpty())
321 GlyphVector[] texts = new GlyphVector[warnings.size()+1];
325 texts[0] = createText(trans.get("RocketInfo.Warning"));
327 for (Warning w: warnings) {
328 texts[i] = createText(w.toString());
332 for (GlyphVector v: texts) {
333 Rectangle2D rect = v.getVisualBounds();
334 if (rect.getWidth() > max)
335 max = rect.getWidth();
339 float y = y2 - line * warnings.size();
340 g2.setColor(new Color(255,0,0,130));
342 for (GlyphVector v: texts) {
343 Rectangle2D rect = v.getVisualBounds();
344 g2.drawGlyphVector(v, (float)(x2 - max/2 - rect.getWidth()/2), y);
350 private void drawFlightInformation() {
351 double height = drawFlightData();
353 if (calculatingData) {
355 GlyphVector calculating = createText(trans.get("RocketInfo.Calculating"));
356 g2.setColor(Color.BLACK);
357 g2.drawGlyphVector(calculating, x1, (float)(y2-height));
362 private double drawFlightData() {
363 if (flightData == null)
369 GlyphVector apogee = createText(trans.get("RocketInfo.Apogee")+" ");
371 GlyphVector maxVelocity = createText(trans.get("RocketInfo.Maxvelocity") +" ");
372 //// Max. acceleration:
373 GlyphVector maxAcceleration = createText(trans.get("RocketInfo.Maxacceleration") + " ");
375 GlyphVector apogeeValue, velocityValue, accelerationValue;
376 if (!Double.isNaN(flightData.getMaxAltitude())) {
377 apogeeValue = createText(
378 UnitGroup.UNITS_DISTANCE.toStringUnit(flightData.getMaxAltitude()));
381 apogeeValue = createText(trans.get("RocketInfo.apogeeValue"));
383 if (!Double.isNaN(flightData.getMaxVelocity())) {
384 velocityValue = createText(
385 UnitGroup.UNITS_VELOCITY.toStringUnit(flightData.getMaxVelocity()) +
387 " " +trans.get("RocketInfo.Mach") +" " +
388 UnitGroup.UNITS_COEFFICIENT.toString(flightData.getMaxMachNumber()) + ")");
391 velocityValue = createText(trans.get("RocketInfo.velocityValue"));
393 if (!Double.isNaN(flightData.getMaxAcceleration())) {
394 accelerationValue = createText(
395 UnitGroup.UNITS_ACCELERATION.toStringUnit(flightData.getMaxAcceleration()));
398 accelerationValue = createText(trans.get("RocketInfo.accelerationValue"));
402 rect = apogee.getVisualBounds();
403 width = MathUtil.max(width, rect.getWidth());
405 rect = maxVelocity.getVisualBounds();
406 width = MathUtil.max(width, rect.getWidth());
408 rect = maxAcceleration.getVisualBounds();
409 width = MathUtil.max(width, rect.getWidth());
413 if (!calculatingData)
414 g2.setColor(new Color(0,0,127));
416 g2.setColor(new Color(0,0,127,127));
419 g2.drawGlyphVector(apogee, (float)x1, (float)(y2-2*line));
420 g2.drawGlyphVector(maxVelocity, (float)x1, (float)(y2-line));
421 g2.drawGlyphVector(maxAcceleration, (float)x1, (float)(y2));
423 g2.drawGlyphVector(apogeeValue, (float)(x1+width), (float)(y2-2*line));
424 g2.drawGlyphVector(velocityValue, (float)(x1+width), (float)(y2-line));
425 g2.drawGlyphVector(accelerationValue, (float)(x1+width), (float)(y2));
432 private GlyphVector createText(String text) {
433 return FONT.createGlyphVector(g2.getFontRenderContext(), text);
436 private GlyphVector createSmallText(String text) {
437 return SMALLFONT.createGlyphVector(g2.getFontRenderContext(), text);