]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/gui/ProfileChart.java
Version 1, September 2006
[GpsPrune.git] / tim / prune / gui / ProfileChart.java
diff --git a/tim/prune/gui/ProfileChart.java b/tim/prune/gui/ProfileChart.java
new file mode 100644 (file)
index 0000000..431da0d
--- /dev/null
@@ -0,0 +1,207 @@
+package tim.prune.gui;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.event.MouseEvent;
+
+import tim.prune.I18nManager;
+import tim.prune.data.AltitudeRange;
+import tim.prune.data.Track;
+import tim.prune.data.TrackInfo;
+
+/**
+ * Chart component for the profile display
+ */
+public class ProfileChart extends GenericChart
+{
+       private double _xScaleFactor = 0.0;
+       private static final int[] ALTITUDE_SCALES = {10000, 5000, 2000, 1000, 500, 200, 100, 50};
+       private static final Color COLOR_LINES       = Color.GRAY;
+       private static final Color COLOR_ALT_BARS    = Color.BLUE;
+       private static final Color COLOR_SELECTED    = Color.RED;
+       private static final Color COLOR_SELECTED_BG = Color.ORANGE;
+       private static final Color COLOR_ALT_SCALE   = Color.RED;
+
+
+       /**
+        * Constructor
+        * @param inTrackInfo Track info object
+        */
+       public ProfileChart(TrackInfo inTrackInfo)
+       {
+               super(inTrackInfo);
+               MINIMUM_SIZE = new Dimension(200, 100);
+               addMouseListener(this);
+       }
+
+
+       /**
+        * Override paint method to draw map
+        */
+       public void paint(Graphics g)
+       {
+               super.paint(g);
+               if (_track != null && _track.getNumPoints() > 0)
+               {
+                       int width = getWidth();
+                       int height = getHeight();
+                       AltitudeRange altitudeRange = _track.getAltitudeRange();
+                       int minAltitude = altitudeRange.getMinimum();
+                       int maxAltitude = altitudeRange.getMaximum();
+
+                       // message if no altitudes in track
+                       if (minAltitude < 0 || maxAltitude < 0)
+                       {
+                               g.setColor(COLOR_LINES);
+                               g.drawString(I18nManager.getText("display.noaltitudes"), 50, height/2);
+                               return;
+                       }
+
+                       // altitude profile
+                       int numPoints = _track.getNumPoints();
+                       _xScaleFactor = 1.0 * (width - 2 * BORDER_WIDTH) / numPoints;
+                       double yScaleFactor = 1.0 * (height - 2 * BORDER_WIDTH) /
+                         (altitudeRange.getMaximum() - minAltitude);
+                       int barWidth = (int) (_xScaleFactor + 1.0);
+                       int selectedPoint = _trackInfo.getSelection().getCurrentPointIndex();
+
+                       // horizontal lines for scale - set to round numbers eg 500m
+                       int lineScale = getLineScale(minAltitude, maxAltitude);
+                       int altitude = 0;
+                       int y = 0;
+                       if (lineScale > 1)
+                       {
+                               g.setColor(COLOR_LINES);
+                               while (altitude < maxAltitude)
+                               {
+                                       if (altitude > minAltitude)
+                                       {
+                                               y = height - BORDER_WIDTH - (int) (yScaleFactor * (altitude - minAltitude));
+                                               g.drawLine(BORDER_WIDTH + 1, y, width - BORDER_WIDTH - 1, y);
+                                       }
+                                       altitude += lineScale;
+                               }
+                       }
+
+                       // loop through points
+                       int chartFormat = altitudeRange.getFormat();
+                       for (int p = 0; p < numPoints; p++)
+                       {
+                               int x = (int) (_xScaleFactor * p);
+                               if (p == selectedPoint)
+                               {
+                                       g.setColor(COLOR_SELECTED_BG);
+                                       g.fillRect(BORDER_WIDTH + x, BORDER_WIDTH+1, barWidth, height-2*BORDER_WIDTH-2);
+                                       g.setColor(COLOR_SELECTED);
+                               }
+                               else
+                               {
+                                       g.setColor(COLOR_ALT_BARS);
+                               }
+                               if (_track.getPoint(p).getAltitude().isValid())
+                               {
+                                       altitude = _track.getPoint(p).getAltitude().getValue(chartFormat);
+                                       y = (int) (yScaleFactor * (altitude - minAltitude));
+                                       g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
+                               }
+                       }
+                       // Draw numbers on top of the graph to mark scale
+                       if (lineScale > 1)
+                       {
+                               int textHeight = g.getFontMetrics().getHeight();
+                               altitude = 0;
+                               y = 0;
+                               g.setColor(COLOR_ALT_SCALE);
+                               while (altitude < maxAltitude)
+                               {
+                                       if (altitude > minAltitude)
+                                       {
+                                               y = height - BORDER_WIDTH - (int) (yScaleFactor * (altitude - minAltitude));
+                                               // Limit y so String isn't above border
+                                               if (y < (BORDER_WIDTH + textHeight))
+                                               {
+                                                       y = BORDER_WIDTH + textHeight;
+                                               }
+                                               g.drawString(""+altitude, BORDER_WIDTH + 5, y);
+                                       }
+                                       altitude += lineScale;
+                               }
+                       }
+               }
+       }
+
+
+       /**
+        * Work out the scale for the horizontal lines
+        * @param inMin min altitude of data
+        * @param inMax max altitude of data
+        * @return scale separation, or -1 for no scale
+        */
+       private int getLineScale(int inMin, int inMax)
+       {
+               if ((inMax - inMin) < 50 || inMax < 0)
+               {
+                       return -1;
+               }
+               int numScales = ALTITUDE_SCALES.length;
+               int scale = 0;
+               int numLines = 0;
+               int altitude = 0;
+               for (int i=0; i<numScales; i++)
+               {
+                       scale = ALTITUDE_SCALES[i];
+                       if (scale < inMax)
+                       {
+                               numLines = 0;
+                               altitude = 0;
+                               while (altitude < inMax)
+                               {
+                                       altitude += scale;
+                                       if (altitude > inMin)
+                                       {
+                                               numLines++;
+                                       }
+                               }
+                               if (numLines > 2)
+                               {
+                                       return scale;
+                               }
+                       }
+               }
+               // no suitable scale found so just use minimum
+               return ALTITUDE_SCALES[numScales-1];
+       }
+
+
+       /**
+        * Method to inform map that data has changed
+        */
+       public void dataUpdated(Track inTrack)
+       {
+               _track = inTrack;
+               repaint();
+       }
+
+
+       /**
+        * React to click on profile display
+        */
+       public void mouseClicked(MouseEvent e)
+       {
+               // ignore right clicks
+               if (_track != null && !e.isMetaDown())
+               {
+                       int xClick = e.getX();
+                       int yClick = e.getY();
+                       // Check click is within main area (not in border)
+                       if (xClick > BORDER_WIDTH && yClick > BORDER_WIDTH && xClick < (getWidth() - BORDER_WIDTH)
+                               && yClick < (getHeight() - BORDER_WIDTH))
+                       {
+                               // work out which data point is nearest and select it
+                               int pointNum = (int) ((e.getX() - BORDER_WIDTH) / _xScaleFactor);
+                               _trackInfo.getSelection().selectPoint(pointNum);
+                       }
+               }
+       }
+}