package com.github.pfichtner.jrunalyser.base.data.track;
import static com.google.common.base.Preconditions.checkArgument;
import java.util.Collection;
import java.util.List;
import com.github.pfichtner.jrunalyser.base.data.DefaultDistance;
import com.github.pfichtner.jrunalyser.base.data.Distance;
import com.github.pfichtner.jrunalyser.base.data.DistanceUnit;
import com.github.pfichtner.jrunalyser.base.data.DivideTrack;
import com.github.pfichtner.jrunalyser.base.data.GeoUtil;
import com.github.pfichtner.jrunalyser.base.data.LinkedTrackPoint;
import com.github.pfichtner.jrunalyser.base.data.WayPoint;
import com.github.pfichtner.jrunalyser.base.data.segment.Segment;
import com.github.pfichtner.jrunalyser.base.data.segmenter.Segmenters;
import com.github.pfichtner.jrunalyser.base.data.stat.DefaultStatistics;
import com.github.pfichtner.jrunalyser.base.data.stat.Statistics;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
public class Tracks {
private Tracks() {
super();
}
public static LinkedTrackPoint getStartPoint(Track track) {
return getStartPoint(track.getTrackpoints());
}
public static LinkedTrackPoint getStartPoint(
Collection<? extends LinkedTrackPoint> trackpoints) {
return Iterables.get(checkNotEmpty(trackpoints), 0);
}
public static LinkedTrackPoint getEndPoint(Track track) {
return getEndPoint(track.getTrackpoints());
}
public static LinkedTrackPoint getEndPoint(
Collection<? extends LinkedTrackPoint> trackpoints) {
return Iterables.getLast(checkNotEmpty(trackpoints));
}
private static <T> Collection<T> checkNotEmpty(Collection<T> wps) {
checkArgument(!wps.isEmpty(), "Track has no waypoints");
return wps;
}
/**
* Creates a new Track with all trackpoints (and segments) reversed. The
* statistics are recalculated since they could differ from the original's
* one
*
* @return reversed Track
*/
public static Track reverseView(final Track track) {
return new Track() {
@Override
public Statistics getStatistics() {
return DefaultStatistics.ofTrack(this);
}
@Override
public List<? extends LinkedTrackPoint> getTrackpoints() {
return Lists.reverse(track.getTrackpoints());
}
@Override
public List<Segment> getSegments() {
return Lists.reverse(track.getSegments());
}
@Override
public Metadata getMetadata() {
return track.getMetadata();
}
@Override
public Id getId() {
return track.getId();
}
@Override
public List<? extends WayPoint> getWaypoints() {
return track.getWaypoints();
}
};
}
public static Track reverse(Track track) {
Track view = reverseView(track);
return new DefaultTrack(view.getId(), view.getMetadata(),
track.getWaypoints(), view.getSegments(), view.getStatistics());
}
/**
* Returns <code>true</code> if startpos and endpos of the track are nearby.
*
* @param track
* the track to check
* @return <code>true</code> if startpos and endpos are nearby
*/
public static boolean isRoundtrip(Track track) {
Distance maxDiff = DefaultDistance.of(75, DistanceUnit.METERS);
Distance diffMeters = GeoUtil.calcDistance(getStartPoint(track),
getEndPoint(track));
return diffMeters.compareTo(maxDiff) <= 0;
}
/**
* Returns <code>true</code> if the track's away and return ways are
* (nearly) identical.
*
* @param track
* the track to check
* @return <code>true</code> if the track's away and return ways are
* (nearly) identical
*/
public static boolean isAwayEqReturn(Track track) {
Distance maxDiff = DefaultDistance.of(75, DistanceUnit.METERS);
int parts = 20; // must be even!
List<Segment> segments = Segmenters
.getSegmenter(new DivideTrack(parts, Distance.class))
.segment(track).getSegments();
for (int i = 0; i < segments.size() / 2; i++) {
WayPoint fw = Iterables.get(segments.get(i).getTrackpoints(), 0);
WayPoint bw = Iterables.getLast(segments.get(
segments.size() - 1 - i).getTrackpoints());
Distance diffMeters = GeoUtil.calcDistance(fw, bw);
if (diffMeters.compareTo(maxDiff) > 0) {
return false;
}
}
return true;
}
}