--- /dev/null
+package tim.prune.data;
+
+/**
+ * Class to manage the scaling of points
+ */
+public class PointScaler
+{
+ // Original data
+ private Track _track = null;
+ // Range information
+ private AltitudeRange _altRange = null;
+ private DoubleRange _latRange = null;
+ private DoubleRange _lonRange = null;
+ private double _latMedian = 0.0;
+ private double _lonMedian = 0.0;
+ private int _minAltitude = 0;
+ private int _maxAltitude = 0;
+ // Scaling information
+ private double _longFactor = 0.0;
+ // Scaled points
+ private double[] _xValues = null;
+ private double[] _yValues = null;
+ private int[] _altValues = null;
+ private double _maxX = 0.0;
+ private double _maxY = 0.0;
+ // lat/long lines
+ private double[] _latLinesDegs = null;
+ private double[] _lonLinesDegs = null;
+ private double[] _latLinesScaled = null;
+ private double[] _lonLinesScaled = null;
+
+ // Constants
+ private static final double[] COORD_SEPARATIONS = {
+ 1.0, // 1deg
+ 30.0/60.0, 20.0/60.0, // 30min, 20min
+ 10.0/60.0, 5.0/60.0, // 10min, 5min
+ 3.0/60.0, 2.0/60.0, 1.0/60.0 // 3min, 2min, 1min
+ };
+ private static final int MAX_COORD_SEPARATION_INDEX = COORD_SEPARATIONS.length - 1;
+
+ /**
+ * Constructor
+ * @param inTrack Track object
+ */
+ public PointScaler(Track inTrack)
+ {
+ _track = inTrack;
+ _altRange = new AltitudeRange();
+ _latRange = new DoubleRange();
+ _lonRange = new DoubleRange();
+ }
+
+
+ /**
+ * Scale the points
+ */
+ public void scale()
+ {
+ // Clear data
+ _altRange.clear();
+ _latRange.clear();
+ _lonRange.clear();
+ int numPoints = 0;
+ int p = 0;
+ DataPoint point = null;
+ // Find limits of data
+ if (_track != null && (numPoints = _track.getNumPoints()) > 0)
+ {
+ for (p=0; p<numPoints; p++)
+ {
+ point = _track.getPoint(p);
+ if (point != null)
+ {
+ _latRange.addValue(point.getLatitude().getDouble());
+ _lonRange.addValue(point.getLongitude().getDouble());
+ _altRange.addValue(point.getAltitude());
+ }
+ }
+
+ // Find median latitude and calculate factor
+ _latMedian = (_latRange.getMinimum() + _latRange.getMaximum()) / 2;
+ _lonMedian = (_lonRange.getMinimum() + _lonRange.getMaximum()) / 2;
+ _minAltitude = _altRange.getMinimum();
+ _longFactor = Math.cos(_latMedian / 180.0 * Math.PI); // quite rough
+
+ // create new arrays for scaled values
+ if (_xValues == null || _xValues.length != numPoints)
+ {
+ _xValues = new double[numPoints];
+ _yValues = new double[numPoints];
+ _altValues = new int[numPoints];
+ }
+ // Calculate scaled values
+ for (p=0; p<numPoints; p++)
+ {
+ point = _track.getPoint(p);
+ if (point != null)
+ {
+ _xValues[p] = getScaledLongitude(point.getLongitude().getDouble());
+ _yValues[p] = getScaledLatitude(point.getLatitude().getDouble());
+ _altValues[p] = getScaledAltitude(point.getAltitude());
+ }
+ }
+ // Calculate x and y range
+ _maxX = getScaledLongitude(_lonRange.getMaximum());
+ _maxY = getScaledLatitude(_latRange.getMaximum());
+ _maxAltitude = _altRange.getMaximum() - _altRange.getMinimum();
+ }
+ }
+
+
+ /**
+ * @return maximum horiz value
+ */
+ public double getMaximumHoriz() { return _maxX; }
+ /**
+ * @return maximum vert value
+ */
+ public double getMaximumVert() { return _maxY; }
+ /**
+ * @return maximum alt value
+ */
+ public int getMaximumAlt() { return _maxAltitude; }
+
+ /**
+ * Get the horizontal value for the specified point
+ * @param inIndex index of point, starting at 0
+ * @return scaled horizontal value
+ */
+ public double getHorizValue(int inIndex)
+ {
+ return _xValues[inIndex];
+ }
+ /**
+ * Get the vertical value for the specified point
+ * @param inIndex index of point, starting at 0
+ * @return scaled vertical value
+ */
+ public double getVertValue(int inIndex)
+ {
+ return _yValues[inIndex];
+ }
+ /**
+ * Get the altitude value for the specified point
+ * @param inIndex index of point, starting at 0
+ * @return scaled altitude value
+ */
+ public int getAltValue(int inIndex)
+ {
+ return _altValues[inIndex];
+ }
+
+ /**
+ * Scale the given latitude value
+ * @param inLatitude latitude in degrees
+ * @return scaled latitude
+ */
+ public double getScaledLatitude(double inLatitude)
+ {
+ return inLatitude - _latMedian;
+ }
+ /**
+ * Scale the given longitude value
+ * @param inLongitude longitude in degrees
+ * @return scaled longitude
+ */
+ public double getScaledLongitude(double inLongitude)
+ {
+ return (inLongitude - _lonMedian) * _longFactor;
+ }
+ /**
+ * Scale the given altitude value
+ * @param inAltitude Altitude object
+ * @return scaled altitude
+ */
+ public int getScaledAltitude(Altitude inAltitude)
+ {
+ if (inAltitude == null) return -1;
+ return inAltitude.getValue(_altRange.getFormat()) - _minAltitude;
+ }
+
+ /**
+ * Unscale the given latitude value
+ * @param inScaledLatitude scaled latitude
+ * @return latitude in degrees
+ */
+ public double getUnscaledLatitude(double inScaledLatitude)
+ {
+ return inScaledLatitude + _latMedian;
+ }
+ /**
+ * Unscale the given longitude value
+ * @param inScaledLongitude scaled longitude
+ * @return longitude in degrees
+ */
+ public double getUnscaledLongitude(double inScaledLongitude)
+ {
+ return inScaledLongitude / _longFactor + _lonMedian;
+ }
+
+ /**
+ * Calculate the latitude and longitude lines
+ */
+ public void calculateLatLongLines()
+ {
+ double maxValue = getMaximumHoriz() > getMaximumVert() ?
+ getMaximumHoriz():getMaximumVert();
+ // calculate boundaries in degrees
+ double minLong = getUnscaledLongitude(-maxValue);
+ double maxLong = getUnscaledLongitude(maxValue);
+ double minLat = getUnscaledLatitude(-maxValue);
+ double maxLat = getUnscaledLatitude(maxValue);
+ // work out what line separation to use to give at least two lines
+ int sepIndex = -1;
+ double separation;
+ int numLatLines = 0, numLonLines = 0;
+ do
+ {
+ sepIndex++;
+ separation = COORD_SEPARATIONS[sepIndex];
+ numLatLines = getNumLinesBetween(minLat, maxLat, separation);
+ numLonLines = getNumLinesBetween(minLong, maxLong, separation);
+ }
+ while ((numLonLines <= 1 || numLatLines <= 1) && sepIndex < MAX_COORD_SEPARATION_INDEX);
+ // create lines based on this separation
+ _latLinesDegs = getLines(minLat, maxLat, separation, numLatLines);
+ _lonLinesDegs = getLines(minLong, maxLong, separation, numLonLines);
+ // scale lines also
+ _latLinesScaled = new double[numLatLines];
+ for (int i=0; i<numLatLines; i++) _latLinesScaled[i] = getScaledLatitude(_latLinesDegs[i]);
+ _lonLinesScaled = new double[numLonLines];
+ for (int i=0; i<numLonLines; i++) _lonLinesScaled[i] = getScaledLongitude(_lonLinesDegs[i]);
+ }
+
+
+ /**
+ * Calculate the number of lines in the given range using the specified separation
+ * @param inMin minimum value
+ * @param inMax maximum value
+ * @param inSeparation line separation
+ * @return number of lines
+ */
+ private static int getNumLinesBetween(double inMin, double inMax, double inSeparation)
+ {
+ // Start looking from round number of degrees below minimum
+ double value = (int) inMin;
+ if (inMin < 0.0) value = value - 1.0;
+ // Loop until bigger than maximum
+ int numLines = 0;
+ while (value < inMax)
+ {
+ if (value >= inMin) numLines++;
+ value += inSeparation;
+ }
+ return numLines;
+ }
+
+
+ /**
+ * Get the line values in the given range using the specified separation
+ * @param inMin minimum value
+ * @param inMax maximum value
+ * @param inSeparation line separation
+ * @param inCount number of lines already counted
+ * @return array of line values
+ */
+ private static double[] getLines(double inMin, double inMax, double inSeparation, int inCount)
+ {
+ double[] values = new double[inCount];
+ // Start looking from round number of degrees below minimum
+ double value = (int) inMin;
+ if (inMin < 0.0) value = value - 1.0;
+ // Loop until bigger than maximum
+ int numLines = 0;
+ while (value < inMax)
+ {
+ if (value >= inMin)
+ {
+ values[numLines] = value;
+ numLines++;
+ }
+ value += inSeparation;
+ }
+ return values;
+ }
+
+ /**
+ * @return array of latitude lines in degrees
+ */
+ public double[] getLatitudeLines()
+ {
+ return _latLinesDegs;
+ }
+ /**
+ * @return array of longitude lines in degrees
+ */
+ public double[] getLongitudeLines()
+ {
+ return _lonLinesDegs;
+ }
+ /**
+ * @return array of latitude lines in scaled units
+ */
+ public double[] getScaledLatitudeLines()
+ {
+ return _latLinesScaled;
+ }
+ /**
+ * @return array of longitude lines in scaled units
+ */
+ public double[] getScaledLongitudeLines()
+ {
+ return _lonLinesScaled;
+ }
+}