]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/data/SpeedCalculator.java
Version 19, May 2018
[GpsPrune.git] / tim / prune / data / SpeedCalculator.java
1 package tim.prune.data;
2
3 import tim.prune.config.Config;
4
5 /**
6  * Abstract class to hold static calculation functions
7  * for speed (and vertical speed)
8  */
9 public abstract class SpeedCalculator
10 {
11         /**
12          * Calculate the horizontal speed value of the track at the specified index
13          * @param inTrack track object
14          * @param inIndex index of point to calculate speed for
15          * @param inValue object in which to place result of calculation
16          */
17         public static void calculateSpeed(Track inTrack, int inIndex, SpeedValue inValue)
18         {
19                 inValue.setInvalid();
20                 if (inTrack == null || inIndex < 0 || inValue == null)
21                 {
22                         System.err.println("Cannot calculate speed for index " + inIndex);
23                         return;
24                 }
25
26                 DataPoint point = inTrack.getPoint(inIndex);
27                 if (point == null) {return;}
28                 boolean pointHasSpeed = false;
29                 double  speedValue = 0.0;
30
31                 // First, see if point has a speed value already
32                 if (point.hasHSpeed()) {
33                         speedValue = point.getHSpeed().getValue(Config.getUnitSet().getSpeedUnit());
34                         pointHasSpeed = true;
35                 }
36
37                 // otherwise, see if we can calculate it from the timestamps
38                 if (!pointHasSpeed && point.hasTimestamp() && !point.isWaypoint())
39                 {
40                         double totalRadians = 0.0;
41                         int index = inIndex-1;
42                         DataPoint p = null;
43                         DataPoint q = point;
44                         Timestamp earlyStamp = point.getTimestamp();
45                         boolean stop = false;
46
47                         // Count backwards until timestamp earlier than now; total distances back to this point
48                         if (!point.getSegmentStart())
49                         {
50                                 do
51                                 {
52                                         p = inTrack.getPoint(index);
53                                         boolean timeOk = p != null && p.hasTimestamp() && p.getTimestamp().isBefore(point.getTimestamp());
54                                         boolean pValid = timeOk && !p.isWaypoint();
55                                         if (pValid) {
56                                                 totalRadians += DataPoint.calculateRadiansBetween(p, q);
57                                                 earlyStamp = p.getTimestamp();
58                                         }
59
60                                         stop = (p == null) || p.getSegmentStart() || hasSufficientTimeDifference(p, point);
61                                         index--;
62                                         if (p != null && !p.isWaypoint()) {
63                                                 q = p;
64                                         }
65                                 }
66                                 while (!stop);
67                         }
68                         // Count forwards until timestamp later than now; total distances forward to this point
69                         Timestamp lateStamp = point.getTimestamp();
70                         q = point;
71                         index = inIndex+1;
72                         do
73                         {
74                                 p = inTrack.getPoint(index);
75                                 boolean timeOk = p != null && p.hasTimestamp() && !p.getTimestamp().isBefore(point.getTimestamp());
76                                 boolean pValid = timeOk && !p.isWaypoint() && !p.getSegmentStart();
77                                 if (pValid) {
78                                         totalRadians += DataPoint.calculateRadiansBetween(p, q);
79                                         lateStamp = p.getTimestamp();
80                                 }
81
82                                 stop = (p == null) || p.getSegmentStart() || hasSufficientTimeDifference(point, p);
83                                 index++;
84                                 if (p != null && !p.isWaypoint()) {
85                                         q = p;
86                                 }
87                         }
88                         while (!stop);
89
90                         // See if we've managed to get a time range of at least a second
91                         long milliseconds = lateStamp.getMillisecondsSince(earlyStamp);
92                         if (milliseconds >= 1000L)
93                         {
94                                 double dist = Distance.convertRadiansToDistance(totalRadians);
95                                 // Store the value and maintain max and min values
96                                 speedValue = dist / milliseconds * 1000.0 * 60.0 * 60.0; // convert from per millisec to per hour
97                                 pointHasSpeed = true;
98                         }
99                 }
100                 // Did we get a value?
101                 if (pointHasSpeed)
102                 {
103                         inValue.setValue(speedValue);
104                 }
105                 // otherwise, just leave value as invalid
106         }
107
108
109         /**
110          * Calculate the vertical speed value of the track at the specified index
111          * @param inTrack track object
112          * @param inIndex index of point to calculate speed for
113          * @param inValue object in which to place the result of calculation
114          */
115         public static void calculateVerticalSpeed(Track inTrack, int inIndex, SpeedValue inValue)
116         {
117                 if (inTrack == null || inIndex < 0 || inValue == null) {
118                         System.err.println("Cannot calculate vert speed for index " + inIndex);
119                         return;
120                 }
121                 inValue.setInvalid();
122
123                 DataPoint point = inTrack.getPoint(inIndex);
124                 boolean pointHasSpeed = false;
125                 double  speedValue = 0.0;
126
127                 // First, see if point has a speed value already
128                 if (point != null && point.hasVSpeed())
129                 {
130                         speedValue = point.getVSpeed().getValue(Config.getUnitSet().getVerticalSpeedUnit());
131                         pointHasSpeed = true;
132                 }
133                 // otherwise, see if we can calculate it from the heights and timestamps
134                 if (!pointHasSpeed
135                         && point != null && point.hasTimestamp() && point.hasAltitude() && !point.isWaypoint())
136                 {
137                         int index = inIndex-1;
138                         DataPoint p = null;
139                         Timestamp earlyStamp = point.getTimestamp();
140                         Altitude firstAlt = point.getAltitude();
141                         boolean stop = false;
142
143                         // Count backwards until timestamp earlier than now
144                         if (!point.getSegmentStart())
145                         {
146                                 do
147                                 {
148                                         p = inTrack.getPoint(index);
149                                         boolean timeOk = p != null && p.hasTimestamp() && p.getTimestamp().isBefore(point.getTimestamp());
150                                         boolean pValid = timeOk && !p.isWaypoint();
151                                         if (pValid) {
152                                                 earlyStamp = p.getTimestamp();
153                                                 if (p.hasAltitude()) firstAlt = p.getAltitude();
154                                         }
155
156                                         stop = (p == null) || p.getSegmentStart() || hasSufficientTimeDifference(p, point);
157                                         index--;
158                                 }
159                                 while (!stop);
160                         }
161
162                         // Count forwards until timestamp later than now
163                         Timestamp lateStamp = point.getTimestamp();
164                         Altitude lastAlt = point.getAltitude();
165                         index = inIndex+1;
166                         do
167                         {
168                                 p = inTrack.getPoint(index);
169                                 boolean timeOk = p != null && p.hasTimestamp() && !p.getTimestamp().isBefore(point.getTimestamp());
170                                 boolean pValid = timeOk && !p.isWaypoint() && !p.getSegmentStart();
171                                 if (pValid) {
172                                         lateStamp = p.getTimestamp();
173                                         if (p.hasAltitude()) lastAlt = p.getAltitude();
174                                 }
175
176                                 stop = (p == null) || p.getSegmentStart() || hasSufficientTimeDifference(point, p);
177                                 index++;
178                         }
179                         while (!stop);
180
181                         // See if we've managed to get a non-zero time range
182                         long milliseconds = lateStamp.getMillisecondsSince(earlyStamp);
183                         if (milliseconds >= 1000L)
184                         {
185                                 double altDiff = (lastAlt.getMetricValue() - firstAlt.getMetricValue())
186                                  * Config.getUnitSet().getVerticalSpeedUnit().getMultFactorFromStd();
187                                 speedValue = altDiff / milliseconds * 1000.0; // units are feet/sec or metres/sec
188                                 pointHasSpeed = true;
189                         }
190                 }
191                 // Check whether we got a value from either method
192                 if (pointHasSpeed)
193                 {
194                         inValue.setValue(speedValue);
195                 }
196         }
197
198         /**
199          * Check whether the time difference between P1 and P2 is sufficiently large
200          * @param inP1 earlier point
201          * @param inP2 later point
202          * @return true if we can stop looking now, found a point early/late enough
203          */
204         private static boolean hasSufficientTimeDifference(DataPoint inP1, DataPoint inP2)
205         {
206                 if (inP1 == null || inP2 == null)
207                         return true; // we have to give up now
208                 if (!inP1.hasTimestamp() || !inP2.hasTimestamp())
209                         return false; // keep looking
210                 final long MIN_TIME_DIFFERENCE_MS = 1000L;
211                 return inP2.getTimestamp().getMillisecondsSince(inP1.getTimestamp()) >= MIN_TIME_DIFFERENCE_MS;
212         }
213 }