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;
}
}
|