]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/data/Selection.java
4849a4a42bcddb948172bf494f9180d5639eb9a0
[GpsPrune.git] / tim / prune / data / Selection.java
1 package tim.prune.data;
2
3 import tim.prune.UpdateMessageBroker;
4
5 /**
6  * Class to represent a selected portion of a Track
7  * and its properties
8  */
9 public class Selection
10 {
11         private Track _track = null;
12         private UpdateMessageBroker _broker = null;
13         private int _currentPoint = -1;
14         private boolean _valid = false;
15         private int _startIndex = -1, _endIndex = -1;
16         private int _currentPhotoIndex = -1;
17         private IntegerRange _altitudeRange = null;
18         private int _climb = -1, _descent = -1;
19         private int _altitudeFormat = Altitude.FORMAT_NONE;
20         private long _seconds = 0L;
21         private double _angDistance = -1.0; //, _averageSpeed = -1.0;
22
23
24         /**
25          * Constructor
26          * @param inTrack track object
27          * @param inBroker broker object
28          */
29         public Selection(Track inTrack, UpdateMessageBroker inBroker)
30         {
31                 _track = inTrack;
32                 _broker = inBroker;
33         }
34
35
36         /**
37          * Reset selection to be recalculated
38          */
39         private void reset()
40         {
41                 _valid = false;
42         }
43
44
45         /**
46          * Select the point at the given index
47          * @param inIndex index number of selected point
48          */
49         public void selectPoint(int inIndex)
50         {
51                 if (inIndex >= -1)
52                 {
53                         _currentPoint = inIndex;
54                         check();
55                 }
56         }
57
58         /**
59          * Select the specified point and range in one go
60          * @param inPointIndex point selection
61          * @param inStart range start
62          * @param inEnd range end
63          */
64         public void select(int inPointIndex, int inStart, int inEnd)
65         {
66                 _currentPoint = inPointIndex;
67                 _startIndex = inStart;
68                 _endIndex = inEnd;
69                 reset();
70                 check();
71         }
72
73
74         /**
75          * Select the previous point
76          */
77         public void selectPreviousPoint()
78         {
79                 if (_currentPoint > 0)
80                         selectPoint(_currentPoint - 1);
81         }
82
83         /**
84          * Select the next point
85          */
86         public void selectNextPoint()
87         {
88                 selectPoint(_currentPoint + 1);
89         }
90
91         /**
92          * @return the current point index
93          */
94         public int getCurrentPointIndex()
95         {
96                 return _currentPoint;
97         }
98
99
100         /**
101          * @return true if range is selected
102          */
103         public boolean hasRangeSelected()
104         {
105                 return _startIndex >= 0 && _endIndex > _startIndex;
106         }
107
108
109         /**
110          * Recalculate all selection details
111          */
112         private void recalculate()
113         {
114                 _altitudeFormat = Altitude.FORMAT_NONE;
115                 if (_track.getNumPoints() > 0 && hasRangeSelected())
116                 {
117                         _altitudeRange = new IntegerRange();
118                         _climb = 0;
119                         _descent = 0;
120                         Altitude altitude = null;
121                         Timestamp time = null, startTime = null, endTime = null;
122                         DataPoint lastPoint = null, currPoint = null;
123                         _angDistance = 0.0;
124                         int altValue = 0;
125                         int lastAltValue = 0;
126                         boolean foundAlt = false;
127                         for (int i=_startIndex; i<=_endIndex; i++)
128                         {
129                                 currPoint = _track.getPoint(i);
130                                 altitude = currPoint.getAltitude();
131                                 // Ignore waypoints in altitude calculations
132                                 if (!currPoint.isWaypoint() && altitude.isValid())
133                                 {
134                                         altValue = altitude.getValue(_altitudeFormat);
135                                         if (_altitudeFormat == Altitude.FORMAT_NONE)
136                                                 _altitudeFormat = altitude.getFormat();
137                                         _altitudeRange.addValue(altValue);
138                                         if (foundAlt)
139                                         {
140                                                 if (altValue > lastAltValue)
141                                                         _climb += (altValue - lastAltValue);
142                                                 else
143                                                         _descent += (lastAltValue - altValue);
144                                         }
145                                         lastAltValue = altValue;
146                                         foundAlt = true;
147                                 }
148                                 // Store the first and last timestamp in the range
149                                 time = currPoint.getTimestamp();
150                                 if (time.isValid())
151                                 {
152                                         if (startTime == null) startTime = time;
153                                         endTime = time;
154                                 }
155                                 // Calculate distances, again ignoring waypoints
156                                 if (!currPoint.isWaypoint())
157                                 {
158                                         if (lastPoint != null)
159                                         {
160                                                 _angDistance += DataPoint.calculateRadiansBetween(lastPoint, currPoint);
161                                         }
162                                         lastPoint = currPoint;
163                                 }
164                         }
165                         if (endTime != null)
166                         {
167                                 _seconds = endTime.getSecondsSince(startTime);
168                         }
169                         else
170                         {
171                                 _seconds = 0L;
172                         }
173                 }
174                 _valid = true;
175         }
176
177
178         /**
179          * @return start index
180          */
181         public int getStart()
182         {
183                 if (!_valid) recalculate();
184                 return _startIndex;
185         }
186
187
188         /**
189          * @return end index
190          */
191         public int getEnd()
192         {
193                 if (!_valid) recalculate();
194                 return _endIndex;
195         }
196
197
198         /**
199          * @return the altitude format, ie feet or metres
200          */
201         public int getAltitudeFormat()
202         {
203                 return _altitudeFormat;
204         }
205
206         /**
207          * @return altitude range
208          */
209         public IntegerRange getAltitudeRange()
210         {
211                 if (!_valid) recalculate();
212                 return _altitudeRange;
213         }
214
215
216         /**
217          * @return climb
218          */
219         public int getClimb()
220         {
221                 if (!_valid) recalculate();
222                 return _climb;
223         }
224
225         /**
226          * @return descent
227          */
228         public int getDescent()
229         {
230                 if (!_valid) recalculate();
231                 return _descent;
232         }
233
234
235         /**
236          * @return number of seconds spanned by selection
237          */
238         public long getNumSeconds()
239         {
240                 if (!_valid) recalculate();
241                 return _seconds;
242         }
243
244
245         /**
246          * @param inFormat distance units to use, from class Distance
247          * @return distance of Selection in specified units
248          */
249         public double getDistance(int inUnits)
250         {
251                 return Distance.convertRadians(_angDistance, inUnits);
252         }
253
254
255         /**
256          * Clear selected point and range
257          */
258         public void clearAll()
259         {
260                 _currentPoint = -1;
261                 deselectRange();
262                 deselectPhoto();
263         }
264
265
266         /**
267          * Deselect range
268          */
269         public void deselectRange()
270         {
271                 _startIndex = _endIndex = -1;
272                 reset();
273                 check();
274         }
275
276
277         /**
278          * Select the range from the current point
279          */
280         public void selectRangeStart()
281         {
282                 selectRangeStart(_currentPoint);
283         }
284
285
286         /**
287          * Set the index for the start of the range selection
288          * @param inStartIndex start index
289          */
290         public void selectRangeStart(int inStartIndex)
291         {
292                 if (inStartIndex < 0)
293                 {
294                         _startIndex = _endIndex = -1;
295                 }
296                 else
297                 {
298                         _startIndex = inStartIndex;
299                         // Move end of selection to max if necessary
300                         if (_endIndex <= _startIndex)
301                         {
302                                 _endIndex = _track.getNumPoints() - 1;
303                         }
304                 }
305                 reset();
306                 _broker.informSubscribers();
307         }
308
309
310         /**
311          * Select the range up to the current point
312          */
313         public void selectRangeEnd()
314         {
315                 selectRangeEnd(_currentPoint);
316         }
317
318
319         /**
320          * Set the index for the end of the range selection
321          * @param inEndIndex end index
322          */
323         public void selectRangeEnd(int inEndIndex)
324         {
325                 if (inEndIndex < 0)
326                 {
327                         _startIndex = _endIndex = -1;
328                 }
329                 else
330                 {
331                         _endIndex = inEndIndex;
332                         // Move start of selection to min if necessary
333                         if (_startIndex > _endIndex || _startIndex < 0)
334                         {
335                                 _startIndex = 0;
336                         }
337                 }
338                 reset();
339                 _broker.informSubscribers();
340         }
341
342
343         /**
344          * Modify the selection given that the selected range has been deleted
345          */
346         public void modifyRangeDeleted()
347         {
348                 // Modify current point, if any
349                 if (_currentPoint > _endIndex)
350                 {
351                         _currentPoint -= (_endIndex - _startIndex);
352                 }
353                 else if (_currentPoint > _startIndex)
354                 {
355                         _currentPoint = _startIndex;
356                 }
357                 // Clear selected range
358                 _startIndex = _endIndex = -1;
359                 // Check for consistency and fire update
360                 check();
361         }
362
363
364         /**
365          * Modify the selection when a point is deleted
366          */
367         public void modifyPointDeleted()
368         {
369                 // current point index doesn't change, just gets checked
370                 // range needs to get altered if deleted point is inside or before
371                 if (hasRangeSelected() && _currentPoint <= _endIndex)
372                 {
373                         _endIndex--;
374                         if (_currentPoint < _startIndex)
375                                 _startIndex--;
376                         reset();
377                 }
378                 check();
379         }
380
381
382         /**
383          * Deselect photo
384          */
385         public void deselectPhoto()
386         {
387                 _currentPhotoIndex = -1;
388                 check();
389         }
390
391
392         /**
393          * Select the specified photo and point
394          * @param inPhotoIndex index of selected photo in PhotoList
395          * @param inPointIndex index of selected point
396          */
397         public void selectPhotoAndPoint(int inPhotoIndex, int inPointIndex)
398         {
399                 _currentPhotoIndex = inPhotoIndex;
400                 if (inPointIndex > -1)
401                 {
402                         // select associated point, if any
403                         selectPoint(inPointIndex);
404                 }
405                 else
406                 {
407                         // Check if not already done
408                         check();
409                 }
410         }
411
412
413         /**
414          * @return currently selected photo index
415          */
416         public int getCurrentPhotoIndex()
417         {
418                 // System.out.println("Current photo index = " + _currentPhotoIndex);
419                 return _currentPhotoIndex;
420         }
421
422
423         /**
424          * Check that the selection still makes sense
425          * and fire update message to listeners
426          */
427         private void check()
428         {
429                 if (_track != null)
430                 {
431                         if (_track.getNumPoints() > 0)
432                         {
433                                 int maxIndex = _track.getNumPoints() - 1;
434                                 if (_currentPoint > maxIndex)
435                                 {
436                                         _currentPoint = maxIndex;
437                                 }
438                                 if (_endIndex > maxIndex)
439                                 {
440                                         _endIndex = maxIndex;
441                                 }
442                                 if (_startIndex > maxIndex)
443                                 {
444                                         _startIndex = maxIndex;
445                                 }
446                         }
447                         else
448                         {
449                                 // track is empty, clear selections
450                                 _currentPoint = _startIndex = _endIndex = -1;
451                         }
452                 }
453                 _broker.informSubscribers();
454         }
455 }