X-Git-Url: http://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fdata%2FTrack.java;h=eeb5b626bb484e59750b605849d653d77ca2a25b;hb=52bf9e8686c916be37a26a0b75340393d4478b05;hp=c5a0f16f4d72a3707ebf4460088958c97cbf14c0;hpb=5625a1abadb5f2ca5f017fe7dbda1d5141cb637b;p=GpsPrune.git diff --git a/tim/prune/data/Track.java b/tim/prune/data/Track.java index c5a0f16..eeb5b62 100644 --- a/tim/prune/data/Track.java +++ b/tim/prune/data/Track.java @@ -5,6 +5,7 @@ import java.util.List; import tim.prune.UpdateMessageBroker; import tim.prune.edit.FieldEdit; import tim.prune.edit.FieldEditList; +import tim.prune.gui.map.MapUtils; /** @@ -13,13 +14,13 @@ import tim.prune.edit.FieldEditList; */ public class Track { - // Broker object - UpdateMessageBroker _broker = null; // Data points private DataPoint[] _dataPoints = null; // Scaled x, y values private double[] _xValues = null; private double[] _yValues = null; + private double[] _xValuesNew = null; + private double[] _yValuesNew = null; private boolean _scaled = false; private int _numPoints = 0; private boolean _mixedData = false; @@ -32,13 +33,10 @@ public class Track /** - * Constructor giving arrays of Fields and Objects - * @param inFieldArray field array - * @param inPointArray 2d array of field values + * Constructor for empty track */ - public Track(UpdateMessageBroker inBroker) + public Track() { - _broker = inBroker; // create field list _masterFieldList = new FieldList(null); // make empty DataPoint array @@ -80,6 +78,11 @@ public class Track } } _numPoints = pointIndex; + // Set first track point to be start of segment + DataPoint firstTrackPoint = getNextTrackPoint(0); + if (firstTrackPoint != null) { + firstTrackPoint.setSegmentStart(true); + } // needs to be scaled _scaled = false; } @@ -90,7 +93,7 @@ public class Track /** * Combine this Track with new data - * @param inOtherTrack + * @param inOtherTrack other track to combine */ public void combine(Track inOtherTrack) { @@ -107,7 +110,7 @@ public class Track // needs to be scaled again _scaled = false; // inform listeners - _broker.informSubscribers(); + UpdateMessageBroker.informSubscribers(); } @@ -122,7 +125,7 @@ public class Track _numPoints = inNewSize; // needs to be scaled again _scaled = false; - _broker.informSubscribers(); + UpdateMessageBroker.informSubscribers(); } } @@ -137,6 +140,7 @@ public class Track // (maybe should be separate thread?) // (maybe should be in separate class?) // (maybe should be based on subtended angles instead of distances?) + // Suggestion: Find last track point, don't delete it (or maybe preserve first and last of each segment?) if (inResolution <= 0) return 0; int numCopied = 0; @@ -147,14 +151,17 @@ public class Track if (yscale > wholeScale) wholeScale = yscale; double minDist = wholeScale / inResolution; + // Keep track of segment start flags of the deleted points + boolean setSegment = false; // Copy selected points DataPoint[] newPointArray = new DataPoint[_numPoints]; int[] pointIndices = new int[_numPoints]; for (int i=0; i<_numPoints; i++) { + DataPoint point = _dataPoints[i]; boolean keepPoint = true; // Don't delete waypoints or photo points - if (!_dataPoints[i].isWaypoint() && _dataPoints[i].getPhoto() == null) + if (!point.isWaypoint() && point.getPhoto() == null) { // go through newPointArray to check for range for (int j=0; j= inEnd || inEnd >= _numPoints) { + return false; + } + boolean foundTimestamp = false; + // Loop over all points within range + for (int i=inStart; i<=inEnd; i++) + { + Timestamp timestamp = _dataPoints[i].getTimestamp(); + if (timestamp != null) + { + // This point has a timestamp so add the offset to it + foundTimestamp = true; + timestamp.addOffset(inOffset); + } + } + return foundTimestamp; + } + + + /** + * Merge the track segments within the given range + * @param inStart start index + * @param inEnd end index + * @return true if successful + */ + public boolean mergeTrackSegments(int inStart, int inEnd) + { + boolean firstTrackPoint = true; + // Loop between start and end + for (int i=inStart; i<=inEnd; i++) { + DataPoint point = getPoint(i); + // Set all segments to false apart from first track point + if (point != null && !point.isWaypoint()) { + point.setSegmentStart(firstTrackPoint); + firstTrackPoint = false; + } + } + // Find following track point, if any + DataPoint nextPoint = getNextTrackPoint(inEnd+1); + if (nextPoint != null) {nextPoint.setSegmentStart(true);} + UpdateMessageBroker.informSubscribers(); + return true; + } + /** * Collect all waypoints to the start or end of the track * @param inAtStart true to collect at start, false for end @@ -381,7 +471,7 @@ public class Track } // needs to be scaled again _scaled = false; - _broker.informSubscribers(); + UpdateMessageBroker.informSubscribers(); return true; } @@ -439,11 +529,66 @@ public class Track _dataPoints = dataCopy; // needs to be scaled again to recalc x, y _scaled = false; - _broker.informSubscribers(); + UpdateMessageBroker.informSubscribers(); return true; } + /** + * Cut and move the specified section + * @param inSectionStart start index of section + * @param inSectionEnd end index of section + * @param inMoveTo index of move to point + * @return true if move successful + */ + public boolean cutAndMoveSection(int inSectionStart, int inSectionEnd, int inMoveTo) + { + // Check that indices make sense + if (inSectionStart > 0 && inSectionEnd > inSectionStart && inMoveTo > 0 + && (inMoveTo < inSectionStart || inMoveTo > (inSectionEnd+1))) + { + // do the cut and move + DataPoint[] newPointArray = new DataPoint[_numPoints]; + // System.out.println("Cut/move section (" + inSectionStart + " - " + inSectionEnd + ") to before point " + inMoveTo); + // Is it a forward copy or a backward copy? + if (inSectionStart > inMoveTo) + { + int sectionLength = inSectionEnd - inSectionStart + 1; + // move section to earlier point + if (inMoveTo > 0) + System.arraycopy(_dataPoints, 0, newPointArray, 0, inMoveTo); // unchanged points before + System.arraycopy(_dataPoints, inSectionStart, newPointArray, inMoveTo, sectionLength); // moved bit + // after insertion point, before moved bit + if (inSectionStart > (inMoveTo + 1)) + System.arraycopy(_dataPoints, inMoveTo, newPointArray, inMoveTo + sectionLength, inSectionStart - inMoveTo); + // after moved bit + if (inSectionEnd < (_numPoints - 1)) + System.arraycopy(_dataPoints, inSectionEnd+1, newPointArray, inSectionEnd+1, _numPoints - inSectionEnd - 1); + } + else + { + // Move section to later point + if (inSectionStart > 0) + System.arraycopy(_dataPoints, 0, newPointArray, 0, inSectionStart); // unchanged points before + // from end of section to move to point + if (inMoveTo > (inSectionEnd + 1)) + System.arraycopy(_dataPoints, inSectionEnd+1, newPointArray, inSectionStart, inMoveTo - inSectionEnd - 1); + // moved bit + System.arraycopy(_dataPoints, inSectionStart, newPointArray, inSectionStart + inMoveTo - inSectionEnd - 1, + inSectionEnd - inSectionStart + 1); + // unchanged bit after + if (inSectionEnd < (_numPoints - 1)) + System.arraycopy(_dataPoints, inMoveTo, newPointArray, inMoveTo, _numPoints - inMoveTo); + } + // Copy array references + _dataPoints = newPointArray; + _scaled = false; + return true; + } + return false; + } + + /** * Interpolate extra points between two selected ones * @param inStartIndex start index of interpolation @@ -481,7 +626,7 @@ public class Track } // needs to be scaled again to recalc x, y _scaled = false; - _broker.informSubscribers(); + UpdateMessageBroker.informSubscribers(); } @@ -537,6 +682,23 @@ public class Track return _yRange; } + /** + * @return The range of lat values as a DoubleRange object + */ + public DoubleRange getLatRange() + { + if (!_scaled) scalePoints(); + return _latRange; + } + /** + * @return The range of lon values as a DoubleRange object + */ + public DoubleRange getLonRange() + { + if (!_scaled) scalePoints(); + return _longRange; + } + /** * @param inPointNum point index, starting at 0 * @return scaled x value of specified point @@ -557,6 +719,26 @@ public class Track return _yValues[inPointNum]; } + /** + * @param inPointNum point index, starting at 0 + * @return scaled x value of specified point + */ + public double getXNew(int inPointNum) + { + if (!_scaled) scalePoints(); + return _xValuesNew[inPointNum]; + } + + /** + * @param inPointNum point index, starting at 0 + * @return scaled y value of specified point + */ + public double getYNew(int inPointNum) + { + if (!_scaled) scalePoints(); + return _yValuesNew[inPointNum]; + } + /** * @return the master field list */ @@ -691,6 +873,8 @@ public class Track // Loop over points and calculate scales _xValues = new double[getNumPoints()]; _yValues = new double[getNumPoints()]; + _xValuesNew = new double[getNumPoints()]; + _yValuesNew = new double[getNumPoints()]; _xRange = new DoubleRange(); _yRange = new DoubleRange(); for (p=0; p < getNumPoints(); p++) @@ -700,8 +884,10 @@ public class Track { _xValues[p] = (point.getLongitude().getDouble() - longMedian) * longFactor; _xRange.addValue(_xValues[p]); + _xValuesNew[p] = MapUtils.getXFromLongitude(point.getLongitude().getDouble()); _yValues[p] = (point.getLatitude().getDouble() - latMedian); _yRange.addValue(_yValues[p]); + _yValuesNew[p] = MapUtils.getYFromLatitude(point.getLatitude().getDouble()); } } _scaled = true; @@ -743,6 +929,119 @@ public class Track } + /** + * Find the nearest point to the specified x and y coordinates + * or -1 if no point is within the specified max distance + * @param inX x coordinate + * @param inY y coordinate + * @param inMaxDist maximum distance from selected coordinates + * @param inJustTrackPoints true if waypoints should be ignored + * @return index of nearest point or -1 if not found + */ + public int getNearestPointIndexNew(double inX, double inY, double inMaxDist, boolean inJustTrackPoints) + { + int nearestPoint = 0; + double nearestDist = -1.0; + double currDist; + for (int i=0; i < getNumPoints(); i++) + { + if (!inJustTrackPoints || !_dataPoints[i].isWaypoint()) + { + currDist = Math.abs(_xValuesNew[i] - inX) + Math.abs(_yValuesNew[i] - inY); + if (currDist < nearestDist || nearestDist < 0.0) + { + nearestPoint = i; + nearestDist = currDist; + } + } + } + // Check whether it's within required distance + if (nearestDist > inMaxDist && inMaxDist > 0.0) + { + return -1; + } + return nearestPoint; + } + + /** + * Get the next track point starting from the given index + * @param inStartIndex index to start looking from + * @return next track point, or null if end of data reached + */ + public DataPoint getNextTrackPoint(int inStartIndex) + { + return getNextTrackPoint(inStartIndex, _numPoints, true); + } + + /** + * Get the next track point in the given range + * @param inStartIndex index to start looking from + * @param inEndIndex index to stop looking + * @return next track point, or null if end of data reached + */ + public DataPoint getNextTrackPoint(int inStartIndex, int inEndIndex) + { + return getNextTrackPoint(inStartIndex, inEndIndex, true); + } + + /** + * Get the previous track point starting from the given index + * @param inStartIndex index to start looking from + * @return next track point, or null if end of data reached + */ + public DataPoint getPreviousTrackPoint(int inStartIndex) + { + return getNextTrackPoint(inStartIndex, _numPoints, false); + } + + /** + * Get the next track point starting from the given index + * @param inStartIndex index to start looking from + * @param inEndIndex index to stop looking (inclusive) + * @param inCountUp true for next, false for previous + * @return next track point, or null if end of data reached + */ + private DataPoint getNextTrackPoint(int inStartIndex, int inEndIndex, boolean inCountUp) + { + // Loop forever over points + int increment = inCountUp?1:-1; + for (int i=inStartIndex; i<=inEndIndex; i+=increment) + { + DataPoint point = getPoint(i); + // Exit if end of data reached - there wasn't a track point + if (point == null) {return null;} + if (point.isValid() && !point.isWaypoint()) { + // next track point found + return point; + } + } + return null; + } + + /** + * Shift all the segment start flags in the given range by 1 + * Method used by reverse range and its undo + * @param inStartIndex start of range, inclusive + * @param inEndIndex end of range, inclusive + */ + public void shiftSegmentStarts(int inStartIndex, int inEndIndex) + { + boolean prevFlag = true; + boolean currFlag = true; + for (int i=inStartIndex; i<= inEndIndex; i++) + { + DataPoint point = getPoint(i); + if (point != null && !point.isWaypoint()) + { + // remember flag + currFlag = point.getSegmentStart(); + // shift flag by 1 + point.setSegmentStart(prevFlag); + prevFlag = currFlag; + } + } + } + ////////////////// Cloning and replacing /////////////////// /** @@ -807,7 +1106,7 @@ public class Track _numPoints++; // needs to be scaled again _scaled = false; - _broker.informSubscribers(); + UpdateMessageBroker.informSubscribers(); return true; } @@ -840,7 +1139,7 @@ public class Track _numPoints += inPoints.length; // needs to be scaled again _scaled = false; - _broker.informSubscribers(); + UpdateMessageBroker.informSubscribers(); return true; } @@ -848,6 +1147,7 @@ public class Track /** * Replace the track contents with the given point array * @param inContents array of DataPoint objects + * @return true on success */ public boolean replaceContents(DataPoint[] inContents) { @@ -857,7 +1157,7 @@ public class Track _dataPoints = inContents; _numPoints = _dataPoints.length; _scaled = false; - _broker.informSubscribers(); + UpdateMessageBroker.informSubscribers(); return true; } @@ -892,7 +1192,7 @@ public class Track // point possibly needs to be scaled again _scaled = false; // trigger listeners - _broker.informSubscribers(); + UpdateMessageBroker.informSubscribers(); return true; } return false;