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