X-Git-Url: https://gitweb.fperrin.net/?p=GpsPrune.git;a=blobdiff_plain;f=tim%2Fprune%2Ffunction%2FFullRangeDetails.java;h=a0bae6517a09419dd5af77622f49b983de0e601e;hp=338bf0bebbe1e1aef4d0130cf9b5d904b9c1a5c5;hb=4d5796d02a15808311c09448d79e6e7d1de9d636;hpb=f1b92378a792131ac8fb33a869405851d5b2d1f7 diff --git a/tim/prune/function/FullRangeDetails.java b/tim/prune/function/FullRangeDetails.java index 338bf0b..a0bae65 100644 --- a/tim/prune/function/FullRangeDetails.java +++ b/tim/prune/function/FullRangeDetails.java @@ -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(""); + } } /**