1 package net.sf.openrocket.gui.figureelements;
3 import static net.sf.openrocket.util.Chars.*;
7 import java.awt.Graphics2D;
8 import java.awt.Rectangle;
9 import java.awt.font.GlyphVector;
10 import java.awt.geom.Rectangle2D;
12 import net.sf.openrocket.aerodynamics.Warning;
13 import net.sf.openrocket.aerodynamics.WarningSet;
14 import net.sf.openrocket.rocketcomponent.Configuration;
15 import net.sf.openrocket.simulation.FlightData;
16 import net.sf.openrocket.unit.UnitGroup;
17 import net.sf.openrocket.util.MathUtil;
18 import net.sf.openrocket.util.Prefs;
22 * A <code>FigureElement</code> that draws text at different positions in the figure
23 * with general data about the rocket.
25 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
27 public class RocketInfo implements FigureElement {
29 // Margin around the figure edges, pixels
30 private static final int MARGIN = 8;
33 private static final Font FONT = new Font(Font.SANS_SERIF, Font.PLAIN, 11);
34 private static final Font SMALLFONT = new Font(Font.SANS_SERIF, Font.PLAIN, 9);
37 private final Caret cpCaret = new CPCaret(0,0);
38 private final Caret cgCaret = new CGCaret(0,0);
40 private final Configuration configuration;
41 private final UnitGroup stabilityUnits;
43 private double cg = 0, cp = 0;
44 private double length = 0, diameter = 0;
45 private double mass = 0;
46 private double aoa = Double.NaN, theta = Double.NaN, mach = Prefs.getDefaultMach();
48 private WarningSet warnings = null;
50 private boolean calculatingData = false;
51 private FlightData flightData = null;
53 private Graphics2D g2 = null;
54 private float line = 0;
55 private float x1, x2, y1, y2;
61 public RocketInfo(Configuration configuration) {
62 this.configuration = configuration;
63 this.stabilityUnits = UnitGroup.stabilityUnits(configuration);
68 public void paint(Graphics2D g2, double scale) {
69 throw new UnsupportedOperationException("paint() must be called with coordinates");
73 public void paint(Graphics2D g2, double scale, Rectangle visible) {
75 this.line = FONT.getLineMetrics("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
76 g2.getFontRenderContext()).getHeight();
78 x1 = visible.x + MARGIN;
79 x2 = visible.x + visible.width - MARGIN;
80 y1 = visible.y + line ;
81 y2 = visible.y + visible.height - MARGIN;
86 drawFlightInformation();
90 public void setCG(double cg) {
94 public void setCP(double cp) {
98 public void setLength(double length) {
102 public void setDiameter(double diameter) {
103 this.diameter = diameter;
106 public void setMass(double mass) {
110 public void setWarnings(WarningSet warnings) {
111 this.warnings = warnings.clone();
114 public void setAOA(double aoa) {
118 public void setTheta(double theta) {
122 public void setMach(double mach) {
127 public void setFlightData(FlightData data) {
128 this.flightData = data;
131 public void setCalculatingData(boolean calc) {
132 this.calculatingData = calc;
138 private void drawMainInfo() {
139 GlyphVector name = createText(configuration.getRocket().getName());
140 GlyphVector lengthLine = createText(
141 "Length " + UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(length) +
143 UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(diameter));
146 if (configuration.hasMotors())
147 massText = "Mass with motors ";
149 massText = "Mass with no motors ";
151 massText += UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(mass);
153 GlyphVector massLine = createText(massText);
156 g2.setColor(Color.BLACK);
158 g2.drawGlyphVector(name, x1, y1);
159 g2.drawGlyphVector(lengthLine, x1, y1+line);
160 g2.drawGlyphVector(massLine, x1, y1+2*line);
165 private void drawStabilityInfo() {
168 at = "at M="+UnitGroup.UNITS_COEFFICIENT.getDefaultUnit().toStringUnit(mach);
169 if (!Double.isNaN(aoa)) {
170 at += " "+ALPHA+"=" + UnitGroup.UNITS_ANGLE.getDefaultUnit().toStringUnit(aoa);
172 if (!Double.isNaN(theta)) {
173 at += " "+THETA+"=" + UnitGroup.UNITS_ANGLE.getDefaultUnit().toStringUnit(theta);
176 GlyphVector cgValue = createText(
177 UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(cg));
178 GlyphVector cpValue = createText(
179 UnitGroup.UNITS_LENGTH.getDefaultUnit().toStringUnit(cp));
180 GlyphVector stabValue = createText(
181 stabilityUnits.getDefaultUnit().toStringUnit(cp-cg));
183 GlyphVector cgText = createText("CG: ");
184 GlyphVector cpText = createText("CP: ");
185 GlyphVector stabText = createText("Stability: ");
186 GlyphVector atText = createSmallText(at);
188 Rectangle2D cgRect = cgValue.getVisualBounds();
189 Rectangle2D cpRect = cpValue.getVisualBounds();
190 Rectangle2D cgTextRect = cgText.getVisualBounds();
191 Rectangle2D cpTextRect = cpText.getVisualBounds();
192 Rectangle2D stabRect = stabValue.getVisualBounds();
193 Rectangle2D stabTextRect = stabText.getVisualBounds();
194 Rectangle2D atTextRect = atText.getVisualBounds();
196 double unitWidth = MathUtil.max(cpRect.getWidth(), cgRect.getWidth(),
197 stabRect.getWidth());
198 double textWidth = Math.max(cpTextRect.getWidth(), cgTextRect.getWidth());
201 g2.setColor(Color.BLACK);
203 g2.drawGlyphVector(stabValue, (float)(x2-stabRect.getWidth()), y1);
204 g2.drawGlyphVector(cgValue, (float)(x2-cgRect.getWidth()), y1+line);
205 g2.drawGlyphVector(cpValue, (float)(x2-cpRect.getWidth()), y1+2*line);
207 g2.drawGlyphVector(stabText, (float)(x2-unitWidth-stabTextRect.getWidth()), y1);
208 g2.drawGlyphVector(cgText, (float)(x2-unitWidth-cgTextRect.getWidth()), y1+line);
209 g2.drawGlyphVector(cpText, (float)(x2-unitWidth-cpTextRect.getWidth()), y1+2*line);
211 cgCaret.setPosition(x2 - unitWidth - textWidth - 10, y1+line-0.3*line);
212 cgCaret.paint(g2, 1.7);
214 cpCaret.setPosition(x2 - unitWidth - textWidth - 10, y1+2*line-0.3*line);
215 cpCaret.paint(g2, 1.7);
218 if (unitWidth + textWidth + 10 > atTextRect.getWidth()) {
219 atPos = (float)(x2-(unitWidth+textWidth+10+atTextRect.getWidth())/2);
221 atPos = (float)(x2 - atTextRect.getWidth());
224 g2.setColor(Color.GRAY);
225 g2.drawGlyphVector(atText, atPos, y1 + 3*line);
230 private void drawWarnings() {
231 if (warnings == null || warnings.isEmpty())
234 GlyphVector[] texts = new GlyphVector[warnings.size()+1];
237 texts[0] = createText("Warning:");
239 for (Warning w: warnings) {
240 texts[i] = createText(w.toString());
244 for (GlyphVector v: texts) {
245 Rectangle2D rect = v.getVisualBounds();
246 if (rect.getWidth() > max)
247 max = rect.getWidth();
251 float y = y2 - line * warnings.size();
252 g2.setColor(new Color(255,0,0,130));
254 for (GlyphVector v: texts) {
255 Rectangle2D rect = v.getVisualBounds();
256 g2.drawGlyphVector(v, (float)(x2 - max/2 - rect.getWidth()/2), y);
262 private void drawFlightInformation() {
263 double height = drawFlightData();
265 if (calculatingData) {
266 GlyphVector calculating = createText("Calculating...");
267 g2.setColor(Color.BLACK);
268 g2.drawGlyphVector(calculating, x1, (float)(y2-height));
273 private double drawFlightData() {
274 if (flightData == null)
279 GlyphVector apogee = createText("Apogee: ");
280 GlyphVector maxVelocity = createText("Max. velocity: ");
281 GlyphVector maxAcceleration = createText("Max. acceleration: ");
283 GlyphVector apogeeValue, velocityValue, accelerationValue;
284 if (!Double.isNaN(flightData.getMaxAltitude())) {
285 apogeeValue = createText(
286 UnitGroup.UNITS_DISTANCE.toStringUnit(flightData.getMaxAltitude()));
288 apogeeValue = createText("N/A");
290 if (!Double.isNaN(flightData.getMaxVelocity())) {
291 velocityValue = createText(
292 UnitGroup.UNITS_VELOCITY.toStringUnit(flightData.getMaxVelocity()) +
294 UnitGroup.UNITS_COEFFICIENT.toString(flightData.getMaxMachNumber()) + ")");
296 velocityValue = createText("N/A");
298 if (!Double.isNaN(flightData.getMaxAcceleration())) {
299 accelerationValue = createText(
300 UnitGroup.UNITS_ACCELERATION.toStringUnit(flightData.getMaxAcceleration()));
302 accelerationValue = createText("N/A");
306 rect = apogee.getVisualBounds();
307 width = MathUtil.max(width, rect.getWidth());
309 rect = maxVelocity.getVisualBounds();
310 width = MathUtil.max(width, rect.getWidth());
312 rect = maxAcceleration.getVisualBounds();
313 width = MathUtil.max(width, rect.getWidth());
317 if (!calculatingData)
318 g2.setColor(new Color(0,0,127));
320 g2.setColor(new Color(0,0,127,127));
323 g2.drawGlyphVector(apogee, (float)x1, (float)(y2-2*line));
324 g2.drawGlyphVector(maxVelocity, (float)x1, (float)(y2-line));
325 g2.drawGlyphVector(maxAcceleration, (float)x1, (float)(y2));
327 g2.drawGlyphVector(apogeeValue, (float)(x1+width), (float)(y2-2*line));
328 g2.drawGlyphVector(velocityValue, (float)(x1+width), (float)(y2-line));
329 g2.drawGlyphVector(accelerationValue, (float)(x1+width), (float)(y2));
336 private GlyphVector createText(String text) {
337 return FONT.createGlyphVector(g2.getFontRenderContext(), text);
340 private GlyphVector createSmallText(String text) {
341 return SMALLFONT.createGlyphVector(g2.getFontRenderContext(), text);