refactored CandidateFinder such that always the race's current course is used to obtain the waypoints list, and passing instructions are re-calculated on the fly if necessary

This commit is contained in:
Axel Uhl committed 2015-03-31 23:07:33 +02:00
1 parent 992229594d
commit f1d6e22070
1 file changed
+67 -40
@@ -73,19 +73,12 @@ public class CandidateFinderImpl implements CandidateFinder {
public CandidateFinderImpl(DynamicTrackedRace race) {
this.race = race;
RaceDefinition raceDefinition = race.getRace();
Course course = raceDefinition.getCourse();
Iterable<Waypoint> waypoints = course.getWaypoints();
Waypoint firstWaypointOfRace = course.getFirstWaypoint();
Waypoint lastWaypointOfRace = course.getLastWaypoint();
for (Competitor c : raceDefinition.getCompetitors()) {
xteCache.put(c, new LimitedLinkedHashMap<GPSFix, Map<Waypoint, List<Distance>>>(25));
distanceCache.put(c, new LimitedLinkedHashMap<GPSFix, Map<Waypoint, List<Distance>>>(25));
xteCandidates.put(c, new HashMap<Waypoint, Map<List<GPSFix>, Candidate>>());
distanceCandidates.put(c, new HashMap<Waypoint, Map<GPSFix, Candidate>>());
}
for (Waypoint w : waypoints) {
processNewWaypoint(w, firstWaypointOfRace, lastWaypointOfRace);
}
}
private class LimitedLinkedHashMap<K, V> extends LinkedHashMap<K, V> {
@@ -109,9 +102,11 @@ public class CandidateFinderImpl implements CandidateFinder {
Set<GPSFix> fixes = getAllFixes(c);
distanceCache.get(c).clear();
xteCache.get(c).clear();
for (Waypoint w : race.getRace().getCourse().getWaypoints()) {
xteCandidates.get(c).get(w).clear();
distanceCandidates.get(c).get(w).clear();
synchronized (xteCandidates) {
xteCandidates.get(c).clear();
}
synchronized (distanceCandidates) {
distanceCandidates.get(c).clear();
}
return getCandidateDeltas(c, fixes);
}
@@ -192,11 +187,10 @@ public class CandidateFinderImpl implements CandidateFinder {
List<Candidate> badCans = new ArrayList<>();
List<Candidate> newCans = new ArrayList<>();
for (Waypoint w : changedWaypoints) {
Map<List<GPSFix>, Candidate> xteCans = xteCandidates.get(c).get(w);
Map<List<GPSFix>, Candidate> xteCans = getXteCandidates(c, w);
badCans.addAll(xteCans.values());
xteCans.clear();
;
Map<GPSFix, Candidate> distanceCans = distanceCandidates.get(c).get(w);
Map<GPSFix, Candidate> distanceCans = getDistanceCandidates(c, w);
badCans.addAll(distanceCans.values());
distanceCans.clear();
}
@@ -211,10 +205,6 @@ public class CandidateFinderImpl implements CandidateFinder {
@Override
public Map<Competitor, Util.Pair<List<Candidate>, List<Candidate>>> updateWaypoints(
Iterable<Waypoint> addedWaypoints, Iterable<Waypoint> removedWaypoints, Integer smallestIndex) {
Course course = race.getRace().getCourse();
for (Waypoint w : addedWaypoints) {
processNewWaypoint(w, course.getFirstWaypoint(), course.getLastWaypoint());
}
Map<Competitor, List<Candidate>> removedWaypointCandidates = removeWaypoints(removedWaypoints);
Map<Competitor, Util.Pair<List<Candidate>, List<Candidate>>> newAndUpdatedCandidates = invalidateAfterCourseChange(smallestIndex);
for (Entry<Competitor, List<Candidate>> entry : removedWaypointCandidates.entrySet()) {
@@ -234,18 +224,44 @@ public class CandidateFinderImpl implements CandidateFinder {
for (Entry<Competitor, List<Candidate>> entry : result.entrySet()) {
Competitor c = entry.getKey();
List<Candidate> badCans = entry.getValue();
Map<Waypoint, Map<List<GPSFix>, Candidate>> xteCans = xteCandidates.get(c);
badCans.addAll(xteCans.get(w).values());
xteCans.remove(w);
Map<Waypoint, Map<GPSFix, Candidate>> distanceCans = distanceCandidates.get(c);
badCans.addAll(distanceCans.get(w).values());
distanceCans.remove(w);
badCans.addAll(getXteCandidates(c, w).values());
synchronized (xteCandidates) {
xteCandidates.get(c).remove(w);
}
badCans.addAll(getDistanceCandidates(c, w).values());
synchronized (distanceCandidates) {
distanceCandidates.get(c).remove(w);
}
}
}
return result;
}
private Map<GPSFix, Candidate> getDistanceCandidates(Competitor c, Waypoint w) {
synchronized (distanceCandidates) {
Map<GPSFix, Candidate> result = distanceCandidates.get(c).get(w);
if (result == null) {
result = new HashMap<>();
distanceCandidates.get(c).put(w, result);
}
return result;
}
}
private void processNewWaypoint(Waypoint w, Waypoint firstWaypoint, Waypoint lastWaypoint) {
private Map<List<GPSFix>, Candidate> getXteCandidates(Competitor c, Waypoint w) {
synchronized (xteCandidates) {
Map<List<GPSFix>, Candidate> result = xteCandidates.get(c).get(w);
if (result == null) {
result = new HashMap<>();
xteCandidates.get(c).put(w, result);
}
return result;
}
}
private PassingInstruction determinePassingInstructions(Waypoint w) {
final Waypoint firstWaypoint = race.getRace().getCourse().getFirstWaypoint();
final Waypoint lastWaypoint = race.getRace().getCourse().getLastWaypoint();
PassingInstruction instruction = w.getPassingInstructions();
if ((w.equals(firstWaypoint) || w.equals(lastWaypoint)) && instruction == PassingInstruction.Gate) {
instruction = PassingInstruction.Line;
@@ -269,11 +285,7 @@ public class CandidateFinderImpl implements CandidateFinder {
}
}
}
passingInstructions.put(w, instruction);
for (Competitor c : race.getRace().getCompetitors()) {
xteCandidates.get(c).put(w, new HashMap<List<GPSFix>, Candidate>());
distanceCandidates.get(c).put(w, new HashMap<GPSFix, Candidate>());
}
return instruction;
}
private Set<GPSFix> getAllFixes(Competitor c) {
@@ -378,23 +390,23 @@ public class CandidateFinderImpl implements CandidateFinder {
}
portMark = false;
}
oldCan = distanceCandidates.get(c).get(w).get(fix);
oldCan = getDistanceCandidates(c, w).get(fix);
if (oldCan != null) {
wasCan = true;
}
if (!wasCan && isCan) {
Candidate newCan = new CandidateImpl(race.getRace().getCourse().getIndexOfWaypoint(w) + 1, t,
probability, w);
distanceCandidates.get(c).get(w).put(fix, newCan);
getDistanceCandidates(c, w).put(fix, newCan);
result.getA().add(newCan);
logger.finest("Added distance" + newCan.toString() + "for " + c);
} else if (wasCan && !isCan) {
distanceCandidates.get(c).get(w).remove(fix);
getDistanceCandidates(c, w).remove(fix);
result.getB().add(oldCan);
} else if (wasCan && isCan && oldCan.getProbability() != probability) {
Candidate newCan = new CandidateImpl(race.getRace().getCourse().getIndexOfWaypoint(w) + 1, t,
probability, w);
distanceCandidates.get(c).get(w).put(fix, newCan);
getDistanceCandidates(c, w).put(fix, newCan);
result.getA().add(newCan);
logger.finest("Added distance" + newCan.toString() + "for " + c);
result.getB().add(oldCan);
@@ -412,7 +424,7 @@ public class CandidateFinderImpl implements CandidateFinder {
if (result == null) {
// Else calculate distances and put them into the cache
result = new LinkedHashMap<>();
for (Waypoint w : passingInstructions.keySet()) {
for (Waypoint w : getWaypoints()) {
List<Distance> distances = calculateDistance(fix.getPosition(), w, fix.getTimePoint());
result.put(w, distances);
}
@@ -459,7 +471,7 @@ public class CandidateFinderImpl implements CandidateFinder {
for (Waypoint w : waypoints) {
List<List<GPSFix>> oldCandidates = new ArrayList<>();
Map<List<GPSFix>, Candidate> newCandidates = new HashMap<List<GPSFix>, Candidate>();
Map<List<GPSFix>, Candidate> waypointCandidates = xteCandidates.get(c).get(w);
Map<List<GPSFix>, Candidate> waypointCandidates = getXteCandidates(c, w);
for (List<GPSFix> fixPair : waypointCandidates.keySet()) {
if (fixPair.contains(fix)) {
oldCandidates.add(fixPair);
@@ -547,7 +559,7 @@ public class CandidateFinderImpl implements CandidateFinder {
result = new HashMap<>();
Position p = fix.getPosition();
TimePoint t = fix.getTimePoint();
for (Waypoint w : passingInstructions.keySet()) {
for (Waypoint w : getWaypoints()) {
List<Distance> distances = new ArrayList<>();
result.put(w, distances);
for (Util.Pair<Position, Bearing> crossingInfo : getCrossingInformation(w, t)) {
@@ -561,6 +573,10 @@ public class CandidateFinderImpl implements CandidateFinder {
return result;
}
private Iterable<Waypoint> getWaypoints() {
return race.getRace().getCourse().getWaypoints();
}
/**
* Calculates the cross-track error of each fix to the position and crossing bearing of each waypoint. Gates have
* two of these and lines always go from the port mark to the starboard mark.
@@ -597,7 +613,7 @@ public class CandidateFinderImpl implements CandidateFinder {
*/
private boolean isOnCorrectSideOfWaypoint(Waypoint w, Position p, TimePoint t, boolean portMark) {
boolean result = true;
PassingInstruction instruction = passingInstructions.get(w);
PassingInstruction instruction = getPassingInstructions(w);
if (instruction == PassingInstruction.Line) {
List<Position> pos = new ArrayList<>();
for (Mark m : w.getMarks()) {
@@ -641,7 +657,7 @@ public class CandidateFinderImpl implements CandidateFinder {
*/
private boolean passesInTheRightDirection(Waypoint w, double xte1, double xte2, boolean portMark) {
boolean result = true;
PassingInstruction instruction = passingInstructions.get(w);
PassingInstruction instruction = getPassingInstructions(w);
if (instruction == PassingInstruction.Port || instruction == PassingInstruction.Line
|| (instruction == PassingInstruction.Gate && portMark)) {
result = xte1 > xte2 ? true : false;
@@ -689,7 +705,7 @@ public class CandidateFinderImpl implements CandidateFinder {
*/
private List<Distance> calculateDistance(Position p, Waypoint w, TimePoint t) {
List<Distance> distances = new ArrayList<>();
PassingInstruction instruction = passingInstructions.get(w);
PassingInstruction instruction = getPassingInstructions(w);
boolean singleMark = false;
switch (instruction) {
case Port:
@@ -743,13 +759,24 @@ public class CandidateFinderImpl implements CandidateFinder {
return distances;
}
private PassingInstruction getPassingInstructions(Waypoint w) {
final PassingInstruction result;
if (passingInstructions.containsKey(w)) {
result = passingInstructions.get(w);
} else {
result = determinePassingInstructions(w);
passingInstructions.put(w, result);
}
return result;
}
/**
* @return all possible ways to pass a waypoint, described as a position and a bearing. The line out of those two
* must be crossed.
*/
private Iterable<Util.Pair<Position, Bearing>> getCrossingInformation(Waypoint w, TimePoint t) {
List<Util.Pair<Position, Bearing>> result = new ArrayList<>();
PassingInstruction instruction = passingInstructions.get(w);
PassingInstruction instruction = getPassingInstructions(w);
if (instruction == PassingInstruction.Line) {
Util.Pair<Mark, Mark> marks = getPortAndStarboardMarks(t, w);
Position portPosition = null;