]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/data/Selection.java
7b63d70838e660c9af142aa1b341f5c2bd40ccce
[GpsPrune.git] / src / tim / prune / data / Selection.java
1 package tim.prune.data;
2
3 import tim.prune.DataSubscriber;
4 import tim.prune.UpdateMessageBroker;
5
6 /**
7  * Class to represent a selected portion of a Track
8  * and its properties
9  */
10 public class Selection
11 {
12         private Track _track = null;
13         private int _currentPoint = -1;
14         private boolean _valid = false;
15         private int _prevNumPoints = 0;
16         private int _startIndex = -1, _endIndex = -1;
17         private int _currentPhotoIndex = -1;
18         private int _currentAudioIndex = -1;
19         private AltitudeRange _altitudeRange = null;
20         private long _movingMilliseconds = 0L;
21         private double _angMovingDistance = -1.0;
22
23
24         /**
25          * Constructor
26          * @param inTrack track object
27          */
28         public Selection(Track inTrack)
29         {
30                 _track = inTrack;
31         }
32
33
34         /**
35          * Mark selection invalid so it will be recalculated
36          */
37         public void markInvalid()
38         {
39                 _valid = false;
40         }
41
42
43         /**
44          * @return the current point index
45          */
46         public int getCurrentPointIndex()
47         {
48                 return _currentPoint;
49         }
50
51
52         /**
53          * @return true if range is selected
54          */
55         public boolean hasRangeSelected()
56         {
57                 return _startIndex >= 0 && _endIndex > _startIndex;
58         }
59
60
61         /**
62          * Recalculate all selection details
63          */
64         private void recalculate()
65         {
66                 final int numPoints = _track.getNumPoints();
67                 // Recheck if the number of points has changed
68                 if (numPoints != _prevNumPoints)
69                 {
70                         _prevNumPoints = numPoints;
71                         check();
72                 }
73                 if (numPoints > 0 && hasRangeSelected())
74                 {
75                         _altitudeRange = new AltitudeRange();
76                         Altitude altitude = null;
77                         Timestamp time = null, previousTime = null;
78                         DataPoint lastPoint = null, currPoint = null;
79                         _angMovingDistance = 0.0;
80                         _movingMilliseconds = 0L;
81                         // Loop over points in selection
82                         for (int i=_startIndex; i<=_endIndex; i++)
83                         {
84                                 currPoint = _track.getPoint(i);
85                                 altitude = currPoint.getAltitude();
86                                 // Ignore waypoints in altitude calculations
87                                 if (!currPoint.isWaypoint() && altitude.isValid())
88                                 {
89                                         if (currPoint.getSegmentStart()) {
90                                                 _altitudeRange.ignoreValue(altitude);
91                                         }
92                                         else {
93                                                 _altitudeRange.addValue(altitude);
94                                         }
95                                 }
96                                 // Compare timestamps within the segments
97                                 time = currPoint.getTimestamp();
98                                 if (time.isValid())
99                                 {
100                                         // add moving time
101                                         if (!currPoint.getSegmentStart() && previousTime != null && time.isAfter(previousTime)) {
102                                                 _movingMilliseconds += time.getMillisecondsSince(previousTime);
103                                         }
104                                         previousTime = time;
105                                 }
106                                 // Calculate distances, again ignoring waypoints
107                                 if (!currPoint.isWaypoint())
108                                 {
109                                         if (lastPoint != null)
110                                         {
111                                                 double radians = DataPoint.calculateRadiansBetween(lastPoint, currPoint);
112                                                 if (!currPoint.getSegmentStart()) {
113                                                         _angMovingDistance += radians;
114                                                 }
115                                         }
116                                         lastPoint = currPoint;
117                                 }
118                         }
119                 }
120                 _valid = true;
121         }
122
123
124         /**
125          * @return start index
126          */
127         public int getStart()
128         {
129                 if (!_valid) recalculate();
130                 return _startIndex;
131         }
132
133
134         /**
135          * @return end index
136          */
137         public int getEnd()
138         {
139                 if (!_valid) recalculate();
140                 return _endIndex;
141         }
142
143         /**
144          * @return altitude range
145          */
146         public AltitudeRange getAltitudeRange()
147         {
148                 if (!_valid) recalculate();
149                 return _altitudeRange;
150         }
151
152
153         /**
154          * @return number of seconds spanned by segments within selection
155          */
156         public long getMovingSeconds()
157         {
158                 if (!_valid) recalculate();
159                 return _movingMilliseconds / 1000L;
160         }
161
162         /**
163          * @return moving distance of Selection in current units
164          */
165         public double getMovingDistance()
166         {
167                 return Distance.convertRadiansToDistance(_angMovingDistance);
168         }
169
170         /**
171          * Clear selected point, range, photo and audio
172          */
173         public void clearAll()
174         {
175                 _currentPoint = -1;
176                 selectRange(-1, -1);
177                 _currentPhotoIndex = -1;
178                 _currentAudioIndex = -1;
179                 check();
180         }
181
182
183         /**
184          * Select range from start to end
185          * @param inStartIndex index of start of range
186          * @param inEndIndex index of end of range
187          */
188         public void selectRange(int inStartIndex, int inEndIndex)
189         {
190                 _startIndex = inStartIndex;
191                 _endIndex = inEndIndex;
192                 markInvalid();
193                 check();
194         }
195
196
197         /**
198          * Select the range from the current point
199          */
200         public void selectRangeStart()
201         {
202                 selectRangeStart(_currentPoint);
203         }
204
205
206         /**
207          * Set the index for the start of the range selection
208          * @param inStartIndex start index
209          */
210         private void selectRangeStart(int inStartIndex)
211         {
212                 if (inStartIndex < 0)
213                 {
214                         _startIndex = _endIndex = -1;
215                 }
216                 else
217                 {
218                         _startIndex = inStartIndex;
219                         // Move end of selection to max if necessary
220                         if (_endIndex <= _startIndex)
221                         {
222                                 _endIndex = _track.getNumPoints() - 1;
223                         }
224                 }
225                 markInvalid();
226                 UpdateMessageBroker.informSubscribers();
227         }
228
229
230         /**
231          * Select the range up to the current point
232          */
233         public void selectRangeEnd()
234         {
235                 selectRangeEnd(_currentPoint);
236         }
237
238
239         /**
240          * Set the index for the end of the range selection
241          * @param inEndIndex end index
242          */
243         public void selectRangeEnd(int inEndIndex)
244         {
245                 if (inEndIndex < 0)
246                 {
247                         _startIndex = _endIndex = -1;
248                 }
249                 else
250                 {
251                         _endIndex = inEndIndex;
252                         // Move start of selection to min if necessary
253                         if (_startIndex > _endIndex || _startIndex < 0) {
254                                 _startIndex = 0;
255                         }
256                 }
257                 markInvalid();
258                 UpdateMessageBroker.informSubscribers();
259         }
260
261
262         /**
263          * Modify the selection given that the selected range has been deleted
264          */
265         public void modifyRangeDeleted()
266         {
267                 // Modify current point, if any
268                 if (_currentPoint > _endIndex)
269                 {
270                         _currentPoint -= (_endIndex - _startIndex);
271                 }
272                 else if (_currentPoint > _startIndex)
273                 {
274                         _currentPoint = _startIndex;
275                 }
276                 // Clear selected range
277                 _startIndex = _endIndex = -1;
278                 // Check for consistency and fire update
279                 check();
280         }
281
282
283         /**
284          * Modify the selection when a point is deleted
285          */
286         public void modifyPointDeleted()
287         {
288                 // current point index doesn't change, just gets checked
289                 // range needs to get altered if deleted point is inside or before
290                 if (hasRangeSelected() && _currentPoint <= _endIndex)
291                 {
292                         _endIndex--;
293                         if (_currentPoint < _startIndex)
294                                 _startIndex--;
295                         markInvalid();
296                 }
297                 check();
298         }
299
300
301         /**
302          * Select the specified photo and point
303          * @param inPointIndex index of selected point
304          * @param inPhotoIndex index of selected photo in PhotoList
305          * @param inAudioIndex index of selected audio item
306          */
307         public void selectPointPhotoAudio(int inPointIndex, int inPhotoIndex, int inAudioIndex)
308         {
309                 _currentPoint = inPointIndex;
310                 _currentPhotoIndex = inPhotoIndex;
311                 _currentAudioIndex = inAudioIndex;
312                 check();
313         }
314
315
316         /**
317          * @return currently selected photo index
318          */
319         public int getCurrentPhotoIndex()
320         {
321                 return _currentPhotoIndex;
322         }
323
324         /**
325          * @return currently selected audio index
326          */
327         public int getCurrentAudioIndex()
328         {
329                 return _currentAudioIndex;
330         }
331
332         /**
333          * Check that the selection still makes sense
334          * and fire update message to listeners
335          */
336         private void check()
337         {
338                 if (_track != null && _track.getNumPoints() > 0)
339                 {
340                         int maxIndex = _track.getNumPoints() - 1;
341                         if (_currentPoint > maxIndex)
342                         {
343                                 _currentPoint = maxIndex;
344                         }
345                         if (_endIndex > maxIndex)
346                         {
347                                 _endIndex = maxIndex;
348                         }
349                         if (_startIndex > maxIndex)
350                         {
351                                 _startIndex = maxIndex;
352                         }
353                 }
354                 else
355                 {
356                         // track is empty, clear selections
357                         _currentPoint = _startIndex = _endIndex = -1;
358                 }
359                 UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
360         }
361 }