mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-11 14:50:56 +00:00
prepared track for distinguishing between raw and smoothened fixes
This commit is contained in:
1 parent
cc1a24dae7
commit
f22c6fda80
12 files changed
+68
-39
No files matched your search
+1
-1
@@ -219,7 +219,7 @@ public abstract class AbstractTracTracLiveTest implements Listener {
|
||||
|
||||
protected void storeTrack(Competitor competitor, DynamicTrack<Competitor, GPSFixMoving> track) throws FileNotFoundException, IOException {
|
||||
ObjectOutput oo = getOutputStream(competitor);
|
||||
for (GPSFixMoving fix : track.getFixes()) {
|
||||
for (GPSFixMoving fix : track.getRawFixes()) {
|
||||
writeGPSFixMoving(fix, oo);
|
||||
}
|
||||
oo.close();
|
||||
|
||||
+1
-1
@@ -129,7 +129,7 @@ public class TrackSmootheningTest extends AbstractTracTracLiveTest {
|
||||
TimePoint lastTimePoint = null;
|
||||
GPSFixMoving lastFix = null;
|
||||
GPSFixMoving outlier = null;
|
||||
for (GPSFixMoving fix : track.getFixes()) {
|
||||
for (GPSFixMoving fix : track.getRawFixes()) {
|
||||
if (lastTimePoint != null) {
|
||||
TimePoint thisTimePoint = fix.getTimePoint();
|
||||
long intervalInMillis = thisTimePoint.asMillis()-lastTimePoint.asMillis();
|
||||
|
||||
@@ -73,7 +73,7 @@ public class TrackTest {
|
||||
|
||||
@Test
|
||||
public void testIterate() {
|
||||
Iterator<GPSFixMoving> i = track.getFixes().iterator();
|
||||
Iterator<GPSFixMoving> i = track.getRawFixes().iterator();
|
||||
int count;
|
||||
for (count=0; i.hasNext(); count++) {
|
||||
i.next();
|
||||
@@ -86,24 +86,24 @@ public class TrackTest {
|
||||
long lastMillis = 0;
|
||||
GPSFix lastFix = null;
|
||||
boolean first = true;
|
||||
for (Iterator<GPSFixMoving> i = track.getFixes().iterator(); i.hasNext(); first = false) {
|
||||
for (Iterator<GPSFixMoving> i = track.getRawFixes().iterator(); i.hasNext(); first = false) {
|
||||
GPSFixMoving fix = i.next();
|
||||
long millis = fix.getTimePoint().asMillis();
|
||||
if (!first) {
|
||||
assertTrue(millis > lastMillis);
|
||||
TimePoint inBetweenTimePoint = new MillisecondsTimePoint((millis+lastMillis)/2);
|
||||
assertEquals(lastFix, track.getLastFixBefore(inBetweenTimePoint));
|
||||
assertEquals(lastFix, track.getLastRawFixBefore(inBetweenTimePoint));
|
||||
assertEquals(lastFix, track.getLastFixAtOrBefore(inBetweenTimePoint));
|
||||
assertEquals(fix, track.getFirstFixAfter(inBetweenTimePoint));
|
||||
assertEquals(fix, track.getFirstFixAtOrAfter(inBetweenTimePoint));
|
||||
assertEquals(fix, track.getFirstRawFixAtOrAfter(inBetweenTimePoint));
|
||||
|
||||
assertEquals(lastFix, track.getLastFixAtOrBefore(lastFix.getTimePoint()));
|
||||
assertEquals(fix, track.getFirstFixAtOrAfter(fix.getTimePoint()));
|
||||
assertEquals(fix, track.getFirstRawFixAtOrAfter(fix.getTimePoint()));
|
||||
|
||||
assertEquals(lastFix, track.getLastFixBefore(fix.getTimePoint()));
|
||||
assertEquals(lastFix, track.getLastRawFixBefore(fix.getTimePoint()));
|
||||
assertEquals(fix, track.getLastFixAtOrBefore(fix.getTimePoint()));
|
||||
assertEquals(fix, track.getFirstFixAfter(lastFix.getTimePoint()));
|
||||
assertEquals(lastFix, track.getFirstFixAtOrAfter(lastFix.getTimePoint()));
|
||||
assertEquals(lastFix, track.getFirstRawFixAtOrAfter(lastFix.getTimePoint()));
|
||||
}
|
||||
lastMillis = millis;
|
||||
lastFix = fix;
|
||||
@@ -112,7 +112,7 @@ public class TrackTest {
|
||||
|
||||
@Test
|
||||
public void assertEstimatedPositionBeforeStartIsStart() {
|
||||
GPSFixMoving start = track.getFixes().iterator().next();
|
||||
GPSFixMoving start = track.getRawFixes().iterator().next();
|
||||
TimePoint oneNanoBeforeStart = new MillisecondsTimePoint(start.getTimePoint().asMillis()-1);
|
||||
assertEquals(start.getPosition(), track.getEstimatedPosition(oneNanoBeforeStart, false));
|
||||
}
|
||||
@@ -122,7 +122,7 @@ public class TrackTest {
|
||||
long lastMillis = 0;
|
||||
GPSFix lastFix = null;
|
||||
boolean first = true;
|
||||
for (Iterator<GPSFixMoving> i = track.getFixes().iterator(); i.hasNext(); first = false) {
|
||||
for (Iterator<GPSFixMoving> i = track.getRawFixes().iterator(); i.hasNext(); first = false) {
|
||||
GPSFixMoving fix = i.next();
|
||||
long millis = fix.getTimePoint().asMillis();
|
||||
if (!first) {
|
||||
@@ -143,9 +143,9 @@ public class TrackTest {
|
||||
|
||||
@Test
|
||||
public void testSimpleExtrapolation() {
|
||||
GPSFix fix = track.getLastFix();
|
||||
GPSFix fix = track.getLastRawFix();
|
||||
long millis = fix.getTimePoint().asMillis();
|
||||
GPSFix lastFix = track.getLastFixBefore(fix.getTimePoint());
|
||||
GPSFix lastFix = track.getLastRawFixBefore(fix.getTimePoint());
|
||||
long lastMillis = lastFix.getTimePoint().asMillis();
|
||||
TimePoint afterTimePoint = new MillisecondsTimePoint(millis + (millis-lastMillis));
|
||||
Position extrapolatedPosition = track.getEstimatedPosition(afterTimePoint, true);
|
||||
@@ -155,9 +155,9 @@ public class TrackTest {
|
||||
|
||||
@Test
|
||||
public void testExtrapolationDoesntHappenIfSuppressed() {
|
||||
GPSFix fix = track.getLastFix();
|
||||
GPSFix fix = track.getLastRawFix();
|
||||
long millis = fix.getTimePoint().asMillis();
|
||||
GPSFix lastFix = track.getLastFixBefore(fix.getTimePoint());
|
||||
GPSFix lastFix = track.getLastRawFixBefore(fix.getTimePoint());
|
||||
long lastMillis = lastFix.getTimePoint().asMillis();
|
||||
TimePoint afterTimePoint = new MillisecondsTimePoint(millis + (millis-lastMillis));
|
||||
Position extrapolatedPosition = track.getEstimatedPosition(afterTimePoint, false);
|
||||
@@ -170,7 +170,7 @@ public class TrackTest {
|
||||
List<GPSFixMoving> fixes = new ArrayList<GPSFixMoving>();
|
||||
boolean first = true;
|
||||
GPSFixMoving oldFix = null;
|
||||
for (GPSFixMoving fix : track.getFixes()) {
|
||||
for (GPSFixMoving fix : track.getRawFixes()) {
|
||||
fixes.add(fix);
|
||||
if (first) {
|
||||
first = false;
|
||||
@@ -228,7 +228,7 @@ public class TrackTest {
|
||||
@Test
|
||||
public void testDistanceTraveledOnInBetweenSectionFromFixToFix() {
|
||||
// take second and third fix and compute distance between them
|
||||
Iterator<GPSFixMoving> iter = track.getFixes().iterator();
|
||||
Iterator<GPSFixMoving> iter = track.getRawFixes().iterator();
|
||||
iter.next(); // skip first;
|
||||
GPSFix second = iter.next();
|
||||
GPSFix third = iter.next();
|
||||
|
||||
+1
-1
@@ -138,7 +138,7 @@ public class RaceTrackerImpl implements Listener, RaceTracker {
|
||||
boolean first = true;
|
||||
for (Buoy buoy : domainControlPoint.getBuoys()) {
|
||||
DynamicTrack<Buoy, GPSFix> buoyTrack = trackedRace.getTrack(buoy);
|
||||
if (buoyTrack.getFirstFix() == null) {
|
||||
if (buoyTrack.getFirstRawFix() == null) {
|
||||
buoyTrack.addGPSFix(new GPSFixImpl(new DegreePosition(
|
||||
first ? controlPoint.getLat1() : controlPoint.getLat2(),
|
||||
first ? controlPoint.getLon1() : controlPoint.getLon2()), MillisecondsTimePoint.now()));
|
||||
|
||||
@@ -17,24 +17,28 @@ public interface Track<FixType extends Timed> {
|
||||
* applied to the fixes returned by this method.
|
||||
*/
|
||||
Iterable<FixType> getFixes();
|
||||
|
||||
Iterable<FixType> getRawFixes();
|
||||
|
||||
FixType getLastFixAtOrBefore(TimePoint timePoint);
|
||||
|
||||
FixType getFirstFixAtOrAfter(TimePoint timePoint);
|
||||
FixType getFirstRawFixAtOrAfter(TimePoint timePoint);
|
||||
|
||||
FixType getLastFixBefore(TimePoint timePoint);
|
||||
FixType getLastRawFixBefore(TimePoint timePoint);
|
||||
|
||||
FixType getFirstFixAfter(TimePoint timePoint);
|
||||
|
||||
/**
|
||||
* The first fix in this track or <code>null</code> if the track is empty
|
||||
* The first fix in this track or <code>null</code> if the track is empty. The fix returned may
|
||||
* be an outlier that is not returned by calls operating on the smoothened version of the track.
|
||||
*/
|
||||
FixType getFirstFix();
|
||||
FixType getFirstRawFix();
|
||||
|
||||
/**
|
||||
* The last fix in this track or <code>null</code> if the track is empty
|
||||
* The last fix in this track or <code>null</code> if the track is empty. The fix returned may
|
||||
* be an outlier that is not returned by calls operating on the smoothened version of the track.
|
||||
*/
|
||||
FixType getLastFix();
|
||||
FixType getLastRawFix();
|
||||
|
||||
/**
|
||||
* Returns an iterator starting at the first fix after <code>startingAt</code> (or "at or after" in case
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ public class DynamicTrackImpl<ItemType, FixType extends GPSFix> extends
|
||||
|
||||
@Override
|
||||
public void addGPSFix(FixType gpsFix) {
|
||||
getInternalFixes().add(gpsFix);
|
||||
getInternalRawFixes().add(gpsFix);
|
||||
for (RaceChangeListener<ItemType> listener : listeners) {
|
||||
listener.gpsFixReceived(gpsFix, getTrackedItem());
|
||||
}
|
||||
|
||||
+6
-2
@@ -54,7 +54,7 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends TrackImpl
|
||||
@Override
|
||||
public Position getEstimatedPosition(TimePoint timePoint, boolean extrapolate) {
|
||||
FixType lastFixAtOrBefore = getLastFixAtOrBefore(timePoint);
|
||||
FixType firstFixAtOrAfter = getFirstFixAtOrAfter(timePoint);
|
||||
FixType firstFixAtOrAfter = getFirstRawFixAtOrAfter(timePoint);
|
||||
if (lastFixAtOrBefore != null && lastFixAtOrBefore == firstFixAtOrAfter) {
|
||||
return lastFixAtOrBefore.getPosition(); // exact match; how unlikely is that?
|
||||
} else {
|
||||
@@ -109,7 +109,7 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends TrackImpl
|
||||
return null;
|
||||
}
|
||||
} else if (fix2 == null) {
|
||||
FixType lastBeforeFix1 = getLastFixBefore(fix1.getTimePoint());
|
||||
FixType lastBeforeFix1 = getLastRawFixBefore(fix1.getTimePoint());
|
||||
if (lastBeforeFix1 != null) {
|
||||
fix2 = fix1;
|
||||
fix1 = lastBeforeFix1; // compute speed based on the last two fixes and assume constant speed
|
||||
@@ -129,6 +129,10 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends TrackImpl
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the smoothened fixes (see {@link #getInternalFixes()}), type-cast such that it's a set of {@link GPSFix}
|
||||
* objects
|
||||
*/
|
||||
private NavigableSet<GPSFix> getGPSFixes() {
|
||||
@SuppressWarnings("unchecked")
|
||||
NavigableSet<GPSFix> result = (NavigableSet<GPSFix>) super.getInternalFixes();
|
||||
|
||||
+25
-5
@@ -32,18 +32,38 @@ public abstract class TrackImpl<FixType extends Timed> implements Track<FixType>
|
||||
this.fixes = new ConcurrentSkipListSet<Timed>(TimedComparator.INSTANCE);
|
||||
}
|
||||
|
||||
protected NavigableSet<FixType> getInternalRawFixes() {
|
||||
@SuppressWarnings("unchecked")
|
||||
NavigableSet<FixType> result = (NavigableSet<FixType>) fixes;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the smoothened fixes
|
||||
*/
|
||||
protected NavigableSet<FixType> getInternalFixes() {
|
||||
// TODO smoothen the track before returning it, or construct a smoothening "view" onto it
|
||||
@SuppressWarnings("unchecked")
|
||||
NavigableSet<FixType> result = (NavigableSet<FixType>) fixes;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates the fixes in the order of their time points
|
||||
* Iterates the fixes with outliers getting skipped, in the order of their time points
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Iterable<FixType> getFixes() {
|
||||
// TODO skip outliers in iterable returned
|
||||
return (Iterable<FixType>) Collections.unmodifiableSet(fixes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the raw sequence of fixes, all potential outliers included
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Iterable<FixType> getRawFixes() {
|
||||
return (Iterable<FixType>) Collections.unmodifiableSet(fixes);
|
||||
}
|
||||
|
||||
@@ -55,13 +75,13 @@ public abstract class TrackImpl<FixType extends Timed> implements Track<FixType>
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public FixType getFirstFixAtOrAfter(TimePoint timePoint) {
|
||||
public FixType getFirstRawFixAtOrAfter(TimePoint timePoint) {
|
||||
return (FixType) fixes.ceiling(new DummyTimed(timePoint));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public FixType getLastFixBefore(TimePoint timePoint) {
|
||||
public FixType getLastRawFixBefore(TimePoint timePoint) {
|
||||
return (FixType) fixes.lower(new DummyTimed(timePoint));
|
||||
}
|
||||
|
||||
@@ -73,7 +93,7 @@ public abstract class TrackImpl<FixType extends Timed> implements Track<FixType>
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public FixType getFirstFix() {
|
||||
public FixType getFirstRawFix() {
|
||||
if (fixes.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
@@ -83,7 +103,7 @@ public abstract class TrackImpl<FixType extends Timed> implements Track<FixType>
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public FixType getLastFix() {
|
||||
public FixType getLastRawFix() {
|
||||
if (fixes.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
|
||||
timePointToUse = getMarkPassingForLegEnd().getTimePoint();
|
||||
} else {
|
||||
// use time point of latest fix
|
||||
GPSFixMoving lastFix = getTrackedRace().getTrack(getCompetitor()).getLastFix();
|
||||
GPSFixMoving lastFix = getTrackedRace().getTrack(getCompetitor()).getLastRawFix();
|
||||
if (lastFix != null) {
|
||||
timePointToUse = lastFix.getTimePoint();
|
||||
} else {
|
||||
|
||||
+5
-4
@@ -51,7 +51,7 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
|
||||
|
||||
@Override
|
||||
public void add(Wind wind) {
|
||||
getInternalFixes().add(wind);
|
||||
getInternalRawFixes().add(wind);
|
||||
notifyListenersAboutReceive(wind);
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (Wind wind : getFixes()) {
|
||||
for (Wind wind : getRawFixes()) {
|
||||
result.append(wind);
|
||||
result.append(" avg(");
|
||||
result.append(millisecondsOverWhichToAverage);
|
||||
@@ -178,7 +178,7 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
|
||||
|
||||
public String toCSV() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (Wind wind : getFixes()) {
|
||||
for (Wind wind : getRawFixes()) {
|
||||
append(result, wind);
|
||||
Wind estimate = getEstimatedWind(wind.getPosition(), wind.getTimePoint());
|
||||
append(result, estimate);
|
||||
@@ -245,7 +245,8 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
|
||||
|
||||
@Override
|
||||
public void remove(Wind wind) {
|
||||
getInternalFixes().remove(wind);
|
||||
getInternalRawFixes().remove(wind);
|
||||
notifyListenersAboutRemoval(wind);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -254,7 +254,7 @@ public class UDPExpeditionReceiverTest {
|
||||
if (m.getTrueWind() != null) {
|
||||
Declination declination = declinationService.getDeclination(m.getTimePoint(), lastKnownPosition,
|
||||
/* timeoutForOnlineFetchInMilliseconds */5000);
|
||||
for (Wind recordedWind : race.getWindTrack().getFixes()) {
|
||||
for (Wind recordedWind : race.getWindTrack().getRawFixes()) {
|
||||
if (Math.abs(m.getTrueWindBearing().getDegrees() + declination.getBearingCorrectedTo(m.getTimePoint()).getDegrees() -
|
||||
recordedWind.getBearing().getDegrees()) <= 0.0000001) {
|
||||
matched.add(recordedWind);
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ public class TestStoringAndRetrievingWindTracks extends AbstractTracTracLiveTest
|
||||
WindTrack result = DomainObjectFactory.INSTANCE.loadWindTrack(domainEvent, race, windSource, /* millisecondsOverWhichToAverage */
|
||||
30000, database);
|
||||
double myBearingDeg = 123.4;
|
||||
for (Wind wind : result.getFixes()) {
|
||||
for (Wind wind : result.getRawFixes()) {
|
||||
assertEquals(pos, wind.getPosition());
|
||||
assertEquals(10., wind.getKnots(), 0.000000000001);
|
||||
assertEquals(myBearingDeg, wind.getBearing().getDegrees(), 0.000000001);
|
||||
|
||||
Reference in new issue
Block a user