]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/data/PointScaler.java
Version 14, October 2012
[GpsPrune.git] / tim / prune / data / PointScaler.java
1 package tim.prune.data;
2
3 /**
4  * Class to manage the scaling of points
5  */
6 public class PointScaler
7 {
8         // Original data
9         private Track _track = null;
10         // Range information
11         private double _latMedian = 0.0;
12         private double _lonMedian = 0.0;
13         private int _minAltitude = 0;
14         // Scaling information
15         private double _longFactor = 0.0;
16         private double _altFactor = 0.0;
17         // Scaled points
18         private double[] _xValues = null;
19         private double[] _yValues = null;
20         private double[] _altValues = null;
21         // max values
22         private double _maxX = 0.0;
23         private double _maxY = 0.0;
24         private double _maxScaledAlt = 0.0;
25         // lat/long lines
26         private double[] _latLinesDegs = null;
27         private double[] _lonLinesDegs = null;
28         private double[] _latLinesScaled = null;
29         private double[] _lonLinesScaled = null;
30
31         // Constants
32         private static final double[] COORD_SEPARATIONS = {
33                 1.0,                      // 1deg
34                 30.0/60.0, 20.0/60.0,     // 30min, 20min
35                 10.0/60.0, 5.0/60.0,      // 10min, 5min
36                 3.0/60.0, 2.0/60.0, 1.0/60.0   // 3min, 2min, 1min
37         };
38         private static final int MAX_COORD_SEPARATION_INDEX = COORD_SEPARATIONS.length - 1;
39
40         /**
41          * Constructor
42          * @param inTrack Track object
43          */
44         public PointScaler(Track inTrack)
45         {
46                 _track = inTrack;
47         }
48
49
50         /**
51          * Scale the points
52          */
53         public void scale()
54         {
55                 // Clear data
56                 DoubleRange latRange = new DoubleRange();
57                 DoubleRange lonRange = new DoubleRange();
58                 DoubleRange altRange = new DoubleRange();
59                 int numPoints = 0;
60                 int p = 0;
61                 DataPoint point = null;
62                 // Find limits of data
63                 if (_track != null && (numPoints = _track.getNumPoints()) > 0)
64                 {
65                         for (p=0; p<numPoints; p++)
66                         {
67                                 point = _track.getPoint(p);
68                                 if (point != null)
69                                 {
70                                         latRange.addValue(point.getLatitude().getDouble());
71                                         lonRange.addValue(point.getLongitude().getDouble());
72                                         altRange.addValue(point.getAltitude().getValue(Altitude.Format.METRES));
73                                 }
74                         }
75
76                         // Find median latitude and calculate factor
77                         _latMedian = (latRange.getMinimum() + latRange.getMaximum()) / 2;
78                         _lonMedian = (lonRange.getMinimum() + lonRange.getMaximum()) / 2;
79                         _minAltitude = (int) altRange.getMinimum();
80                         _longFactor = Math.cos(_latMedian / 180.0 * Math.PI); // quite rough
81                         // Find altitude scale factor using distance
82                         DataPoint p1 = new DataPoint(new Latitude(latRange.getMinimum(), Coordinate.FORMAT_DEG),
83                                 new Longitude(_lonMedian, Coordinate.FORMAT_DEG), null);
84                         DataPoint p2 = new DataPoint(new Latitude(latRange.getMaximum(), Coordinate.FORMAT_DEG),
85                                 new Longitude(_lonMedian, Coordinate.FORMAT_DEG), null);
86                         double horizDist = Distance.convertRadiansToDistance(
87                                 DataPoint.calculateRadiansBetween(p1, p2), UnitSetLibrary.UNITS_METRES); // both in m
88                         _altFactor = 1.0 / horizDist;
89
90                         // create new arrays for scaled values
91                         if (_xValues == null || _xValues.length != numPoints)
92                         {
93                                 _xValues = new double[numPoints];
94                                 _yValues = new double[numPoints];
95                                 _altValues = new double[numPoints];
96                         }
97                         // Calculate scaled values
98                         for (p=0; p<numPoints; p++)
99                         {
100                                 point = _track.getPoint(p);
101                                 if (point != null)
102                                 {
103                                         _xValues[p] = getScaledLongitude(point.getLongitude().getDouble());
104                                         _yValues[p] = getScaledLatitude(point.getLatitude().getDouble());
105                                         _altValues[p] = getScaledAltitude(point.getAltitude());
106                                         if (_altValues[p] > _maxScaledAlt) {_maxScaledAlt = _altValues[p];}
107                                 }
108                         }
109                         // Calculate x and y range
110                         _maxX = getScaledLongitude(lonRange.getMaximum());
111                         _maxY = getScaledLatitude(latRange.getMaximum());
112                 }
113         }
114
115
116         /**
117          * @return maximum horiz value
118          */
119         public double getMaximumHoriz() { return _maxX; }
120         /**
121          * @return maximum vert value
122          */
123         public double getMaximumVert() { return _maxY; }
124
125         /** @return maximum scaled altitude value */
126         public double getMaxScaledAlt() { return _maxScaledAlt; }
127
128         /**
129          * Get the horizontal value for the specified point
130          * @param inIndex index of point, starting at 0
131          * @return scaled horizontal value
132          */
133         public double getHorizValue(int inIndex)
134         {
135                 return _xValues[inIndex];
136         }
137         /**
138          * Get the vertical value for the specified point
139          * @param inIndex index of point, starting at 0
140          * @return scaled vertical value
141          */
142         public double getVertValue(int inIndex)
143         {
144                 return _yValues[inIndex];
145         }
146         /**
147          * Get the altitude value for the specified point
148          * @param inIndex index of point, starting at 0
149          * @return scaled altitude value
150          */
151         public double getAltValue(int inIndex)
152         {
153                 return _altValues[inIndex];
154         }
155
156         /**
157          * Scale the given latitude value
158          * @param inLatitude latitude in degrees
159          * @return scaled latitude
160          */
161         private double getScaledLatitude(double inLatitude)
162         {
163                 return inLatitude - _latMedian;
164         }
165         /**
166          * Scale the given longitude value
167          * @param inLongitude longitude in degrees
168          * @return scaled longitude
169          */
170         private double getScaledLongitude(double inLongitude)
171         {
172                 return (inLongitude - _lonMedian) * _longFactor;
173         }
174         /**
175          * Scale the given altitude value
176          * @param inAltitude Altitude object
177          * @return scaled altitude
178          */
179         private double getScaledAltitude(Altitude inAltitude)
180         {
181                 if (inAltitude == null) return -1;
182                 return (inAltitude.getValue(Altitude.Format.METRES) - _minAltitude) * _altFactor;
183         }
184
185         /**
186          * Unscale the given latitude value
187          * @param inScaledLatitude scaled latitude
188          * @return latitude in degrees
189          */
190         private double getUnscaledLatitude(double inScaledLatitude)
191         {
192                 return inScaledLatitude + _latMedian;
193         }
194         /**
195          * Unscale the given longitude value
196          * @param inScaledLongitude scaled longitude
197          * @return longitude in degrees
198          */
199         private double getUnscaledLongitude(double inScaledLongitude)
200         {
201                 return inScaledLongitude / _longFactor + _lonMedian;
202         }
203
204         /**
205          * Calculate the latitude and longitude lines
206          */
207         public void calculateLatLongLines()
208         {
209                 double maxValue = getMaximumHoriz() > getMaximumVert() ?
210                         getMaximumHoriz():getMaximumVert();
211                 // calculate boundaries in degrees
212                 double minLong = getUnscaledLongitude(-maxValue);
213                 double maxLong = getUnscaledLongitude(maxValue);
214                 double minLat = getUnscaledLatitude(-maxValue);
215                 double maxLat = getUnscaledLatitude(maxValue);
216                 // work out what line separation to use to give at least two lines
217                 int sepIndex = -1;
218                 double separation;
219                 int numLatLines = 0, numLonLines = 0;
220                 do
221                 {
222                         sepIndex++;
223                         separation = COORD_SEPARATIONS[sepIndex];
224                         numLatLines = getNumLinesBetween(minLat, maxLat, separation);
225                         numLonLines = getNumLinesBetween(minLong, maxLong, separation);
226                 }
227                 while ((numLonLines <= 1 || numLatLines <= 1) && sepIndex < MAX_COORD_SEPARATION_INDEX);
228                 // create lines based on this separation
229                 _latLinesDegs = getLines(minLat, maxLat, separation, numLatLines);
230                 _lonLinesDegs = getLines(minLong, maxLong, separation, numLonLines);
231                 // scale lines also
232                 _latLinesScaled = new double[numLatLines];
233                 for (int i=0; i<numLatLines; i++) _latLinesScaled[i] = getScaledLatitude(_latLinesDegs[i]);
234                 _lonLinesScaled = new double[numLonLines];
235                 for (int i=0; i<numLonLines; i++) _lonLinesScaled[i] = getScaledLongitude(_lonLinesDegs[i]);
236         }
237
238
239         /**
240          * Calculate the number of lines in the given range using the specified separation
241          * @param inMin minimum value
242          * @param inMax maximum value
243          * @param inSeparation line separation
244          * @return number of lines
245          */
246         private static int getNumLinesBetween(double inMin, double inMax, double inSeparation)
247         {
248                 // Start looking from round number of degrees below minimum
249                 double value = (int) inMin;
250                 if (inMin < 0.0) value = value - 1.0;
251                 // Loop until bigger than maximum
252                 int numLines = 0;
253                 while (value < inMax)
254                 {
255                         if (value >= inMin) numLines++;
256                         value += inSeparation;
257                 }
258                 return numLines;
259         }
260
261
262         /**
263          * Get the line values in the given range using the specified separation
264          * @param inMin minimum value
265          * @param inMax maximum value
266          * @param inSeparation line separation
267          * @param inCount number of lines already counted
268          * @return array of line values
269          */
270         private static double[] getLines(double inMin, double inMax, double inSeparation, int inCount)
271         {
272                 double[] values = new double[inCount];
273                 // Start looking from round number of degrees below minimum
274                 double value = (int) inMin;
275                 if (inMin < 0.0) value = value - 1.0;
276                 // Loop until bigger than maximum
277                 int numLines = 0;
278                 while (value < inMax)
279                 {
280                         if (value >= inMin)
281                         {
282                                 values[numLines] = value;
283                                 numLines++;
284                         }
285                         value += inSeparation;
286                 }
287                 return values;
288         }
289
290         /**
291          * @return array of latitude lines in degrees
292          */
293         public double[] getLatitudeLines()
294         {
295                 return _latLinesDegs;
296         }
297         /**
298          * @return array of longitude lines in degrees
299          */
300         public double[] getLongitudeLines()
301         {
302                 return _lonLinesDegs;
303         }
304         /**
305          * @return array of latitude lines in scaled units
306          */
307         public double[] getScaledLatitudeLines()
308         {
309                 return _latLinesScaled;
310         }
311         /**
312          * @return array of longitude lines in scaled units
313          */
314         public double[] getScaledLongitudeLines()
315         {
316                 return _lonLinesScaled;
317         }
318 }