]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/gui/ProfileChart.java
Version 4, January 2008
[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          * @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                         AltitudeRange altitudeRange = _track.getAltitudeRange();
51                         int minAltitude = altitudeRange.getMinimum();
52                         int maxAltitude = altitudeRange.getMaximum();
53
54                         // message if no altitudes in track
55                         if (minAltitude < 0 || maxAltitude < 0
56                                 || minAltitude == maxAltitude)
57                         {
58                                 g.setColor(COLOR_LINES);
59                                 g.drawString(I18nManager.getText("display.noaltitudes"), 50, height/2);
60                                 return;
61                         }
62
63                         // altitude profile
64                         int numPoints = _track.getNumPoints();
65                         _xScaleFactor = 1.0 * (width - 2 * BORDER_WIDTH) / numPoints;
66                         double yScaleFactor = 1.0 * (height - 2 * BORDER_WIDTH) /
67                           (altitudeRange.getMaximum() - minAltitude);
68                         int barWidth = (int) (_xScaleFactor + 1.0);
69                         int selectedPoint = _trackInfo.getSelection().getCurrentPointIndex();
70
71                         // horizontal lines for scale - set to round numbers eg 500m
72                         int lineScale = getLineScale(minAltitude, maxAltitude);
73                         int altitude = 0;
74                         int y = 0;
75                         if (lineScale > 1)
76                         {
77                                 g.setColor(COLOR_LINES);
78                                 while (altitude < maxAltitude)
79                                 {
80                                         if (altitude > minAltitude)
81                                         {
82                                                 y = height - BORDER_WIDTH - (int) (yScaleFactor * (altitude - minAltitude));
83                                                 g.drawLine(BORDER_WIDTH + 1, y, width - BORDER_WIDTH - 1, y);
84                                         }
85                                         altitude += lineScale;
86                                 }
87                         }
88
89                         // loop through points
90                         int chartFormat = altitudeRange.getFormat();
91                         for (int p = 0; p < numPoints; p++)
92                         {
93                                 int x = (int) (_xScaleFactor * p);
94                                 if (p == selectedPoint)
95                                 {
96                                         g.setColor(COLOR_SELECTED_BG);
97                                         g.fillRect(BORDER_WIDTH + x, BORDER_WIDTH+1, barWidth, height-2*BORDER_WIDTH-2);
98                                         g.setColor(COLOR_SELECTED);
99                                 }
100                                 else
101                                 {
102                                         g.setColor(COLOR_ALT_BARS);
103                                 }
104                                 if (_track.getPoint(p).getAltitude().isValid())
105                                 {
106                                         altitude = _track.getPoint(p).getAltitude().getValue(chartFormat);
107                                         y = (int) (yScaleFactor * (altitude - minAltitude));
108                                         g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
109                                 }
110                         }
111                         // Draw numbers on top of the graph to mark scale
112                         if (lineScale > 1)
113                         {
114                                 int textHeight = g.getFontMetrics().getHeight();
115                                 altitude = 0;
116                                 y = 0;
117                                 g.setColor(COLOR_ALT_SCALE);
118                                 while (altitude < maxAltitude)
119                                 {
120                                         if (altitude > minAltitude)
121                                         {
122                                                 y = height - BORDER_WIDTH - (int) (yScaleFactor * (altitude - minAltitude));
123                                                 // Limit y so String isn't above border
124                                                 if (y < (BORDER_WIDTH + textHeight))
125                                                 {
126                                                         y = BORDER_WIDTH + textHeight;
127                                                 }
128                                                 g.drawString(""+altitude, BORDER_WIDTH + 5, y);
129                                         }
130                                         altitude += lineScale;
131                                 }
132                         }
133                 }
134         }
135
136
137         /**
138          * Work out the scale for the horizontal lines
139          * @param inMin min altitude of data
140          * @param inMax max altitude of data
141          * @return scale separation, or -1 for no scale
142          */
143         private int getLineScale(int inMin, int inMax)
144         {
145                 if ((inMax - inMin) < 50 || inMax < 0)
146                 {
147                         return -1;
148                 }
149                 int numScales = ALTITUDE_SCALES.length;
150                 int scale = 0;
151                 int numLines = 0;
152                 int altitude = 0;
153                 for (int i=0; i<numScales; i++)
154                 {
155                         scale = ALTITUDE_SCALES[i];
156                         if (scale < inMax)
157                         {
158                                 numLines = 0;
159                                 altitude = 0;
160                                 while (altitude < inMax)
161                                 {
162                                         altitude += scale;
163                                         if (altitude > inMin)
164                                         {
165                                                 numLines++;
166                                         }
167                                 }
168                                 if (numLines > 2)
169                                 {
170                                         return scale;
171                                 }
172                         }
173                 }
174                 // no suitable scale found so just use minimum
175                 return ALTITUDE_SCALES[numScales-1];
176         }
177
178
179         /**
180          * Method to inform map that data has changed
181          * @param inTrack track object
182          */
183         public void dataUpdated(Track inTrack)
184         {
185                 _track = inTrack;
186                 repaint();
187         }
188
189
190         /**
191          * React to click on profile display
192          */
193         public void mouseClicked(MouseEvent e)
194         {
195                 // ignore right clicks
196                 if (_track != null && !e.isMetaDown())
197                 {
198                         int xClick = e.getX();
199                         int yClick = e.getY();
200                         // Check click is within main area (not in border)
201                         if (xClick > BORDER_WIDTH && yClick > BORDER_WIDTH && xClick < (getWidth() - BORDER_WIDTH)
202                                 && yClick < (getHeight() - BORDER_WIDTH))
203                         {
204                                 // work out which data point is nearest and select it
205                                 int pointNum = (int) ((e.getX() - BORDER_WIDTH) / _xScaleFactor);
206                                 _trackInfo.getSelection().selectPoint(pointNum);
207                         }
208                 }
209         }
210 }