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
|
package tim.prune.function;
import tim.prune.App;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
import tim.prune.cmd.EditSingleFieldCmd;
import tim.prune.data.*;
import tim.prune.function.edit.PointEdit;
import java.util.ArrayList;
public class InterpolateTimestamps extends GenericFunction
{
private final ArrayList<PointEdit> _edits = new ArrayList<>();
public InterpolateTimestamps(App inApp) {
super(inApp);
}
/** Execute the function on the selected range */
public void begin()
{
_edits.clear();
double distanceSoFar = 0.0;
ArrayList<IndexAndDistance> pointList = new ArrayList<>();
final int selStart = _app.getTrackInfo().getSelection().getStart();
final int selEnd = _app.getTrackInfo().getSelection().getEnd();
if (selStart < 0 || selEnd <= selStart) {
return;
}
DataPoint fromPoint = null;
DataPoint latestPoint = null;
for (int i=selStart; i<=selEnd; i++)
{
DataPoint point = _app.getTrackInfo().getTrack().getPoint(i);
if (point.isWaypoint()) {
continue;
}
if (point.getSegmentStart())
{
pointList.clear();
fromPoint = null;
}
if (point.hasTimestamp())
{
if (fromPoint != null && !pointList.isEmpty())
{
distanceSoFar += distanceBetween(latestPoint, point);
processPointList(pointList, distanceSoFar,
fromPoint.getTimestamp(), point.getTimestamp());
}
fromPoint = point;
pointList.clear();
distanceSoFar = 0.0;
}
else if (fromPoint != null)
{
distanceSoFar += distanceBetween(latestPoint, point);
pointList.add(new IndexAndDistance(i, distanceSoFar));
}
latestPoint = point;
}
if (_edits.isEmpty()) {
_app.showErrorMessage(getNameKey(), "error.interpolatetimestamps.notpossible");
}
else
{
EditSingleFieldCmd command = new EditSingleFieldCmd(Field.TIMESTAMP, _edits, null);
command.setDescription(I18nManager.getText("undo.applytimestamps"));
command.setConfirmText(I18nManager.getText("confirm.applytimestamps"));
_app.execute(command);
}
}
/**
* Handle a range of points without timestamps
* @param inPointList list of point indexes and their distances
* @param inTotalDistance total distance between the two end points
* @param inStartTimestamp timestamp of point before the range
* @param inEndTimestamp timestamp of point after the range
*/
private void processPointList(ArrayList<IndexAndDistance> inPointList, double inTotalDistance,
Timestamp inStartTimestamp, Timestamp inEndTimestamp)
{
for (IndexAndDistance idxDist : inPointList)
{
final double fraction = idxDist._distance / inTotalDistance;
final long millisAfter = (long) (inEndTimestamp.getMillisecondsSince(inStartTimestamp) * fraction);
Timestamp stamp = inStartTimestamp.addOffsetMilliseconds(millisAfter);
String stampText = stamp.getText(Timestamp.Format.ISO8601, null);
_edits.add(new PointEdit(idxDist._pointIndex, stampText));
}
}
/** @return the distance between two points */
private static double distanceBetween(DataPoint inPoint1, DataPoint inPoint2)
{
double radians = DataPoint.calculateRadiansBetween(inPoint1, inPoint2);
return Distance.convertRadiansToDistance(radians, UnitSetLibrary.UNITS_METRES);
}
public String getNameKey() {
return "function.interpolatetimestamps";
}
/** Inner class to hold points and distances in a list */
private static class IndexAndDistance
{
private final int _pointIndex;
private final double _distance;
private IndexAndDistance(int inIndex, double inDistance)
{
_pointIndex = inIndex;
_distance = inDistance;
}
}
}
|