File: SegmentData.java

package info (click to toggle)
gpsprune 26.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,824 kB
  • sloc: java: 52,154; sh: 25; makefile: 21; python: 15
file content (131 lines) | stat: -rw-r--r-- 4,459 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package tim.prune.function.comparesegments;

import tim.prune.data.Bearing;
import tim.prune.data.DataPoint;
import tim.prune.data.Timestamp;
import tim.prune.data.Track;

import java.util.ArrayList;
import java.util.List;

/**
 * Holds the points and lines of a single segment ready for comparison
 */
public class SegmentData
{
	private final PointSequence _points = new PointSequence();
	private final ArrayList<LineAndBearing> _lines = new ArrayList<>();

	/** Maximum angle change at a point for it to be considered */
	private static final double MAX_ANGLE_CHANGE_DEGREES = 45.0;

	public SegmentData(Track inTrack, int inStartIndex)
	{
		fillPointData(inTrack, _points, inStartIndex);
		fillLineData(_points, _lines);
	}

	/** Fill the given PointSequence object with PointData objects for the specified segment */
	private static void fillPointData(Track inTrack, PointSequence inPoints, int inStartIndex)
	{
		ArrayList<DataPoint> points = createPoints(inTrack, inStartIndex);
		DataPoint prevPoint = null;
		DataPoint point = null;
		double radiansSoFar = 0.0;
		// Loop through the points in threes, taking prevPoint, point and nextPoint
		for (DataPoint nextPoint : points)
		{
			if (point != null)
			{
				// Here we consider the point with the one before it and the one after it
				final double currRadians = DataPoint.calculateRadiansBetween(prevPoint, point);
				radiansSoFar += currRadians;
				final Double bearing;
				if (prevPoint == null) {
					// first line in segment, just take bearing from this point to the next one
					bearing = Bearing.calculateDegrees(point, nextPoint);
				}
				else if (nextPoint == null) {
					// last line in segment, just take bearing from prevPoint to point
					bearing = Bearing.calculateDegrees(prevPoint, point);
				}
				else
				{
					// line in the middle
					// Check difference between bearing(prevPrev->prev) and bearing(prev, point)
					final double angleDiff = Bearing.calculateDegreeChange(prevPoint, point, nextPoint);
					if (angleDiff > MAX_ANGLE_CHANGE_DEGREES) {
						bearing = null;
					}
					else {
						bearing = Bearing.calculateDegrees(prevPoint, nextPoint);
					}
				}
				if (bearing != null)
				{
					final double speedRadsPerSec = getSpeedRadsPerSec(prevPoint, point, nextPoint);
					inPoints.addPoint(new PointData(point, bearing, currRadians, radiansSoFar, speedRadsPerSec));
				}
			}
			prevPoint = point;
			point = nextPoint;
		}
	}

	private static double getSpeedRadsPerSec(DataPoint inPrevPoint, DataPoint inPoint, DataPoint inNextPoint)
	{
		final Timestamp firstStamp = (inPrevPoint == null ? inPoint.getTimestamp() : inPrevPoint.getTimestamp());
		final Timestamp secondStamp = (inNextPoint == null ? inPoint.getTimestamp() : inNextPoint.getTimestamp());
		final long millis = secondStamp.getMillisecondsSince(firstStamp);
		double totalDistanceRads = DataPoint.calculateRadiansBetween(inPrevPoint, inPoint)
			+ DataPoint.calculateRadiansBetween(inPoint, inNextPoint);
		return totalDistanceRads * 1000.0 / millis;
	}

	/** @return a list of the datapoints in the specified segment, ending with null */
	private static ArrayList<DataPoint> createPoints(Track inTrack, int inStartIndex)
	{
		ArrayList<DataPoint> points = new ArrayList<>();
		for (int i=inStartIndex; i<inTrack.getNumPoints(); i++)
		{
			DataPoint point = inTrack.getPoint(i);
			if (point == null || point.isWaypoint()) {
				continue;
			}
			if (point.getSegmentStart() && i > inStartIndex) {
				break; // next segment found
			}
			// TODO: Check for a minimum distance between previous point and this one?
			points.add(point);
		}
		// Add a null point at the end so that we can consider the last triplet
		points.add(null);
		return points;
	}

	private void fillLineData(PointSequence inPoints, ArrayList<LineAndBearing> inLines)
	{
		PointData prevPoint = null;
		for (PointData pd : inPoints.getPoints())
		{
			if (prevPoint != null) {
				inLines.add(new LineAndBearing(prevPoint, pd));
			}
			prevPoint = pd;
		}
	}

	boolean isBefore(SegmentData inOther) {
		return _points.getFirstTimestamp().isBefore(inOther._points.getFirstTimestamp());
	}

	// TODO: Could be an immutable copy?
	PointSequence getPoints() {
		return _points;
	}

	// TODO: Could be an immutable copy?
	List<LineAndBearing> getLines() {
		return _lines;
	}
}