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