]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/data/AltitudeRange.java
Version 19, May 2018
[GpsPrune.git] / tim / prune / data / AltitudeRange.java
index 6c7e5d55a286c1c0715227cc4a1a7204a9a164d2..6a9f65fb1d5fdaf087d118e686fd4991fe0f5c75 100644 (file)
 package tim.prune.data;
 
+import tim.prune.config.Config;
+
 /**
  * Represents a range of altitudes, taking units into account.
  * Values assumed to be >= 0.
  */
 public class AltitudeRange
 {
+       /** Range of altitudes in metres */
        private IntegerRange _range = new IntegerRange();
-       private int _format = Altitude.FORMAT_NONE;
+       /** Flag for whether previous value exists or not */
+       private boolean _gotPreviousValue;
+       /** Previous metric value */
+       private int _previousValue;
+       /** Total climb in metres */
+       private int _climb;
+       /** Total descent in metres */
+       private int _descent;
+       /** Flags for whether minimum or maximum has been found */
+       private boolean _gotPreviousMinimum = false, _gotPreviousMaximum = false;
+       /** Integer values of previous minimum and maximum, if any */
+       private int     _previousExtreme = 0;
 
 
+       /**
+        * Constructor
+        */
+       public AltitudeRange() {
+               clear();
+       }
+
        /**
         * Clear the altitude range
         */
        public void clear()
        {
                _range.clear();
-               _format = Altitude.FORMAT_NONE;
+               _climb = _descent = 0;
+               _gotPreviousValue = false;
+               _previousValue = 0;
+               _gotPreviousMinimum = _gotPreviousMaximum = false;
+               _previousExtreme = 0;
        }
 
 
        /**
         * Add a value to the range
-        * @param inValue value to add, only positive values considered
+        * @param inAltitude value to add, only positive values considered
         */
        public void addValue(Altitude inAltitude)
        {
-               if (inAltitude != null)
+               final int wiggleLimit = Config.getConfigInt(Config.KEY_ALTITUDE_TOLERANCE) / 100;
+
+               if (inAltitude != null && inAltitude.isValid())
                {
-                       int altValue = inAltitude.getValue(_format);
+                       int altValue = (int) inAltitude.getMetricValue();
                        _range.addValue(altValue);
-                       if (_format == Altitude.FORMAT_NONE)
+                       // Compare with previous value if any
+                       if (_gotPreviousValue)
+                       {
+                               if (altValue != _previousValue)
+                               {
+                                       // Got an altitude value which is different from the previous one
+                                       final boolean locallyUp = (altValue > _previousValue);
+                                       final boolean overallUp = _gotPreviousMinimum && _previousValue > _previousExtreme;
+                                       final boolean overallDn = _gotPreviousMaximum && _previousValue < _previousExtreme;
+                                       final boolean moreThanWiggle = Math.abs(altValue - _previousValue) > wiggleLimit;
+                                       // Do we know whether we're going up or down yet?
+                                       if (!_gotPreviousMinimum && !_gotPreviousMaximum)
+                                       {
+                                               // we don't know whether we're going up or down yet - check limit
+                                               if (moreThanWiggle)
+                                               {
+                                                       if (locallyUp) {_gotPreviousMinimum = true;}
+                                                       else {_gotPreviousMaximum = true;}
+                                                       _previousExtreme = _previousValue;
+                                                       _previousValue = altValue;
+                                                       _gotPreviousValue = true;
+                                               }
+                                       }
+                                       else if (overallUp)
+                                       {
+                                               if (locallyUp) {
+                                                       // we're still going up - do nothing
+                                                       _previousValue = altValue;
+                                               }
+                                               else if (moreThanWiggle)
+                                               {
+                                                       // we're going up but have dropped over a maximum
+                                                       // Add the climb from _previousExtreme up to _previousValue
+                                                       _climb += (_previousValue - _previousExtreme);
+                                                       _previousExtreme = _previousValue;
+                                                       _gotPreviousMinimum = false; _gotPreviousMaximum = true;
+                                                       _previousValue = altValue;
+                                                       _gotPreviousValue = true;
+                                               }
+                                       }
+                                       else if (overallDn)
+                                       {
+                                               if (locallyUp) {
+                                                       if (moreThanWiggle)
+                                                       {
+                                                               // we're going down but have climbed up from a minimum
+                                                               // Add the descent from _previousExtreme down to _previousValue
+                                                               _descent += (_previousExtreme - _previousValue);
+                                                               _previousExtreme = _previousValue;
+                                                               _gotPreviousMinimum = true; _gotPreviousMaximum = false;
+                                                               _previousValue = altValue;
+                                                               _gotPreviousValue = true;
+                                                       }
+                                               }
+                                               else {
+                                                       // we're still going down - do nothing
+                                                       _previousValue = altValue;
+                                                       _gotPreviousValue = true;
+                                               }
+                                       }
+                                       // TODO: Behaviour when WIGGLE_LIMIT == 0 should be same as before, all differences cumulated
+                               }
+                       }
+                       else
                        {
-                               _format = inAltitude.getFormat();
+                               // we haven't got a previous value at all, so it's the start of a new segment
+                               _previousValue = altValue;
+                               _gotPreviousValue = true;
                        }
+
+//                     if (!_empty)
+//                     {
+//                             if (altValue > _previousValue)
+//                                     _climb += (altValue - _previousValue);
+//                             else
+//                                     _descent += (_previousValue - altValue);
+//                     }
+//                     _previousValue = altValue;
+//                     _empty = false;
                }
        }
 
+       /**
+        * Reset the climb/descent calculations starting from the given value
+        * @param inAltitude altitude value
+        */
+       public void ignoreValue(Altitude inAltitude)
+       {
+               // Process the previous value, if any, to update climb/descent as that's the end of the previous segment
+               if (_gotPreviousValue && _gotPreviousMinimum && _previousValue > _previousExtreme) {
+                       _climb += (_previousValue - _previousExtreme);
+               }
+               else if (_gotPreviousValue && _gotPreviousMaximum && _previousValue < _previousExtreme) {
+                       _descent += (_previousExtreme - _previousValue);
+               }
+               // Eliminate the counting values to start the new segment
+               _gotPreviousMinimum = _gotPreviousMaximum = false;
+               _gotPreviousValue = false;
+               // Now process this value if there is one
+               if (inAltitude != null && inAltitude.isValid())
+               {
+                       final int altValue = (int) inAltitude.getMetricValue();
+                       _range.addValue(altValue);
+                       _previousValue = altValue;
+                       _gotPreviousValue = true;
+               }
+       }
 
        /**
-        * @return true if positive data values were found
+        * @return true if altitude range found
         */
-       public boolean hasData()
+       public boolean hasRange()
        {
-               return (_range.hasData());
+               return _range.hasValues();
        }
 
 
        /**
-        * @return minimum value, or -1 if none found
+        * @param inUnit altitude units to use
+        * @return minimum value
         */
-       public int getMinimum()
+       public int getMinimum(Unit inUnit)
        {
-               return _range.getMinimum();
+               return (int) (_range.getMinimum() * inUnit.getMultFactorFromStd());
        }
 
+       /**
+        * @param inUnit altitude units to use
+        * @return maximum value
+        */
+       public int getMaximum(Unit inUnit)
+       {
+               return (int) (_range.getMaximum() * inUnit.getMultFactorFromStd());
+       }
 
        /**
-        * @return maximum value, or -1 if none found
+        * @param inUnit altitude units to use
+        * @return total climb
         */
-       public int getMaximum()
+       public int getClimb(Unit inUnit)
        {
-               return _range.getMaximum();
+               // May need to add climb from last segment
+               int lastSegmentClimb = 0;
+               if (_gotPreviousValue && _gotPreviousMinimum && _previousValue > _previousExtreme) {
+                       lastSegmentClimb = _previousValue - _previousExtreme;
+               }
+               return (int) ((_climb + lastSegmentClimb) * inUnit.getMultFactorFromStd());
        }
 
+       /**
+        * @param inUnit altitude units to use
+        * @return total descent
+        */
+       public int getDescent(Unit inUnit)
+       {
+               // May need to add descent from last segment
+               int lastSegmentDescent = 0;
+               if (_gotPreviousValue && _gotPreviousMaximum && _previousValue < _previousExtreme) {
+                       lastSegmentDescent = _previousExtreme - _previousValue;
+               }
+               return (int) ((_descent + lastSegmentDescent) * inUnit.getMultFactorFromStd());
+       }
 
        /**
-        * @return the altitude format used
+        * @return overall height gain in metres
         */
-       public int getFormat()
+       public double getMetricHeightDiff()
        {
-               return _format;
+               return getClimb(UnitSetLibrary.UNITS_METRES) - getDescent(UnitSetLibrary.UNITS_METRES);
        }
 }