]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/gui/ProfileChart.java
Version 1, September 2006
[GpsPrune.git] / tim / prune / gui / ProfileChart.java
1 package tim.prune.gui;
2
3 import java.awt.Color;
4 import java.awt.Dimension;
5 import java.awt.Graphics;
6 import java.awt.event.MouseEvent;
7
8 import tim.prune.I18nManager;
9 import tim.prune.data.AltitudeRange;
10 import tim.prune.data.Track;
11 import tim.prune.data.TrackInfo;
12
13 /**
14  * Chart component for the profile display
15  */
16 public class ProfileChart extends GenericChart
17 {
18         private double _xScaleFactor = 0.0;
19         private static final int[] ALTITUDE_SCALES = {10000, 5000, 2000, 1000, 500, 200, 100, 50};
20         private static final Color COLOR_LINES       = Color.GRAY;
21         private static final Color COLOR_ALT_BARS    = Color.BLUE;
22         private static final Color COLOR_SELECTED    = Color.RED;
23         private static final Color COLOR_SELECTED_BG = Color.ORANGE;
24         private static final Color COLOR_ALT_SCALE   = Color.RED;
25
26
27         /**
28          * Constructor
29          * @param inTrackInfo Track info object
30          */
31         public ProfileChart(TrackInfo inTrackInfo)
32         {
33                 super(inTrackInfo);
34                 MINIMUM_SIZE = new Dimension(200, 100);
35                 addMouseListener(this);
36         }
37
38
39         /**
40          * Override paint method to draw map
41          */
42         public void paint(Graphics g)
43         {
44                 super.paint(g);
45                 if (_track != null && _track.getNumPoints() > 0)
46                 {
47                         int width = getWidth();
48                         int height = getHeight();
49                         AltitudeRange altitudeRange = _track.getAltitudeRange();
50                         int minAltitude = altitudeRange.getMinimum();
51                         int maxAltitude = altitudeRange.getMaximum();
52
53                         // message if no altitudes in track
54                         if (minAltitude < 0 || maxAltitude < 0)
55                         {
56                                 g.setColor(COLOR_LINES);
57                                 g.drawString(I18nManager.getText("display.noaltitudes"), 50, height/2);
58                                 return;
59                         }
60
61                         // altitude profile
62                         int numPoints = _track.getNumPoints();
63                         _xScaleFactor = 1.0 * (width - 2 * BORDER_WIDTH) / numPoints;
64                         double yScaleFactor = 1.0 * (height - 2 * BORDER_WIDTH) /
65                           (altitudeRange.getMaximum() - minAltitude);
66                         int barWidth = (int) (_xScaleFactor + 1.0);
67                         int selectedPoint = _trackInfo.getSelection().getCurrentPointIndex();
68
69                         // horizontal lines for scale - set to round numbers eg 500m
70                         int lineScale = getLineScale(minAltitude, maxAltitude);
71                         int altitude = 0;
72                         int y = 0;
73                         if (lineScale > 1)
74                         {
75                                 g.setColor(COLOR_LINES);
76                                 while (altitude < maxAltitude)
77                                 {
78                                         if (altitude > minAltitude)
79                                         {
80                                                 y = height - BORDER_WIDTH - (int) (yScaleFactor * (altitude - minAltitude));
81                                                 g.drawLine(BORDER_WIDTH + 1, y, width - BORDER_WIDTH - 1, y);
82                                         }
83                                         altitude += lineScale;
84                                 }
85                         }
86
87                         // loop through points
88                         int chartFormat = altitudeRange.getFormat();
89                         for (int p = 0; p < numPoints; p++)
90                         {
91                                 int x = (int) (_xScaleFactor * p);
92                                 if (p == selectedPoint)
93                                 {
94                                         g.setColor(COLOR_SELECTED_BG);
95                                         g.fillRect(BORDER_WIDTH + x, BORDER_WIDTH+1, barWidth, height-2*BORDER_WIDTH-2);
96                                         g.setColor(COLOR_SELECTED);
97                                 }
98                                 else
99                                 {
100                                         g.setColor(COLOR_ALT_BARS);
101                                 }
102                                 if (_track.getPoint(p).getAltitude().isValid())
103                                 {
104                                         altitude = _track.getPoint(p).getAltitude().getValue(chartFormat);
105                                         y = (int) (yScaleFactor * (altitude - minAltitude));
106                                         g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
107                                 }
108                         }
109                         // Draw numbers on top of the graph to mark scale
110                         if (lineScale > 1)
111                         {
112                                 int textHeight = g.getFontMetrics().getHeight();
113                                 altitude = 0;
114                                 y = 0;
115                                 g.setColor(COLOR_ALT_SCALE);
116                                 while (altitude < maxAltitude)
117                                 {
118                                         if (altitude > minAltitude)
119                                         {
120                                                 y = height - BORDER_WIDTH - (int) (yScaleFactor * (altitude - minAltitude));
121                                                 // Limit y so String isn't above border
122                                                 if (y < (BORDER_WIDTH + textHeight))
123                                                 {
124                                                         y = BORDER_WIDTH + textHeight;
125                                                 }
126                                                 g.drawString(""+altitude, BORDER_WIDTH + 5, y);
127                                         }
128                                         altitude += lineScale;
129                                 }
130                         }
131                 }
132         }
133
134
135         /**
136          * Work out the scale for the horizontal lines
137          * @param inMin min altitude of data
138          * @param inMax max altitude of data
139          * @return scale separation, or -1 for no scale
140          */
141         private int getLineScale(int inMin, int inMax)
142         {
143                 if ((inMax - inMin) < 50 || inMax < 0)
144                 {
145                         return -1;
146                 }
147                 int numScales = ALTITUDE_SCALES.length;
148                 int scale = 0;
149                 int numLines = 0;
150                 int altitude = 0;
151                 for (int i=0; i<numScales; i++)
152                 {
153                         scale = ALTITUDE_SCALES[i];
154                         if (scale < inMax)
155                         {
156                                 numLines = 0;
157                                 altitude = 0;
158                                 while (altitude < inMax)
159                                 {
160                                         altitude += scale;
161                                         if (altitude > inMin)
162                                         {
163                                                 numLines++;
164                                         }
165                                 }
166                                 if (numLines > 2)
167                                 {
168                                         return scale;
169                                 }
170                         }
171                 }
172                 // no suitable scale found so just use minimum
173                 return ALTITUDE_SCALES[numScales-1];
174         }
175
176
177         /**
178          * Method to inform map that data has changed
179          */
180         public void dataUpdated(Track inTrack)
181         {
182                 _track = inTrack;
183                 repaint();
184         }
185
186
187         /**
188          * React to click on profile display
189          */
190         public void mouseClicked(MouseEvent e)
191         {
192                 // ignore right clicks
193                 if (_track != null && !e.isMetaDown())
194                 {
195                         int xClick = e.getX();
196                         int yClick = e.getY();
197                         // Check click is within main area (not in border)
198                         if (xClick > BORDER_WIDTH && yClick > BORDER_WIDTH && xClick < (getWidth() - BORDER_WIDTH)
199                                 && yClick < (getHeight() - BORDER_WIDTH))
200                         {
201                                 // work out which data point is nearest and select it
202                                 int pointNum = (int) ((e.getX() - BORDER_WIDTH) / _xScaleFactor);
203                                 _trackInfo.getSelection().selectPoint(pointNum);
204                         }
205                 }
206         }
207 }