]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/function/FullRangeDetails.java
Version 14, October 2012
[GpsPrune.git] / tim / prune / function / FullRangeDetails.java
index 338bf0bebbe1e1aef4d0130cf9b5d904b9c1a5c5..a0bae6517a09419dd5af77622f49b983de0e601e 100644 (file)
@@ -6,6 +6,8 @@ import java.awt.FlowLayout;
 import java.awt.GridLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
 import java.text.NumberFormat;
 
 import javax.swing.BorderFactory;
@@ -19,8 +21,10 @@ import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.config.Config;
 import tim.prune.data.Altitude;
-import tim.prune.data.Distance;
+import tim.prune.data.AltitudeRange;
+import tim.prune.data.DataPoint;
 import tim.prune.data.Selection;
+import tim.prune.data.Unit;
 import tim.prune.gui.DisplayUtils;
 import tim.prune.gui.profile.SpeedData;
 
@@ -31,15 +35,34 @@ public class FullRangeDetails extends GenericFunction
 {
        /** Dialog */
        private JDialog _dialog = null;
+       /** Label for number of points */
+       private JLabel _numPointsLabel = null;
        /** Label for number of segments */
        private JLabel _numSegsLabel = null;
-       /** Label for pace */
-       private JLabel _paceLabel = null;
-       /** Label for gradient */
-       private JLabel _gradientLabel = null;
-       /** Moving distance, speed */
-       private JLabel _movingDistanceLabel = null, _aveMovingSpeedLabel = null;
+       /** Label for the maximum speed */
        private JLabel _maxSpeedLabel = null;
+
+       /** Label for heading of "total" column */
+       private JLabel _colTotalLabel = null;
+       /** Label for heading of "segments" column */
+       private JLabel _colSegmentsLabel = null;
+       /** Labels for distances */
+       private JLabel _totalDistanceLabel = null, _movingDistanceLabel = null;
+       /** Labels for durations */
+       private JLabel _totalDurationLabel = null, _movingDurationLabel = null;
+       /** Labels for climbs */
+       private JLabel _totalClimbLabel = null, _movingClimbLabel = null;
+       /** Labels for descents */
+       private JLabel _totalDescentLabel = null, _movingDescentLabel = null;
+       /** Labels for pace */
+       private JLabel _totalPaceLabel = null, _movingPaceLabel = null;
+       /** Labels for gradient */
+       private JLabel _totalGradientLabel = null, _movingGradientLabel = null;
+       /** Labels for speed */
+       private JLabel _totalSpeedLabel, _movingSpeedLabel = null;
+       /** Labels for vertical speed */
+       private JLabel _totalVertSpeedLabel, _movingVertSpeedLabel = null;
+
        /** Number formatter for one decimal place */
        private static final NumberFormat FORMAT_ONE_DP = NumberFormat.getNumberInstance();
        /** Flexible number formatter for different decimal places */
@@ -87,50 +110,116 @@ public class FullRangeDetails extends GenericFunction
                JPanel dialogPanel = new JPanel();
                dialogPanel.setLayout(new BorderLayout(5, 5));
                // Label at top
-               JLabel topLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.intro"));
+               JLabel topLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.intro") + ":");
                topLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
                dialogPanel.add(topLabel, BorderLayout.NORTH);
 
                // Details panel in middle
                JPanel midPanel = new JPanel();
-               midPanel.setLayout(new GridLayout(0, 2, 6, 2));
+               midPanel.setLayout(new GridLayout(0, 3, 6, 2));
                midPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
+               // Number of points
+               JLabel pointsLabel = new JLabel(I18nManager.getText("details.track.points") + ": ");
+               pointsLabel.setHorizontalAlignment(JLabel.RIGHT);
+               midPanel.add(pointsLabel);
+               _numPointsLabel = new JLabel("100");
+               midPanel.add(_numPointsLabel);
+               midPanel.add(new JLabel(" "));
                // Number of segments
                JLabel segLabel = new JLabel(I18nManager.getText("details.range.numsegments") + ": ");
                segLabel.setHorizontalAlignment(JLabel.RIGHT);
                midPanel.add(segLabel);
                _numSegsLabel = new JLabel("100");
                midPanel.add(_numSegsLabel);
+               midPanel.add(new JLabel(" "));
+               // Maximum speed
+               JLabel maxSpeedLabel = new JLabel(I18nManager.getText("details.range.maxspeed") + ": ");
+               maxSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
+               midPanel.add(maxSpeedLabel);
+               _maxSpeedLabel = new JLabel("10 km/h");
+               midPanel.add(_maxSpeedLabel);
+               midPanel.add(new JLabel(" "));
+
+               // blank row
+               for (int i=0; i<3; i++) midPanel.add(new JLabel(" "));
+
+               // Row for column headings
+               midPanel.add(new JLabel(" "));
+               _colTotalLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.coltotal"));
+               midPanel.add(_colTotalLabel);
+               _colSegmentsLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.colsegments"));
+               midPanel.add(_colSegmentsLabel);
+
+               // Distance
+               JLabel distLabel = new JLabel(I18nManager.getText("fieldname.distance") + ": ");
+               distLabel.setHorizontalAlignment(JLabel.RIGHT);
+               midPanel.add(distLabel);
+               _totalDistanceLabel = new JLabel("5 km");
+               midPanel.add(_totalDistanceLabel);
+               _movingDistanceLabel = new JLabel("5 km");
+               midPanel.add(_movingDistanceLabel);
+
+               // Duration
+               JLabel durationLabel = new JLabel(I18nManager.getText("fieldname.duration") + ": ");
+               durationLabel.setHorizontalAlignment(JLabel.RIGHT);
+               midPanel.add(durationLabel);
+               _totalDurationLabel = new JLabel("15 min");
+               midPanel.add(_totalDurationLabel);
+               _movingDurationLabel = new JLabel("15 min");
+               midPanel.add(_movingDurationLabel);
+
+               // Speed
+               JLabel speedLabel = new JLabel(I18nManager.getText("details.range.avespeed") + ": ");
+               speedLabel.setHorizontalAlignment(JLabel.RIGHT);
+               midPanel.add(speedLabel);
+               _totalSpeedLabel = new JLabel("5.5 km/h");
+               midPanel.add(_totalSpeedLabel);
+               _movingSpeedLabel = new JLabel("5.5 km/h");
+               midPanel.add(_movingSpeedLabel);
+
                // Pace
                JLabel paceLabel = new JLabel(I18nManager.getText("details.range.pace") + ": ");
                paceLabel.setHorizontalAlignment(JLabel.RIGHT);
                midPanel.add(paceLabel);
-               _paceLabel = new JLabel("8 min/km");
-               midPanel.add(_paceLabel);
+               _totalPaceLabel = new JLabel("8 min/km");
+               midPanel.add(_totalPaceLabel);
+               _movingPaceLabel = new JLabel("8 min/km");
+               midPanel.add(_movingPaceLabel);
+
+               // Climb
+               JLabel climbLabel = new JLabel(I18nManager.getText("details.range.climb") + ": ");
+               climbLabel.setHorizontalAlignment(JLabel.RIGHT);
+               midPanel.add(climbLabel);
+               _totalClimbLabel = new JLabel("1000 m");
+               midPanel.add(_totalClimbLabel);
+               _movingClimbLabel = new JLabel("1000 m");
+               midPanel.add(_movingClimbLabel);
+               // Descent
+               JLabel descentLabel = new JLabel(I18nManager.getText("details.range.descent") + ": ");
+               descentLabel.setHorizontalAlignment(JLabel.RIGHT);
+               midPanel.add(descentLabel);
+               _totalDescentLabel = new JLabel("1000 m");
+               midPanel.add(_totalDescentLabel);
+               _movingDescentLabel = new JLabel("1000 m");
+               midPanel.add(_movingDescentLabel);
+
                // Gradient
                JLabel gradientLabel = new JLabel(I18nManager.getText("details.range.gradient") + ": ");
                gradientLabel.setHorizontalAlignment(JLabel.RIGHT);
                midPanel.add(gradientLabel);
-               _gradientLabel = new JLabel("10 %");
-               midPanel.add(_gradientLabel);
-               // Moving distance
-               JLabel movingDistLabel = new JLabel(I18nManager.getText("fieldname.movingdistance") + ": ");
-               movingDistLabel.setHorizontalAlignment(JLabel.RIGHT);
-               midPanel.add(movingDistLabel);
-               _movingDistanceLabel = new JLabel("5 km");
-               midPanel.add(_movingDistanceLabel);
-               // Moving speed
-               JLabel movingSpeedLabel = new JLabel(I18nManager.getText("details.range.avemovingspeed") + ": ");
-               movingSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
-               midPanel.add(movingSpeedLabel);
-               _aveMovingSpeedLabel = new JLabel("5 km/h");
-               midPanel.add(_aveMovingSpeedLabel);
-               // Maximum speed
-               JLabel maxSpeedLabel = new JLabel(I18nManager.getText("details.range.maxspeed") + ": ");
-               maxSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
-               midPanel.add(maxSpeedLabel);
-               _maxSpeedLabel = new JLabel("10 km/h");
-               midPanel.add(_maxSpeedLabel);
+               _totalGradientLabel = new JLabel("10 %");
+               midPanel.add(_totalGradientLabel);
+               _movingGradientLabel = new JLabel("10 %");
+               midPanel.add(_movingGradientLabel);
+
+               // Vertical speed
+               JLabel vSpeedLabel = new JLabel(I18nManager.getText("fieldname.verticalspeed") + ": ");
+               vSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
+               midPanel.add(vSpeedLabel);
+               _totalVertSpeedLabel = new JLabel("1 m/s");
+               midPanel.add(_totalVertSpeedLabel);
+               _movingVertSpeedLabel = new JLabel("1 m/s");
+               midPanel.add(_movingVertSpeedLabel);
 
                dialogPanel.add(midPanel, BorderLayout.CENTER);
                // button panel at bottom
@@ -143,6 +232,12 @@ public class FullRangeDetails extends GenericFunction
                                _dialog.dispose();
                        }
                });
+               closeButton.addKeyListener(new KeyAdapter() {
+                       public void keyPressed(KeyEvent inE) {
+                               if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {_dialog.dispose();}
+                               super.keyPressed(inE);
+                       }
+               });
                buttonPanel.add(closeButton);
                dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
                return dialogPanel;
@@ -155,59 +250,153 @@ public class FullRangeDetails extends GenericFunction
        private void updateDetails()
        {
                Selection selection = _app.getTrackInfo().getSelection();
+               // Number of points
+               _numPointsLabel.setText("" + (selection.getEnd()-selection.getStart()+1));
                // Number of segments
                _numSegsLabel.setText("" + selection.getNumSegments());
-               // Pace value
-               if (selection.getNumSeconds() > 0)
+               final boolean isMultiSegments = (selection.getNumSegments() > 1);
+               // Set visibility of third column accordingly
+               _movingDistanceLabel.setVisible(isMultiSegments);
+               _movingDurationLabel.setVisible(isMultiSegments);
+               _movingClimbLabel.setVisible(isMultiSegments);
+               _movingDescentLabel.setVisible(isMultiSegments);
+               _movingSpeedLabel.setVisible(isMultiSegments);
+               _movingPaceLabel.setVisible(isMultiSegments);
+               _movingGradientLabel.setVisible(isMultiSegments);
+               _movingVertSpeedLabel.setVisible(isMultiSegments);
+
+               // Distance in current units
+               final Unit distUnit = Config.getUnitSet().getDistanceUnit();
+               final String distUnitsStr = I18nManager.getText(distUnit.getShortnameKey());
+               final double selectionDistance = selection.getDistance();
+               _totalDistanceLabel.setText(roundedNumber(selectionDistance) + " " + distUnitsStr);
+
+               // Duration
+               long numSecs = selection.getNumSeconds();
+               _totalDurationLabel.setText(DisplayUtils.buildDurationString(numSecs));
+               // Climb and descent
+               final Unit altUnit = Config.getUnitSet().getAltitudeUnit();
+               final String altUnitsStr = " " + I18nManager.getText(altUnit.getShortnameKey());
+               if (selection.getAltitudeRange().hasRange()) {
+                       _totalClimbLabel.setText(selection.getAltitudeRange().getClimb(altUnit) + altUnitsStr);
+                       _totalDescentLabel.setText(selection.getAltitudeRange().getDescent(altUnit) + altUnitsStr);
+               }
+               else {
+                       _totalClimbLabel.setText("");
+                       _totalDescentLabel.setText("");
+               }
+
+               // Overall pace and speed
+               final String speedUnitsStr = I18nManager.getText(Config.getUnitSet().getSpeedUnit().getShortnameKey());
+               if (numSecs > 0 && selectionDistance > 0)
                {
-                       boolean useMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
-                       Distance.Units distUnits = useMetric?Distance.Units.KILOMETRES:Distance.Units.MILES;
-                       String distUnitsStr = I18nManager.getText(useMetric?"units.kilometres.short":"units.miles.short");
-                       _paceLabel.setText(DisplayUtils.buildDurationString(
-                                       (long) (selection.getNumSeconds()/selection.getDistance(distUnits)))
+                       _totalPaceLabel.setText(
+                               DisplayUtils.buildDurationString((long) (numSecs/selectionDistance))
                                + " / " + distUnitsStr);
+                       _totalSpeedLabel.setText(roundedNumber(selectionDistance/numSecs*3600.0)
+                               + " " + speedUnitsStr);
                }
                else {
-                       _paceLabel.setText("");
+                       _totalPaceLabel.setText("");
+                       _totalSpeedLabel.setText("");
                }
-               // Gradient
-               Altitude firstAlt = _app.getTrackInfo().getTrack().getPoint(selection.getStart()).getAltitude();
-               Altitude lastAlt = _app.getTrackInfo().getTrack().getPoint(selection.getEnd()).getAltitude();
-               double metreDist = selection.getDistance(Distance.Units.METRES);
-               if (firstAlt.isValid() && lastAlt.isValid() && metreDist > 0.0)
+
+               // Moving distance
+               double movingDist = selection.getMovingDistance();
+               _movingDistanceLabel.setText(roundedNumber(movingDist) + " " + distUnitsStr);
+               // Moving average speed
+               long numMovingSecs = selection.getMovingSeconds();
+               if (numMovingSecs > 0)
+               {
+                       _movingDurationLabel.setText(DisplayUtils.buildDurationString(numMovingSecs));
+                       _movingSpeedLabel.setText(roundedNumber(movingDist/numMovingSecs*3600.0)
+                               + " " + speedUnitsStr);
+                       _movingPaceLabel.setText(
+                               DisplayUtils.buildDurationString((long) (numMovingSecs/movingDist))
+                               + " / " + distUnitsStr);
+               }
+               else
+               {
+                       _movingDurationLabel.setText("");
+                       _movingSpeedLabel.setText("");
+                       _movingPaceLabel.setText("");
+               }
+
+               // Moving gradient and moving climb/descent
+               Altitude firstAlt = null, lastAlt = null;
+               Altitude veryFirstAlt = null, veryLastAlt = null;
+               AltitudeRange altRange = new AltitudeRange();
+               double movingHeightDiff = 0.0;
+               if (movingDist > 0.0)
+               {
+                       for (int pNum = selection.getStart(); pNum <= selection.getEnd(); pNum++)
+                       {
+                               DataPoint p = _app.getTrackInfo().getTrack().getPoint(pNum);
+                               if (p != null && !p.isWaypoint())
+                               {
+                                       // If we're starting a new segment, calculate the height diff of the previous one
+                                       if (p.getSegmentStart())
+                                       {
+                                               if (firstAlt != null && firstAlt.isValid() && lastAlt != null && lastAlt.isValid())
+                                                       movingHeightDiff = movingHeightDiff + lastAlt.getMetricValue() - firstAlt.getMetricValue();
+                                               firstAlt = null; lastAlt = null;
+                                       }
+                                       Altitude alt = p.getAltitude();
+                                       if (alt != null && alt.isValid())
+                                       {
+                                               if (firstAlt == null) firstAlt = alt;
+                                               else lastAlt = alt;
+                                               if (veryFirstAlt == null) veryFirstAlt = alt;
+                                               else veryLastAlt = alt;
+                                       }
+                                       // Keep track of climb and descent too
+                                       if (p.getSegmentStart())
+                                               altRange.ignoreValue(alt);
+                                       else
+                                               altRange.addValue(alt);
+                               }
+                       }
+                       // deal with last segment
+                       if (firstAlt != null && firstAlt.isValid() && lastAlt != null && lastAlt.isValid())
+                               movingHeightDiff = movingHeightDiff + lastAlt.getMetricValue() - firstAlt.getMetricValue();
+                       final double metricMovingDist = movingDist / distUnit.getMultFactorFromStd(); // convert back to metres
+                       final double gradient = movingHeightDiff * 100.0 / metricMovingDist;
+                       _movingGradientLabel.setText(FORMAT_ONE_DP.format(gradient) + " %");
+               }
+               if (!altRange.hasRange()) {
+                       _movingGradientLabel.setText("");
+               }
+               final boolean hasAltitudes = veryFirstAlt != null && veryFirstAlt.isValid() && veryLastAlt != null && veryLastAlt.isValid();
+
+               // Total gradient
+               final double metreDist = selection.getDistance() / distUnit.getMultFactorFromStd(); // convert back to metres
+               if (hasAltitudes && metreDist > 0.0)
                {
                        // got an altitude and range
-                       int altDiffInMetres = lastAlt.getValue(Altitude.Format.METRES) - firstAlt.getValue(Altitude.Format.METRES);
+                       int altDiffInMetres = veryLastAlt.getValue(Altitude.Format.METRES) - veryFirstAlt.getValue(Altitude.Format.METRES);
                        double gradient = altDiffInMetres * 100.0 / metreDist;
-                       _gradientLabel.setText(FORMAT_ONE_DP.format(gradient) + " %");
+                       _totalGradientLabel.setText(FORMAT_ONE_DP.format(gradient) + " %");
                }
                else {
                        // no altitude given
-                       _gradientLabel.setText("");
+                       _totalGradientLabel.setText("");
                }
 
-               // Show moving distance and average even when number of segments is 1
-               final boolean isMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
-               final Distance.Units distUnits = isMetric?Distance.Units.KILOMETRES:Distance.Units.MILES;
-               final String distUnitsStr = I18nManager.getText(isMetric?"units.kilometres.short":"units.miles.short");
-               final String speedUnitsStr = I18nManager.getText(isMetric?"units.kmh":"units.mph");
-               // Moving distance
-               _movingDistanceLabel.setText(roundedNumber(selection.getMovingDistance(distUnits)) + " " + distUnitsStr);
-               // Moving average speed
-               long numSecs = selection.getMovingSeconds();
-               if (numSecs > 0) {
-                       _aveMovingSpeedLabel.setText(roundedNumber(selection.getMovingDistance(distUnits)/numSecs*3600.0)
-                               + " " + speedUnitsStr);
+               // Moving climb/descent
+               if (altRange.hasRange()) {
+                       _movingClimbLabel.setText(altRange.getClimb(altUnit) + altUnitsStr);
+                       _movingDescentLabel.setText(altRange.getDescent(altUnit) + altUnitsStr);
                }
                else {
-                       _aveMovingSpeedLabel.setText("");
+                       _movingClimbLabel.setText("");
+                       _movingDescentLabel.setText("");
                }
-
                // Maximum speed
                SpeedData speeds = new SpeedData(_app.getTrackInfo().getTrack());
-               speeds.init();
+               speeds.init(Config.getUnitSet());
                double maxSpeed = 0.0;
-               for (int i=selection.getStart(); i<=selection.getEnd(); i++) {
+               for (int i=selection.getStart(); i<=selection.getEnd(); i++)
+               {
                        if (speeds.hasData(i) && (speeds.getData(i) > maxSpeed)) {
                                maxSpeed = speeds.getData(i);
                        }
@@ -218,6 +407,23 @@ public class FullRangeDetails extends GenericFunction
                else {
                        _maxSpeedLabel.setText("");
                }
+
+               // vertical speed
+               final String vertSpeedUnitsStr = I18nManager.getText(Config.getUnitSet().getVerticalSpeedUnit().getShortnameKey());
+               if (hasAltitudes && metreDist > 0.0 && numSecs > 0)
+               {
+                       // got an altitude and time - do total
+                       final int altDiffInMetres = veryLastAlt.getValue(Altitude.Format.METRES) - veryFirstAlt.getValue(Altitude.Format.METRES);
+                       final double altDiff = altDiffInMetres * altUnit.getMultFactorFromStd();
+                       _totalVertSpeedLabel.setText(roundedNumber(altDiff/numSecs) + " " + vertSpeedUnitsStr);
+                       // and moving
+                       _movingVertSpeedLabel.setText(roundedNumber(movingHeightDiff * altUnit.getMultFactorFromStd() / numMovingSecs) + " " + vertSpeedUnitsStr);
+               }
+               else {
+                       // no vertical speed available
+                       _totalVertSpeedLabel.setText("");
+                       _movingVertSpeedLabel.setText("");
+               }
        }
 
        /**