]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/gui/ProfileChart.java
Version 9, February 2010
[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.config.ColourScheme;
10 import tim.prune.config.Config;
11 import tim.prune.data.Altitude;
12 import tim.prune.data.AltitudeRange;
13 import tim.prune.data.Track;
14 import tim.prune.data.TrackInfo;
15
16 /**
17  * Chart component for the profile display
18  */
19 public class ProfileChart extends GenericChart
20 {
21         /** Current scale factor in x direction*/
22         private double _xScaleFactor = 0.0;
23         /** Possible altitude scales to use */
24         private static final int[] ALTITUDE_SCALES = {10000, 5000, 2000, 1000, 500, 200, 100, 50};
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          * @param g Graphics object
42          */
43         public void paint(Graphics g)
44         {
45                 super.paint(g);
46                 if (_track != null && _track.getNumPoints() > 0)
47                 {
48                         int width = getWidth();
49                         int height = getHeight();
50
51                         // Set up colours
52                         final Color barColour = Config.getColourScheme().getColour(ColourScheme.IDX_POINT);
53                         final Color rangeColour = Config.getColourScheme().getColour(ColourScheme.IDX_SELECTION);
54                         final Color currentColour = Config.getColourScheme().getColour(ColourScheme.IDX_PRIMARY);
55                         final Color secondColour = Config.getColourScheme().getColour(ColourScheme.IDX_SECONDARY);
56                         final Color lineColour = Config.getColourScheme().getColour(ColourScheme.IDX_LINES);
57
58                         // message if no altitudes in track
59                         if (!_track.hasAltitudeData())
60                         {
61                                 g.setColor(lineColour);
62                                 g.drawString(I18nManager.getText("display.noaltitudes"), 50, height/2);
63                                 return;
64                         }
65
66                         // altitude profile
67                         AltitudeRange altitudeRange = _track.getAltitudeRange();
68                         int minAltitude = altitudeRange.getMinimum();
69                         int maxAltitude = altitudeRange.getMaximum();
70                         int numPoints = _track.getNumPoints();
71                         _xScaleFactor = 1.0 * (width - 2 * BORDER_WIDTH - 1) / numPoints;
72                         double yScaleFactor = 1.0 * (height - 2 * BORDER_WIDTH) / (maxAltitude - minAltitude);
73                         int barWidth = (int) (_xScaleFactor + 1.0);
74                         int selectedPoint = _trackInfo.getSelection().getCurrentPointIndex();
75                         // selection start, end
76                         int selectionStart = -1, selectionEnd = -1;
77                         if (_trackInfo.getSelection().hasRangeSelected()) {
78                                 selectionStart = _trackInfo.getSelection().getStart();
79                                 selectionEnd = _trackInfo.getSelection().getEnd();
80                         }
81
82                         // horizontal lines for scale - set to round numbers eg 500m
83                         int lineScale = getLineScale(minAltitude, maxAltitude);
84                         int altitude = 0;
85                         int x = 0, y = 0;
86                         if (lineScale > 1)
87                         {
88                                 g.setColor(lineColour);
89                                 while (altitude < maxAltitude)
90                                 {
91                                         if (altitude > minAltitude)
92                                         {
93                                                 y = height - BORDER_WIDTH - (int) (yScaleFactor * (altitude - minAltitude));
94                                                 g.drawLine(BORDER_WIDTH + 1, y, width - BORDER_WIDTH - 1, y);
95                                         }
96                                         altitude += lineScale;
97                                 }
98                         }
99
100                         try
101                         {
102                                 // loop through points
103                                 Altitude.Format chartFormat = altitudeRange.getFormat();
104                                 g.setColor(barColour);
105                                 for (int p = 0; p < numPoints; p++)
106                                 {
107                                         x = (int) (_xScaleFactor * p) + 1;
108                                         if (p == selectionStart)
109                                                 g.setColor(rangeColour);
110                                         else if (p == (selectionEnd+1))
111                                                 g.setColor(barColour);
112                                         if (_track.getPoint(p).getAltitude().isValid())
113                                         {
114                                                 altitude = _track.getPoint(p).getAltitude().getValue(chartFormat);
115                                                 y = (int) (yScaleFactor * (altitude - minAltitude));
116                                                 g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
117                                         }
118                                 }
119                                 // current point (make sure it's drawn last)
120                                 if (selectedPoint > -1)
121                                 {
122                                         Altitude alt = _track.getPoint(selectedPoint).getAltitude();
123                                         if (alt.isValid())
124                                         {
125                                                 x = (int) (_xScaleFactor * selectedPoint) + 1;
126                                                 g.setColor(secondColour);
127                                                 g.fillRect(BORDER_WIDTH + x, BORDER_WIDTH+1, barWidth, height-2*BORDER_WIDTH-2);
128                                                 g.setColor(currentColour);
129                                                 altitude = alt.getValue(chartFormat);
130                                                 y = (int) (yScaleFactor * (altitude - minAltitude));
131                                                 g.fillRect(BORDER_WIDTH + x, height-BORDER_WIDTH - y, barWidth, y);
132                                         }
133                                 }
134                         }
135                         catch (NullPointerException npe) { // ignore, probably due to data being changed
136                         }
137                         // Draw numbers on top of the graph to mark scale
138                         if (lineScale > 1)
139                         {
140                                 int textHeight = g.getFontMetrics().getHeight();
141                                 altitude = 0;
142                                 y = 0;
143                                 g.setColor(currentColour);
144                                 while (altitude < maxAltitude)
145                                 {
146                                         if (altitude > minAltitude)
147                                         {
148                                                 y = height - BORDER_WIDTH - (int) (yScaleFactor * (altitude - minAltitude));
149                                                 // Limit y so String isn't above border
150                                                 if (y < (BORDER_WIDTH + textHeight))
151                                                 {
152                                                         y = BORDER_WIDTH + textHeight;
153                                                 }
154                                                 g.drawString(""+altitude, BORDER_WIDTH + 5, y);
155                                         }
156                                         altitude += lineScale;
157                                 }
158                         }
159                 }
160         }
161
162
163         /**
164          * Work out the scale for the horizontal lines
165          * @param inMin min altitude of data
166          * @param inMax max altitude of data
167          * @return scale separation, or -1 for no scale
168          */
169         private int getLineScale(int inMin, int inMax)
170         {
171                 if ((inMax - inMin) < 50 || inMax < 0)
172                 {
173                         return -1;
174                 }
175                 int numScales = ALTITUDE_SCALES.length;
176                 int scale = 0;
177                 int numLines = 0;
178                 int altitude = 0;
179                 for (int i=0; i<numScales; i++)
180                 {
181                         scale = ALTITUDE_SCALES[i];
182                         if (scale < inMax)
183                         {
184                                 numLines = 0;
185                                 altitude = 0;
186                                 while (altitude < inMax)
187                                 {
188                                         altitude += scale;
189                                         if (altitude > inMin)
190                                         {
191                                                 numLines++;
192                                         }
193                                 }
194                                 if (numLines > 2)
195                                 {
196                                         return scale;
197                                 }
198                         }
199                 }
200                 // no suitable scale found so just use minimum
201                 return ALTITUDE_SCALES[numScales-1];
202         }
203
204
205         /**
206          * Method to inform map that data has changed
207          * @param inTrack track object
208          */
209         public void dataUpdated(Track inTrack)
210         {
211                 _track = inTrack;
212                 repaint();
213         }
214
215
216         /**
217          * React to click on profile display
218          */
219         public void mouseClicked(MouseEvent e)
220         {
221                 // ignore right clicks
222                 if (_track != null && !e.isMetaDown())
223                 {
224                         int xClick = e.getX();
225                         int yClick = e.getY();
226                         // Check click is within main area (not in border)
227                         if (xClick > BORDER_WIDTH && yClick > BORDER_WIDTH && xClick < (getWidth() - BORDER_WIDTH)
228                                 && yClick < (getHeight() - BORDER_WIDTH))
229                         {
230                                 // work out which data point is nearest and select it
231                                 int pointNum = (int) ((e.getX() - BORDER_WIDTH) / _xScaleFactor);
232                                 // If shift clicked, then extend selection
233                                 if (e.isShiftDown()) {
234                                         _trackInfo.extendSelection(pointNum);
235                                 }
236                                 else {
237                                         _trackInfo.selectPoint(pointNum);
238                                 }
239                         }
240                 }
241         }
242 }