started to introduce a flag on TrackedRace identifying whether the first leg is known to be upwind

This commit is contained in:
Axel Uhl committed 2011-12-20 16:10:56 +01:00
1 parent c8f8262737
commit 82077866ce
19 files changed
+101 -30

No files matched your search

@@ -22,4 +22,17 @@ public interface BoatClass extends Named {
double getMinimumAngleBetweenDifferentTacksDownwind();
double getMinimumAngleBetweenDifferentTacksUpwind();
/**
* Most olympic boat classes start their race with an upwind leg. Some other classes such
* as the Extreme Sailing Series / Extreme40 do not necessarily start with an upwind leg.
* Knowing this is relevant for the wind estimation fallback strategy. If the first leg of
* a boat class doesn't have to be an upwind leg it's not permissible to estimate the wind
* based on the course layout.<p>
*
* The result of calling this method suggests a good default for this boat class. It is
* <em>not</em> an authoritative, prescriptive value. Races with this boat class may still
* start with a non-upwind leg even though this method returns <code>true</code>.
*/
boolean typicallyStartsUpwind();
}
@@ -20,5 +20,5 @@ public interface DomainFactory {
MarkPassing createMarkPassing(TimePoint timePoint, Waypoint waypoint, Competitor competitor);
BoatClass getOrCreateBoatClass(String name);
BoatClass getOrCreateBoatClass(String name, boolean typicallyStartsUpwind);
}
@@ -19,8 +19,11 @@ public class BoatClassImpl extends NamedImpl implements BoatClass {
private final long approximateManeuverDurationInMilliseconds;
public BoatClassImpl(String name) {
private final boolean alwaysStartsUpwind;
public BoatClassImpl(String name, boolean alwaysStartsUpwind) {
super(name);
this.alwaysStartsUpwind = alwaysStartsUpwind;
approximateManeuverDurationInMilliseconds = 8000; // as discussed with Dennis Gehrlein
}
@@ -49,4 +52,9 @@ public class BoatClassImpl extends NamedImpl implements BoatClass {
return MAXIMUM_DISTANCE_FOR_COURSE_APPROXIMATION;
}
@Override
public boolean typicallyStartsUpwind() {
return alwaysStartsUpwind;
}
}
@@ -76,11 +76,11 @@ public class DomainFactoryImpl implements DomainFactory {
}
@Override
public BoatClass getOrCreateBoatClass(String name) {
public BoatClass getOrCreateBoatClass(String name, boolean typicallyStartsUpwind) {
synchronized (boatClassCache) {
BoatClass result = boatClassCache.get(name);
if (result == null) {
result = new BoatClassImpl(name);
result = new BoatClassImpl(name, typicallyStartsUpwind);
boatClassCache.put(name, result);
}
return result;
@@ -45,4 +45,10 @@ public interface DynamicTrackedRace extends TrackedRace {
void setMillisecondsOverWhichToAverageWind(long millisecondsOverWhichToAverageWind);
DynamicTrackedEvent getTrackedEvent();
/**
* If and only if <code>raceIsKnownToStartUpwind</code> is <code>true</code>, this tracked race is allowed to use
* the start leg's direction as a fallback for estimating the wind direction.
*/
void setRaceIsKnownToStartUpwind(boolean raceIsKnownToStartUpwind);
}
@@ -14,6 +14,7 @@ import com.sap.sailing.domain.base.Tack;
import com.sap.sailing.domain.base.TimePoint;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.DouglasPeucker;
import com.sap.sailing.domain.tracking.TrackedLeg.LegType;
/**
* Live tracking data of a single race. The race follows a defined {@link Course} with a sequence of {@link Leg}s. The
@@ -221,4 +222,12 @@ public interface TrackedRace {
* this race between <code>from</code> and <code>to</code>.
*/
List<Maneuver> getManeuvers(Competitor competitor, TimePoint from, TimePoint to) throws NoWindException;
/**
* @return <code>true</code> if this race is known to start with an {@link LegType#UPWIND upwind} leg.
* If this is the case, the wind estimation may default to using the first leg's direction at race start
* time as the direction the wind comes from.
*/
boolean raceIsKnownToStartUpwind();
}
@@ -35,9 +35,12 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
private Set<RaceChangeListener<Competitor>> listeners;
private boolean raceIsKnownToStartUpwind;
public DynamicTrackedRaceImpl(TrackedEvent trackedEvent, RaceDefinition race,
WindStore windStore, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed) {
super(trackedEvent, race, windStore, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed);
this.raceIsKnownToStartUpwind = race.getBoatClass().typicallyStartsUpwind();
for (Competitor competitor : getRace().getCompetitors()) {
DynamicGPSFixTrack<Competitor, GPSFixMoving> track = getTrack(competitor);
track.addListener(this);
@@ -281,4 +284,14 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
return (DynamicTrackedEvent) super.getTrackedEvent();
}
@Override
public void setRaceIsKnownToStartUpwind(boolean raceIsKnownToStartUpwind) {
this.raceIsKnownToStartUpwind = raceIsKnownToStartUpwind;
}
@Override
public boolean raceIsKnownToStartUpwind() {
return raceIsKnownToStartUpwind;
}
}
@@ -112,7 +112,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
private boolean warnedOfNoWindFromSelectedSource;
private boolean warnedOfUsingLegDirectionAsWindEstimation;
public TrackedRaceImpl(TrackedEvent trackedEvent, RaceDefinition race, WindStore windStore,
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed) {
super();
@@ -419,13 +419,14 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
}
}
}
if (result == null) {
if (result == null && raceIsKnownToStartUpwind()) {
if (!warnedOfUsingLegDirectionAsWindEstimation) {
logger.warning("Found no other wind settings either; using starting leg direction as guess for wind direction. Force assumed as 1 knot."+
" Future warnings of this type will be suppressed for this race.");
logger.warning("Found no other wind settings either; using starting leg direction at start time as guess for wind direction. "
+ "Force assumed as 1 knot. Future warnings of this type will be suppressed for this race.");
warnedOfUsingLegDirectionAsWindEstimation = true;
}
result = getDirectionFromStartToNextMark(at);
TimePoint starttime = getStart();
result = getDirectionFromStartToNextMark(starttime == null ? at : starttime);
}
}
return result;