mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-21 19:50:01 +00:00
don't insert extrapolated fixes anywhere except at the end; use real fixes if extrapolation is requested and we have a real fix for the "to" time point
Change-Id: I83fcb72a3d09b97922f918234263ba167f0e7645
This commit is contained in:
1 parent
6746b39028
commit
a0302d97b9
2 files changed
+72
-49
No files matched your search
+64
-43
@@ -227,31 +227,44 @@ public class FixesAndTails {
|
||||
Map<CompetitorDTO, Boolean> overlapsWithKnownFixes, TailFactory tailFactory, long timeForPositionTransitionMillis) {
|
||||
for (final Map.Entry<CompetitorDTO, List<GPSFixDTOWithSpeedWindTackAndLegType>> e : fixesForCompetitors.entrySet()) {
|
||||
if (e.getValue() != null && !e.getValue().isEmpty()) {
|
||||
List<GPSFixDTOWithSpeedWindTackAndLegType> fixesForCompetitor = fixes.get(e.getKey());
|
||||
final CompetitorDTO competitor = e.getKey();
|
||||
List<GPSFixDTOWithSpeedWindTackAndLegType> fixesForCompetitor = fixes.get(competitor);
|
||||
if (fixesForCompetitor == null) {
|
||||
fixesForCompetitor = new ArrayList<GPSFixDTOWithSpeedWindTackAndLegType>();
|
||||
fixes.put(e.getKey(), fixesForCompetitor);
|
||||
fixes.put(competitor, fixesForCompetitor);
|
||||
}
|
||||
if (!overlapsWithKnownFixes.get(e.getKey())) {
|
||||
if (!overlapsWithKnownFixes.get(competitor)) {
|
||||
// clearing and then re-populating establishes the invariant that an extrapolated fix must be the last
|
||||
fixesForCompetitor.clear();
|
||||
// to re-establish the invariants for tails, firstShownFix and lastShownFix, we now need to remove
|
||||
// all points from the competitor's polyline and clear the entries in firstShownFix and lastShownFix
|
||||
final Triggerable triggerable = new Triggerable(new Runnable() { @Override public void run() { clearTail(e.getKey()); } });
|
||||
final Trigger<Polyline> tailTrigger = tails.get(e.getKey());
|
||||
if (tailTrigger != null) {
|
||||
tailTrigger.register(triggerable);
|
||||
}
|
||||
registerIndexTrigger(triggerable, firstShownFix, e.getKey());
|
||||
registerIndexTrigger(triggerable, lastShownFix, e.getKey());
|
||||
final Triggerable triggerable = new Triggerable(new Runnable() { @Override public void run() { clearTail(competitor); } });
|
||||
registerTriggerable(competitor, triggerable);
|
||||
fixesForCompetitor.addAll(e.getValue());
|
||||
overlapsWithKnownFixes.put(e.getKey(), true); // In case this was only one part of a split request, the next request *does* have an overlap
|
||||
overlapsWithKnownFixes.put(competitor, true); // In case this was only one part of a split request, the next request *does* have an overlap
|
||||
} else {
|
||||
mergeFixes(e.getKey(), e.getValue(), timeForPositionTransitionMillis);
|
||||
mergeFixes(competitor, e.getValue(), timeForPositionTransitionMillis);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link Triggerable} that is usually a {@link TriggerableTimer} and is or will be scheduled for delayed execution
|
||||
* will be registered with the {@link #tails}, {@link #firstShownFix} and {@link #lastShownFix} structures such that
|
||||
* when any of them is accessed for the {@code competitor} passed as parameter then the {@code triggerable} will be
|
||||
* triggered to ensure consistency and establish all invariants. This way, invariants may temporarily be left unmet
|
||||
* which gives the UI a better chance of delaying particularly the tail updates. However, in case of read access the
|
||||
* invariants all must be established, hence the trigger pattern.
|
||||
*/
|
||||
private void registerTriggerable(final CompetitorDTO competitor, final Triggerable triggerable) {
|
||||
final Trigger<Polyline> tailTrigger = tails.get(competitor);
|
||||
if (tailTrigger != null) {
|
||||
tailTrigger.register(triggerable);
|
||||
}
|
||||
registerIndexTrigger(triggerable, firstShownFix, competitor);
|
||||
registerIndexTrigger(triggerable, lastShownFix, competitor);
|
||||
}
|
||||
|
||||
private void registerIndexTrigger(Triggerable triggerable, Map<CompetitorDTO, Trigger<Integer>> indexMap, CompetitorDTO competitor) {
|
||||
Trigger<Integer> firstShownFixTrigger = indexMap.get(competitor);
|
||||
@@ -325,6 +338,7 @@ public class FixesAndTails {
|
||||
tail.getPath().removeAt(finalIntoThisIndex - finalIndexOfFirstShownFix);
|
||||
}
|
||||
});
|
||||
registerTriggerable(competitorDTO, triggerable);
|
||||
Timer timer = new TriggerableTimer(triggerable);
|
||||
runDelayedOrImmediately(timer, (int) (timeForPositionTransitionMillis==-1?-1:timeForPositionTransitionMillis/2));
|
||||
}
|
||||
@@ -337,40 +351,47 @@ public class FixesAndTails {
|
||||
intoThisIndex--;
|
||||
}
|
||||
} else {
|
||||
intoThis.add(intoThisIndex, mergeThisFix);
|
||||
if (tail != null && intoThisIndex >= indexOfFirstShownFix && intoThisIndex <= indexOfLastShownFix) {
|
||||
// fix inserted at a position currently visualized by tail
|
||||
tail.getPath().insertAt(intoThisIndex - indexOfFirstShownFix, coordinateSystem.toLatLng(mergeThisFix.position));
|
||||
}
|
||||
if (intoThisIndex < indexOfFirstShownFix) {
|
||||
indexOfFirstShownFix++;
|
||||
}
|
||||
if (intoThisIndex <= indexOfLastShownFix) {
|
||||
indexOfLastShownFix++;
|
||||
}
|
||||
// If there is a fix prior to the one added and that prior fix was obtained by extrapolation, remove it now because
|
||||
// extrapolated fixes can only be the last in the list
|
||||
if (intoThisIndex > 0 && intoThis.get(intoThisIndex-1).extrapolated) {
|
||||
intoThis.remove(intoThisIndex-1);
|
||||
if (tail != null && intoThisIndex-1 >= indexOfFirstShownFix && intoThisIndex-1 <= indexOfLastShownFix) {
|
||||
final int finalIntoThisIndex = intoThisIndex;
|
||||
final int finalIndexOfFirstShownFix = indexOfFirstShownFix;
|
||||
Triggerable triggerable = new Triggerable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
tail.getPath().removeAt(finalIntoThisIndex-1 - finalIndexOfFirstShownFix);
|
||||
}
|
||||
});
|
||||
Timer timer = new TriggerableTimer(triggerable);
|
||||
runDelayedOrImmediately(timer, (int) (timeForPositionTransitionMillis==-1?-1:timeForPositionTransitionMillis/2));
|
||||
// insert the fix only if it is not extrapolated or if the extrapolated fix is to be appended to the end (including
|
||||
// being the only fix)
|
||||
if (!mergeThisFix.extrapolated || intoThisIndex == intoThis.size()) {
|
||||
intoThis.add(intoThisIndex, mergeThisFix);
|
||||
if (tail != null && intoThisIndex >= indexOfFirstShownFix && intoThisIndex <= indexOfLastShownFix) {
|
||||
// fix inserted at a position currently visualized by tail
|
||||
tail.getPath().insertAt(intoThisIndex - indexOfFirstShownFix, coordinateSystem.toLatLng(mergeThisFix.position));
|
||||
}
|
||||
if (intoThisIndex-1 < indexOfFirstShownFix) {
|
||||
indexOfFirstShownFix--;
|
||||
if (intoThisIndex < indexOfFirstShownFix) {
|
||||
indexOfFirstShownFix++;
|
||||
}
|
||||
if (intoThisIndex-1 <= indexOfLastShownFix) {
|
||||
indexOfLastShownFix--;
|
||||
if (intoThisIndex <= indexOfLastShownFix) {
|
||||
indexOfLastShownFix++;
|
||||
}
|
||||
intoThisIndex--;
|
||||
// If there is a fix prior to the one added and that prior fix was obtained by extrapolation, remove it now because
|
||||
// extrapolated fixes can only be the last in the list
|
||||
if (intoThisIndex > 0 && intoThis.get(intoThisIndex-1).extrapolated) {
|
||||
intoThis.remove(intoThisIndex-1);
|
||||
if (tail != null && intoThisIndex-1 >= indexOfFirstShownFix && intoThisIndex-1 <= indexOfLastShownFix) {
|
||||
final int finalIntoThisIndex = intoThisIndex;
|
||||
final int finalIndexOfFirstShownFix = indexOfFirstShownFix;
|
||||
Triggerable triggerable = new Triggerable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
tail.getPath().removeAt(finalIntoThisIndex-1 - finalIndexOfFirstShownFix);
|
||||
}
|
||||
});
|
||||
registerTriggerable(competitorDTO, triggerable);
|
||||
Timer timer = new TriggerableTimer(triggerable);
|
||||
runDelayedOrImmediately(timer, (int) (timeForPositionTransitionMillis==-1?-1:timeForPositionTransitionMillis/2));
|
||||
}
|
||||
if (intoThisIndex-1 < indexOfFirstShownFix) {
|
||||
indexOfFirstShownFix--;
|
||||
}
|
||||
if (intoThisIndex-1 <= indexOfLastShownFix) {
|
||||
indexOfLastShownFix--;
|
||||
}
|
||||
intoThisIndex--;
|
||||
}
|
||||
} else {
|
||||
intoThisIndex--; // to compensate for the following ++
|
||||
}
|
||||
}
|
||||
intoThisIndex++;
|
||||
|
||||
+8
-6
@@ -1717,12 +1717,13 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
* date provided as value
|
||||
* @param to
|
||||
* for the list of competitors provided as keys (expected to be equal to the set of competitors used as
|
||||
* keys in the <code>from</code> parameter, requests the GPS fixes up to but excluding the date provided
|
||||
* as value
|
||||
* keys in the <code>from</code> parameter, requests the GPS fixes up to but excluding (except
|
||||
* {@code extrapolate} is {@code true}) the date provided as value
|
||||
* @param extrapolate
|
||||
* if <code>true</code> and no (exact or interpolated) position is known for <code>date</code>, the last
|
||||
* if <code>true</code> and no (exact or interpolated) position is known for <code>to</code>, the last
|
||||
* entry returned in the list of GPS fixes will be obtained by extrapolating from the competitors last
|
||||
* known position before <code>date</code> and the estimated speed.
|
||||
* known position at <code>to</code> and the estimated speed. With this, the {@code to} time point is no
|
||||
* longer exclusive.
|
||||
* @return a map where for each competitor participating in the race the list of GPS fixes in increasing
|
||||
* chronological order is provided. The last one is the last position at or before <code>date</code>.
|
||||
*/
|
||||
@@ -1750,7 +1751,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
Iterator<GPSFixMoving> fixIter = track.getFixesIterator(fromTimePoint, /* inclusive */true);
|
||||
while (fixIter.hasNext()) {
|
||||
GPSFixMoving fix = fixIter.next();
|
||||
if (fix.getTimePoint().before(toTimePointExcluding)) {
|
||||
if (fix.getTimePoint().before(toTimePointExcluding) ||
|
||||
(extrapolate && fix.getTimePoint().equals(toTimePointExcluding))) {
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
logger.finest(""+competitor.getName()+": " + fix);
|
||||
}
|
||||
@@ -1814,7 +1816,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
if (fixIter.hasNext()) {
|
||||
fix = fixIter.next();
|
||||
} else {
|
||||
// check if fix was at date and if extrapolation is requested
|
||||
// check if fix was at date and if extrapolation is requested;
|
||||
if (!fix.getTimePoint().equals(toTimePointExcluding) && extrapolate) {
|
||||
Position position = track.getEstimatedPosition(toTimePointExcluding, extrapolate);
|
||||
Wind wind2 = trackedRace.getWind(position, toTimePointExcluding);
|
||||
|
||||
Reference in new issue
Block a user