Merge remote-tracking branch 'origin/master' into ribdashboard

This commit is contained in:
Alexander Ries committed 2015-01-29 10:43:22 +01:00
commit 5bbb80891e
18 files changed
+1087 -97

No files matched your search

@@ -17,14 +17,12 @@ import com.sap.sse.common.TimePoint;
public class TracTracStartTimeUpdateHandler extends UpdateHandler implements StartTimeChangedListener {
private static final String ACTION = "update_race_start_time";
private final TracTracStartTimeResetHandler resetHandler;
private final static Logger logger = Logger.getLogger(TracTracStartTimeUpdateHandler.class.getName());
private final static String FIELD_RACE_START_TIME = "race_start_time";
public TracTracStartTimeUpdateHandler(URI updateURI, String tracTracUsername, String tracTracPassword, Serializable tracTracEventId, Serializable raceId) {
super(updateURI, ACTION, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
resetHandler = new TracTracStartTimeResetHandler(updateURI, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
}
@Override
@@ -34,8 +32,20 @@ public class TracTracStartTimeUpdateHandler extends UpdateHandler implements Sta
}
if (newStartTime == null) {
// reset start time with TracTrac
resetHandler.startTimeChanged(null);
/*
* Do not reset start time based on request by Jorge from TracTrac:
*
* """
* We have detected that when you want to update the race start time your
* system sends before a message to reset the race start time. When your
* system invokes the first service our system changes the race start time
* to null and this value causes some secondary effects in our side.
*
* Can you just send the update_race_start_time without the
* reset_race_start_time? The reset_race_start_time service has to be used
* if you want to set the value to null.
* """
*/
} else {
HashMap<String, String> additionalParameters = new HashMap<String, String>();
additionalParameters.put(FIELD_RACE_START_TIME, String.valueOf(newStartTime.asMillis()));
@@ -674,7 +674,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
WindTrackInfoDTO windTrackInfoDTO = windInfo.windTrackInfoByWindSource.get(windSource);
switch (windSource.getType()) {
case EXPEDITION:
// we filter out measured wind sources with a very little confidence
// we filter out measured wind sources with vary low confidence
if (windTrackInfoDTO.minWindConfidence > 0.0001) {
windSourcesToShow.add(new com.sap.sse.common.Util.Pair<WindSource, WindTrackInfoDTO>(windSource, windTrackInfoDTO));
}
@@ -82,7 +82,7 @@ public class TestWindEstimationFromManeuversOnAFew505Races extends OnlineTracTra
CreateModelException, NotEnoughDataHasBeenAddedException {
setUp("OBMR 2012", "event_20121031_OBMR-OBMR_2012_VR_Fr_Fleet_1_2");
Wind average = getManeuverBasedAverageWind();
assertEquals(222, average.getFrom().getDegrees(), 5.0); // wind in this race was from 075deg on average
assertEquals(222, average.getFrom().getDegrees(), 5.0);
}
@Test
@@ -91,7 +91,7 @@ public class TestWindEstimationFromManeuversOnAFew505Races extends OnlineTracTra
CreateModelException, NotEnoughDataHasBeenAddedException {
setUp("event_20110609_KielerWoch-505_Race_2");
Wind average = getManeuverBasedAverageWind();
assertEquals(235, average.getFrom().getDegrees(), 5.0); // wind in this race was from 075deg on average
assertEquals(235, average.getFrom().getDegrees(), 5.0);
}
@Test
@@ -100,7 +100,7 @@ public class TestWindEstimationFromManeuversOnAFew505Races extends OnlineTracTra
CreateModelException, NotEnoughDataHasBeenAddedException {
setUp("event_20110609_KielerWoch-505_Race_3");
Wind average = getManeuverBasedAverageWind();
assertEquals(245, average.getFrom().getDegrees(), 5.0); // wind in this race was from 075deg on average
assertEquals(245, average.getFrom().getDegrees(), 5.0);
}
@Test
@@ -109,7 +109,7 @@ public class TestWindEstimationFromManeuversOnAFew505Races extends OnlineTracTra
CreateModelException, NotEnoughDataHasBeenAddedException {
setUp("event_20110609_KielerWoch-505_race_4");
Wind average = getManeuverBasedAverageWind();
assertEquals(275, average.getFrom().getDegrees(), 5.0); // wind in this race was from 075deg on average
assertEquals(270, average.getFrom().getDegrees(), 5.0);
}
@Test
@@ -139,8 +139,11 @@ public class TestWindEstimationFromManeuversOnAFew505Races extends OnlineTracTra
.sorted((c1, c2) -> (int) -Math.signum(getAverageLikelihood(c1, ManeuverType.TACK)
- getAverageLikelihood(c2, ManeuverType.TACK))).collect(Collectors.toList());
// expecting a wind direction that is from around 245deg, +/- 10deg
assertEquals(245., windTrack.getWeightedAverageMiddleManeuverCOGDeg(clustersSortedByAverageTackLikelihood.get(0), ManeuverType.TACK).getDegrees(), 10.);
assertEquals(245., windTrack.getWeightedAverageMiddleManeuverCOGDeg(clustersSortedByAverageTackLikelihood.get(1), ManeuverType.TACK).getDegrees(), 10.);
assertEquals(
245., windTrack.getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(
clustersSortedByAverageTackLikelihood.get(0), ManeuverType.TACK).getA().getDegrees(), 10.);
assertEquals(245., windTrack.getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(
clustersSortedByAverageTackLikelihood.get(1), ManeuverType.TACK).getA().getDegrees(), 10.);
}
private double getAverageLikelihood(
@@ -70,26 +70,59 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
* for another cluster to be a cluster's opposite tack cluster is determined by first computing the
* {@link #getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(Cluster, double, Bearing) angular
* distance}. For each so many degrees of distance as specified by this constant, the likelihood of the cluster to be the
* opposite tack cluster is halved.
* opposite tack cluster is halved. This constant can also be used to assign likelihoods for other cluster types
* based on their distance from an expected configuration of maneuver angle and middle COG.
*/
private static final double ANGULAR_DISTANCE_FOR_HALF_CONFIDENCE_FOR_OPPOSITE_TACK_CLUSTER_DEG = 20.;
/**
* When one or two jibe clusters have been found whose
* {@link #getLikelihoodOfBeingJibeCluster(Speed, Stream, BoatClass, Set) likelihood of being a jibe cluster} is 100%,
* this is the boost factor by which the base likelihood for the tack cluster candidate will be increased (up to a
* maximum of 1.0).
*/
private static final double BOOST_FACTOR_FOR_FULL_JIBE_CLUSTER_LIKELIHOOD = 0.2;
/**
* When one or two head-up / bear-away clusters on the two tacks adjacent to the middle upwind COG have been found
* whose {@link #getLikelihoodOfClusterBasedOnDistanceFromExpected(double, Bearing, Cluster) likelihood of being
* such a cluster} is 100%, this is the boost factor by which the base likelihood for the tack cluster candidate
* will be increased (up to a maximum of 1.0).
*/
private static final double BOOST_FACTOR_FOR_FULL_HEAD_UP_BEAR_AWAY_CLUSTER_LIKELIHOOD = 0.1;
/**
* When looking for the head-up/bear-away clusters, which average maneuver angle should be expected? This is a bit
* fuzzy because in some cases the head-up and bear-away maneuvers may be grouped into one cluster, resulting in an
* average maneuver angle that is close to zero whereas in other cases they may form two clusters, one with positive
* and the other with negative maneuver angles of somewhere between 10-20deg, typically.
*/
private static final double EXPECTED_AVERAGE_HEAD_UP_AND_BEAR_AWAY_MANEUVER_ANGLE_DEG = 10.;
/**
* We're trying to find the jibe cluster based on a candidate for the tack cluster. This constant tells how many degrees
* the jibe cluster may be off from the reversed tack cluster's centroid in order to be accepted as jibe cluster candidate.
*/
private static final double THRESHOLD_JIBE_CLUSTER_DIFFERENCE_DEGREES = 20;
/**
* For judging the likelihood of a cluster being a speed cluster, the speed ratio of the tack cluster candidate and
* the jibe cluster candidate is computed and compared to what the polar service predicts. The basic likelihood of the
* jibe cluster candidate (based on the maneuver angles relative to their speeds) is boosted by this factor for a perfect
* speed ratio match.
*/
private static final double BOOST_FACTOR_FOR_JIBE_TACK_SPEED_RATIO_LIKELIHOOD = 0;
private final PolarDataService polarService;
private final TrackedRace trackedRace;
/**
* Caches the {@link #getWeightedAverageMiddleManeuverCOGDeg(Cluster, ManeuverType)} results because these values are required several times to
* Caches the {@link #getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(Cluster, ManeuverType)} results because these values are required several times to
* determine the likelihood with which a cluster is a cluster of tacks or a cluster of jibes. Note that the un-weighted averages can simply be obtained
* by asking the cluster for its {@link Cluster#getCentroid() centroid}.
*/
private final Map<Pair<Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble>, ManeuverType>, Bearing>
private final Map<Pair<Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble>, ManeuverType>, Pair<Bearing, Double>>
weightedAverageMiddleCOGForManeuverType;
/**
@@ -308,17 +341,16 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
* There are usually no other maneuvers with similar middle COG because boats can't sail straight against the wind.
* <p>
*
* We evaluate each cluster's likelihood of being the tack cluster by for each of its maneuvers adding up the
* likelihood of that maneuver being a tack, solely based on its maneuver angle, as judged by the polar service. If
* a cluster exists that has approximately the opposite average middle COG (the jibe cluster candidate), the
* likelihoods for its maneuvers being a jibe are added. (TODO adding is statistically not adequate here; however,
* multiplying hundreds if not thousands of probability values would easily lead to a double value going to 0.0
* quickly. But is adding adequate to estimate the cluster having the maximum likelihood of being the tack cluster?
* We'd only need a monotonous function.) Finally, the resulting likelihood is multiplied by how likely the speed
* ratio between the tack and jibe cluster candidates is, based on the polar diagram. For this task, the cluster's
* maneuvers' average speed (weighted by each maneuver's likelihood of being a tack) is divided by that of the jibe
* cluster's maneuvers' average speed (weighted by each maneuver's likelihood of being a jibe) and assigned a
* likelihood by the polar service.
* We evaluate each cluster's likelihood of being the tack cluster by computing the average across all its maneuvers
* for that maneuver being a tack, solely based on its speed and maneuver angle, as
* {@link PolarDataService#getManeuverLikelihoodAndTwsTwa(BoatClass, Speed, double, ManeuverType) judged by the
* polar service}. If a cluster exists that has approximately the opposite average middle COG (the jibe cluster
* candidate), the {@link #getLikelihoodOfBeingJibeCluster(Speed, Stream, BoatClass, Set) likelihood for its maneuvers
* being jibes} are determined and may result in a "boost" for the basic probability of up to 20%. Finally, the
* resulting likelihood is multiplied by how likely the speed ratio between the tack and jibe cluster candidates is,
* based on the polar diagram. For this task, the cluster's maneuvers' average speed (weighted by each maneuver's
* likelihood of being a tack) is divided by that of the jibe cluster's maneuvers' average speed (weighted by each
* maneuver's likelihood of being a jibe) and assigned a likelihood by the polar service.
* <p>
*
* The cluster that has the highest likelihood of being the tack cluster is selected. The confidence of the choice
@@ -361,21 +393,22 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
final Map<Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble>, Double>
likelihoodOfBeingTackCluster = new HashMap<>();
for (Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble> c : clusters) {
likelihoodOfBeingTackCluster.put(c, getLikelihoodOfBeingTackCluster(c, clusters));
likelihoodOfBeingTackCluster.put(c,
getLikelihoodOfBeingTackCluster(c, clusters));
}
// The first two clusters in the resulting list are now our best bet for the tack clusters, assuming that the likelihood for the third element
// in the list is already much lower. Should there be a significant degradation of likelihood between the first and the second cluster, we
// will only use the first, particularly if the average middle COGs of the first two clusters differ significantly.
final List<Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble>> tackClusters =
clusters.stream()
.sorted((c1, c2) -> (int) -Math.signum(likelihoodOfBeingTackCluster.get(c1) // TODO cache result of getLikelihoodOfBeingTackCluster
.sorted((c1, c2) -> (int) -Math.signum(likelihoodOfBeingTackCluster.get(c1)
- likelihoodOfBeingTackCluster.get(c2))).limit(2).collect(Collectors.toList());
addWindFixes(tackClusters.stream(), ManeuverType.TACK);
Bearing estimatedJibeMiddleCOG =
tackClusters.isEmpty() ? null
: (tackClusters.size() == 1 ? getWeightedAverageMiddleManeuverCOGDeg(tackClusters.get(0), ManeuverType.TACK)
: new ScalableBearing(getWeightedAverageMiddleManeuverCOGDeg(tackClusters.get(0), ManeuverType.TACK)).add(
new ScalableBearing(getWeightedAverageMiddleManeuverCOGDeg(tackClusters.get(1), ManeuverType.TACK))).
: (tackClusters.size() == 1 ? getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(tackClusters.get(0), ManeuverType.TACK).getA()
: new ScalableBearing(getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(tackClusters.get(0), ManeuverType.TACK).getA()).add(
new ScalableBearing(getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(tackClusters.get(1), ManeuverType.TACK).getA())).
divide(2)).reverse();
final List<Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble>> jibeClusters =
getJibeClusters(estimatedJibeMiddleCOG, clusters).collect(Collectors.toList());
@@ -402,12 +435,14 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
/**
* Determines the likelihood of <code>cluster</code> being a cluster of tacks, based on the average likelihood of
* the maneuver classifications in <code>cluster</code> to be maneuvers of type {@link ManeuverType#TACK TACK}, in
* turn based on what the {@link #polarService} thinks that this likelihood is and based on whether we find other
* <code>clusters</code> that support this hypothesis. The likelihood is positively affected
* turn based on what the {@link #polarService} thinks that this
* {@link PolarDataService#getManeuverLikelihoodAndTwsTwa(BoatClass, Speed, double, ManeuverType) likelihood} is and
* based on whether we find other <code>clusters</code> that support this hypothesis. The likelihood is positively
* affected
*
* <ul>
* <li>if a second cluster with similar average middle COG and a similar average maneuver angle with opposite sign
* is found that also has a high average likelihood of the maneuvers contained being tacks</li>
* is found that also has a high average likelihood of its maneuvers being tacks</li>
* <li>if other clusters are found that for the average true wind speed estimated from the maneuvers in
* <code>cluster</code> seem like head-up/bear-away clusters on port/starboard tack with an average middle COG that
* is half the tacking angle for that wind speed away from the tack cluster's average middle COG</li>
@@ -423,7 +458,14 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
* apart from the tacks even if they have similar maneuver angles.</li>
* </ul>
*
* @return a likelihood between 0..1 (inclusive)
* @return a likelihood between 0..1 (inclusive), obtained by multiplying the based likelihood of the
* <code>cluster</code> to hold tacks, based on the maneuver angles and their speed and how likely the
* {@link #polarService} considers this to be a tack; with boost factors added for the likelihood of having
* found a good jibe cluster and boost factors for the likelihoods of having found starboard and port tack
* clusters that hold the head-up/bear-away maneuvers. These boosts can add as much as
* {@link #BOOST_FACTOR_FOR_FULL_JIBE_CLUSTER_LIKELIHOOD} + 2*
* {@link #BOOST_FACTOR_FOR_FULL_HEAD_UP_BEAR_AWAY_CLUSTER_LIKELIHOOD} of the original value but will be
* capped at the maximum likelihood of 1.0.
*
* @see ManeuverClassification#getLikelihoodAndTWSBasedOnSpeedAndAngle(ManeuverType)
* @see PolarDataService#getManeuverLikelihoodAndTwsTwa(BoatClass, Speed, double, ManeuverType)
@@ -433,8 +475,7 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
Set<Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble>> clusters) {
// start with the average of all of the cluster's maneuvers' likelihood to be a tack
double averageTackLikelihood = getAverageLikelihoodOfBeingManeuver(ManeuverType.TACK, cluster.stream());
final Bearing approximateMiddleCOG = getWeightedAverageMiddleManeuverCOGDeg(cluster, ManeuverType.TACK);
final Bearing approximateMiddleCOGForJibes = approximateMiddleCOG.reverse();
final Bearing approximateMiddleCOG = getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(cluster, ManeuverType.TACK).getA();
// search for the opposite tack cluster by finding the one that has the smallest angular distance to the expected
// middle COG (same as for the candidate cluster) and expected maneuver angle (the cluster's average maneuver angle with inverted sign)
final Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble> oppositeTackCluster =
@@ -442,11 +483,29 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(a, -cluster.getCentroid().getB(), approximateMiddleCOG)-
getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(b, -cluster.getCentroid().getB(), approximateMiddleCOG))).
orElse(null);
final double likelihoodOfOppositeCluster = getLikelihoodOfOppositeTackCluster(-cluster.getCentroid().getB(), approximateMiddleCOG, oppositeTackCluster);
// TODO search for head-up/bear-away cluster(s) to port and to starboard of cluster's weighted middle COG
// if the opposite tack cluster is empty, it's pretty unlikely that it's a tack cluster; assign a low default probability of 10%
final double likelihoodOfOppositeCluster = oppositeTackCluster.isEmpty() ? 0.1 :
getLikelihoodOfClusterBasedOnDistanceFromExpected(-cluster.getCentroid().getB(), approximateMiddleCOG, oppositeTackCluster);
// compute weighted averages across the current candidate cluster and its supposed opposite tack cluster where the latter
// is weighted by the likelihoodOfOppositeCluster whereas the candidate cluster is always weighed as 1.0 for this purpose
final double averageTackingAngleDeg = (Math.abs(getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(cluster, ManeuverType.TACK).getB()) +
likelihoodOfOppositeCluster*Math.abs(getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(oppositeTackCluster, ManeuverType.TACK).getB()))
/ (1+likelihoodOfOppositeCluster);
final Bearing averageUpwindCOG = new ScalableBearing(
getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(cluster, ManeuverType.TACK).getA()).add(new ScalableBearing(
getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(oppositeTackCluster, ManeuverType.TACK).getA()).
multiply(likelihoodOfOppositeCluster)).divide(1+likelihoodOfOppositeCluster);
// Now search for head-up/bear-away cluster(s) to port and to starboard of cluster's weighted middle COG
final Bearing expectedUpwindStarboardTackCOG = averageUpwindCOG.add(new DegreeBearingImpl(-averageTackingAngleDeg/2.));
double starboardHeadUpBearAwayClusterLikelihood = getLikelihoodOfBestFittingHeadUpBearAwayCluster(
clusters.stream().filter(c->c!=cluster), expectedUpwindStarboardTackCOG);
final Bearing expectedUpwindPortTackCOG = averageUpwindCOG.add(new DegreeBearingImpl(averageTackingAngleDeg/2.));
double portHeadUpBearAwayClusterLikelihood = getLikelihoodOfBestFittingHeadUpBearAwayCluster(
clusters.stream().filter(c->c!=cluster), expectedUpwindPortTackCOG);
// under the assumption that cluster holds tacks, find the clusters that then most likely hold the jibes
final Bearing approximateMiddleCOGForJibes = averageUpwindCOG.reverse();
Stream<Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble>> jibeClusters =
getJibeClusters(approximateMiddleCOGForJibes, clusters);
// increase cluster's score if "good" jibe clusters are found; quality is defined by how well the angle matches and how well the speed ratio fits
@@ -455,12 +514,14 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
if (tackClusterWeightedAverageSpeed != null) {
// find out how likely the speed ratio is between the candidate tack cluster and the corresponding
// hypothetical jibe clusters
double tackJibeLikelihoodBasedOnSpeedRatioAndAverageManeuverAngle = getLikelihoodOfBeingJibeCluster(
double jibeClusterLikelihood = getLikelihoodOfBeingJibeCluster(
tackClusterWeightedAverageSpeed, jibeClusters.map((jc) -> jc.stream()).reduce(Stream::concat)
.orElse(Stream.empty()), getBoatClass());
.orElse(Stream.empty()), getBoatClass(), clusters);
// Likely jibe clusters may raise the general likelihood by up to 20% of the value so far, but not to over 1.0
result = Math.min(1.0, averageTackLikelihood * likelihoodOfOppositeCluster *
(1.0 + 0.2 * tackJibeLikelihoodBasedOnSpeedRatioAndAverageManeuverAngle));
(1.0 + BOOST_FACTOR_FOR_FULL_JIBE_CLUSTER_LIKELIHOOD * jibeClusterLikelihood +
BOOST_FACTOR_FOR_FULL_HEAD_UP_BEAR_AWAY_CLUSTER_LIKELIHOOD * starboardHeadUpBearAwayClusterLikelihood +
BOOST_FACTOR_FOR_FULL_HEAD_UP_BEAR_AWAY_CLUSTER_LIKELIHOOD * portHeadUpBearAwayClusterLikelihood));
} else {
result = .1; // no elements in the cluster, therefore no average speed; low propability that this would be a tack cluster
}
@@ -468,28 +529,86 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
}
/**
* Tells how likely it is that the two clusters are opposite tack clusters. This is determined by looking at the
* {@link #getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(Cluster, double, Bearing) angular distance}
* between the two clusters regarding their middle COG and their average maneuver angles. The likelihood decreases exponentially
* with increasing angle differences. It is 1.0 for an exact match and reaches 0.5 for an angular distance of 20deg.
* Determines a likelihood for <code>cluster</code> being a head-up/bear-away cluster for the
* <code>expectedMiddleCOG</code>.
*
* @return a value between 0..1 (exclusive)
* @see #getLikelihoodOfClusterBasedOnDistanceFromExpected(double, Bearing, Cluster)
*/
private double getLikelihoodOfOppositeTackCluster(
private double getLikelihoodOfBestFittingHeadUpBearAwayCluster(
Stream<Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble>> clusters,
final Bearing expectedAverageMiddleCOG) {
final Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble> starboardTackHeadUpAndBearAwayCluster =
clusters.max((a, b)->(int) Math.signum(
getLikelihoodOfClusterBasedOnDistanceFromExpected(EXPECTED_AVERAGE_HEAD_UP_AND_BEAR_AWAY_MANEUVER_ANGLE_DEG, expectedAverageMiddleCOG, a)-
getLikelihoodOfClusterBasedOnDistanceFromExpected(EXPECTED_AVERAGE_HEAD_UP_AND_BEAR_AWAY_MANEUVER_ANGLE_DEG, expectedAverageMiddleCOG, b))).
orElse(null);
double starboardHeadUpBearAwayClusterLikelihood = starboardTackHeadUpAndBearAwayCluster == null ? 0.0 :
getLikelihoodOfClusterBasedOnDistanceFromExpected(
EXPECTED_AVERAGE_HEAD_UP_AND_BEAR_AWAY_MANEUVER_ANGLE_DEG, expectedAverageMiddleCOG, starboardTackHeadUpAndBearAwayCluster);
return starboardHeadUpBearAwayClusterLikelihood;
}
/**
* Assigns a likelihood to a cluster based on its
* {@link #getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(Cluster, double, Bearing)
* "angular distance"} from an expected average middle COG and Tells how likely it is that the two clusters are opposite tack clusters. This is determined
* by looking at the
* {@link #getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(Cluster, double, Bearing)
* angular distance} between the two clusters regarding their middle COG and their average maneuver angles. The
* likelihood decreases exponentially with increasing angle differences. It is 1.0 for an exact match and reaches
* 0.5 for an angular distance of 20deg.
*/
private double getLikelihoodOfClusterBasedOnDistanceFromExpected(
double expectedManeuverAngleDeg, Bearing expectedApproximateMiddleCOG,
Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble> oppositeTackCluster) {
return Math.exp(Math.log(0.5) * (getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(
oppositeTackCluster, expectedManeuverAngleDeg, expectedApproximateMiddleCOG) / ANGULAR_DISTANCE_FOR_HALF_CONFIDENCE_FOR_OPPOSITE_TACK_CLUSTER_DEG));
final double clusterDistanceFromExpected = getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(
oppositeTackCluster, expectedManeuverAngleDeg, expectedApproximateMiddleCOG);
return getLikelihoodOfClusterBasedOnDistanceFromExpected(clusterDistanceFromExpected);
}
/**
* Assigns a likelihood to a cluster based on its
* {@link #getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(Cluster, double, Bearing)
* "angular distance"} from an expected average middle COG and Tells how likely it is that the two clusters are
* opposite tack clusters. This is determined by looking at the
* {@link #getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(Cluster, double, Bearing)
* angular distance} between the two clusters regarding their middle COG and their average maneuver angles. The
* likelihood decreases exponentially with increasing angle differences. It is 1.0 for an exact match and reaches
* 0.5 for an angular distance of 20deg (see
* {@link #ANGULAR_DISTANCE_FOR_HALF_CONFIDENCE_FOR_OPPOSITE_TACK_CLUSTER_DEG}).
*
* @param clusterDistanceFromExpected
* an angular distance as computed by {@link #getClusterDistance(double, Bearing, double, Bearing)} and
* {@link #getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(Cluster, double, Bearing)}
* .
*/
private double getLikelihoodOfClusterBasedOnDistanceFromExpected(final double clusterDistanceFromExpected) {
return Math.exp(Math.log(0.5) * (clusterDistanceFromExpected / ANGULAR_DISTANCE_FOR_HALF_CONFIDENCE_FOR_OPPOSITE_TACK_CLUSTER_DEG));
}
/**
* A euklidian degree distance based on the two degree distances between the maneuver angles and the
* middle COGs. The expected pair is passed as <code>expcetedManeuverAngleDeg</code> and <code>expectedApproximateMiddleCOG</code> whereas
* the actuals are determined by computing the {@link ManeuverType#TACK}-weighted average for those values from <code>cluster</code>.
*/
private double getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(
Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble> cluster,
double expectedManeuverAngleDeg, Bearing expectedApproximateMiddleCOG) {
final Pair<Bearing, Double> weightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg = getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(cluster, ManeuverType.TACK);
final Bearing weightedAverageMiddleCOG = weightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg.getA();
final Double weightedAverageManeuverAngle = weightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg.getB();
return getClusterDistance(expectedManeuverAngleDeg, expectedApproximateMiddleCOG, weightedAverageManeuverAngle, weightedAverageMiddleCOG);
}
/**
* A euklidian degree distance based on the two degree distances between the maneuver angles and the
* middle COGs.
*/
private double getClusterDistanceBasedOnAverageManeuverLikelihoodAndWeightedAverageMiddleCOG(
Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble> cluster,
double expectedManeuverAngleDeg, Bearing expectedApproximateMiddleCOG) {
final Bearing approximateMiddleCOG = getWeightedAverageMiddleManeuverCOGDeg(cluster, ManeuverType.TACK);
double middleCOGDiff = approximateMiddleCOG.getDifferenceTo(expectedApproximateMiddleCOG).getDegrees();
double maneuverAngleDiff = cluster.getCentroid().getB() - expectedManeuverAngleDeg;
private double getClusterDistance(double expectedManeuverAngleDeg, Bearing expectedApproximateMiddleCOG,
final double weightedAverageManeuverAngle, final Bearing weightedAverageMiddleCOG) {
double middleCOGDiff = weightedAverageMiddleCOG.getDifferenceTo(expectedApproximateMiddleCOG).getDegrees();
double maneuverAngleDiff = weightedAverageManeuverAngle - expectedManeuverAngleDeg;
return Math.sqrt(middleCOGDiff*middleCOGDiff + maneuverAngleDiff*maneuverAngleDiff);
}
@@ -508,7 +627,7 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
/**
* Returns at most two clusters that hold maneuvers with the highest average probability of being a jibe and whose
* {@link #getWeightedAverageMiddleManeuverCOGDeg(Cluster, ManeuverType) weighted average middle COG} fits that of
* {@link #getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(Cluster, ManeuverType) weighted average middle COG} fits that of
* the expected value (<code>approximateMiddleCOGForJibes</code>) within
* {@link #THRESHOLD_JIBE_CLUSTER_DIFFERENCE_DEGREES} degrees.
*/
@@ -519,17 +638,17 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
return clusters.stream().sorted((a, b)->
(int) -Math.signum(getAverageLikelihoodOfBeingManeuver(ManeuverType.JIBE, a.stream()) -
getAverageLikelihoodOfBeingManeuver(ManeuverType.JIBE, b.stream()))).filter(
(jibeClusterCandidate)->Math.abs(getWeightedAverageMiddleManeuverCOGDeg(jibeClusterCandidate, ManeuverType.JIBE).
(jibeClusterCandidate)->Math.abs(getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(jibeClusterCandidate, ManeuverType.JIBE).getA().
getDifferenceTo(approximateMiddleCOGForJibes).getDegrees()) < THRESHOLD_JIBE_CLUSTER_DIFFERENCE_DEGREES).
limit(2);
}
/**
* By looking at the weighted speeds over ground averages, and based on the {@link #polarService} determines how
* likely it is that the jibe cluster contents are actually jibes. This is based on the idea that if for the most
* likely wind speeds the jibes have a different (usually significantly higher) entry speed than the tacks then this
* difference show show in the cluster elements. If they don't, then this should give a penalty for the cluster
* likelihoods.
* {@link PolarDataService#getManeuverLikelihoodAndTwsTwa(BoatClass, Speed, double, ManeuverType) likely} it is that
* the jibe cluster contents are actually jibes. This is based on the idea that if for the most likely wind speeds
* the jibes have a different (usually significantly higher) entry speed than the tacks then this difference should
* show in the cluster elements. If they don't, then this should give a penalty for the cluster likelihoods.
* <p>
*
* The weight of a maneuver for computing the weighted speed average is determined to be the
@@ -539,26 +658,48 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
private double getLikelihoodOfBeingJibeCluster(
Speed tackClusterWeightedAverageSpeed,
Stream<ManeuverClassification> jibeClustersContent,
BoatClass boatClass) {
BoatClass boatClass, Set<Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble>> clusters) {
final int[] count = new int[1];
final double[] likelihoodSum = new double[1];
final ScalableBearing[] scaledAverageDownwindCOG = new ScalableBearing[1];
final double[] scaledAbsJibingAngleSum = new double[1];
Stream<ManeuverClassification> jibeClustersContentPeeker = jibeClustersContent.peek((mc)->{
count[0]++;
likelihoodSum[0] += mc.getLikelihoodAndTWSBasedOnSpeedAndAngle(ManeuverType.JIBE).getA();
final double likelihood = mc.getLikelihoodAndTWSBasedOnSpeedAndAngle(ManeuverType.JIBE).getA();
likelihoodSum[0] += likelihood;
final ScalableBearing scaledCOG = new ScalableBearing(mc.getMiddleManeuverCourse()).multiply(likelihood);
if (scaledAverageDownwindCOG[0] == null) {
scaledAverageDownwindCOG[0] = scaledCOG;
} else {
scaledAverageDownwindCOG[0] = scaledAverageDownwindCOG[0].add(scaledCOG);
}
scaledAbsJibingAngleSum[0] += likelihood * Math.abs(mc.getManeuverAngleDeg());
});
Speed jibeClusterWeightedAverageSpeed = getWeightedAverageSpeed(jibeClustersContentPeeker, ManeuverType.JIBE);
Bearing averageDownwindCOG = scaledAverageDownwindCOG[0] == null ? null : scaledAverageDownwindCOG[0].divide(likelihoodSum[0]);
double absWeightedAverageJibingAbgle = scaledAbsJibingAngleSum[0] / likelihoodSum[0];
final double result;
if (jibeClusterWeightedAverageSpeed != null) {
double tackJibeSpeedRatioLikelihood = polarService.getConfidenceForTackJibeSpeedRatio(
tackClusterWeightedAverageSpeed, jibeClusterWeightedAverageSpeed, boatClass);
if (count[0] > 0) {
double averageJibeLikelihood = likelihoodSum[0] / count[0];
result = averageJibeLikelihood * tackJibeSpeedRatioLikelihood;
// Now search for head-up/bear-away cluster(s) to port and to starboard of cluster's weighted middle COG
final Bearing expectedDownwindStarboardTackCOG = averageDownwindCOG.add(new DegreeBearingImpl(+absWeightedAverageJibingAbgle/2.));
double starboardHeadUpBearAwayClusterLikelihood = getLikelihoodOfBestFittingHeadUpBearAwayCluster(
clusters.stream(), expectedDownwindStarboardTackCOG);
final Bearing expectedDownwindPortTackCOG = averageDownwindCOG.add(new DegreeBearingImpl(-absWeightedAverageJibingAbgle/2.));
double portHeadUpBearAwayClusterLikelihood = getLikelihoodOfBestFittingHeadUpBearAwayCluster(
clusters.stream(), expectedDownwindPortTackCOG);
result = Math.min(1.0, averageJibeLikelihood
* (1.0 + BOOST_FACTOR_FOR_JIBE_TACK_SPEED_RATIO_LIKELIHOOD * tackJibeSpeedRatioLikelihood +
BOOST_FACTOR_FOR_FULL_HEAD_UP_BEAR_AWAY_CLUSTER_LIKELIHOOD * starboardHeadUpBearAwayClusterLikelihood +
BOOST_FACTOR_FOR_FULL_HEAD_UP_BEAR_AWAY_CLUSTER_LIKELIHOOD * portHeadUpBearAwayClusterLikelihood));
} else {
throw new RuntimeException("Internal error: no maneuvers in jibe cluster candidate but still a valid weighted average speed "+jibeClusterWeightedAverageSpeed);
}
} else {
result = 0.5; // no maneuvers in the jibe clusters; could be but may also not be a jibe cluster
result = 0.1; // no maneuvers in the jibe clusters; could be but may also not be a jibe cluster
}
return result;
}
@@ -606,28 +747,35 @@ public class ManeuverBasedWindEstimationTrackImpl extends WindTrackImpl {
/**
* For a cluster of maneuver classifications, clustered two-dimensionally by middle COG and maneuver angle, computes the
* weighted average of the middle COG where as the weight of each maneuver the likelihood that the maneuver was of type
* weighted average of the middle COG and maneuver angle where as the weight of each maneuver the likelihood that the maneuver was of type
* <code>maneuverType</code> is used.<p>
*
* The method has default package scope to allow tests in the same package in the test fragment to use it.
*
* @return the weighted average middle COG
*/
Bearing getWeightedAverageMiddleManeuverCOGDeg(
Pair<Bearing, Double> getWeightedAverageMiddleManeuverCOGDegAndManeuverAngleDeg(
Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble> cluster,
ManeuverType maneuverType) {
Pair<Cluster<ManeuverClassification, Pair<ScalableBearing, ScalableDouble>, Pair<Bearing, Double>, ScalableBearingAndScalableDouble>, ManeuverType> key = new Pair<>(
cluster, maneuverType);
Bearing result = weightedAverageMiddleCOGForManeuverType.get(key);
Pair<Bearing, Double> result = weightedAverageMiddleCOGForManeuverType.get(key);
if (result == null) {
ConfidenceBasedAverager<DoublePair, Bearing, Void> averager = ConfidenceFactory.INSTANCE
ConfidenceBasedAverager<DoublePair, Bearing, Void> middleCOGAverager = ConfidenceFactory.INSTANCE
.createAverager(/* weigher */null);
HasConfidence<DoublePair, Bearing, Void> average = averager.getAverage(
HasConfidence<DoublePair, Bearing, Void> average = middleCOGAverager.getAverage(
cluster.stream()
.map(new ManeuverClassificationToHasConfidenceAndIsScalableAdapter<DoublePair, Bearing>(
maneuverType, (mc) -> new ScalableBearing(mc.getMiddleManeuverCourse()),
polarService)).iterator(), /* at */null);
result = average.getObject();
ConfidenceBasedAverager<Double, Double, Void> maneuverAngleAverager = ConfidenceFactory.INSTANCE
.createAverager(/* weigher */null);
HasConfidence<Double, Double, Void> maneuverAngleAverageDeg = maneuverAngleAverager.getAverage(
cluster.stream()
.map(new ManeuverClassificationToHasConfidenceAndIsScalableAdapter<Double, Double>(
maneuverType, (mc) -> new ScalableDouble(mc.getManeuverAngleDeg()),
polarService)).iterator(), /* at */null);
result = new Pair<>(average.getObject(), maneuverAngleAverageDeg.getObject());
weightedAverageMiddleCOGForManeuverType.put(key, result);
}
return result;
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="resources"/>
<classpathentry kind="output" path="bin"/>
</classpath>
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.sap.sailing.xmlexport.test</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
@@ -0,0 +1,12 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8
@@ -0,0 +1,3 @@
eclipse.preferences.version=1
pluginProject.extensions=false
resolve.requirebundle=false
@@ -0,0 +1,12 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Test
Bundle-SymbolicName: com.sap.sailing.xmlexport.test
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Fragment-Host: com.sap.sailing.xmlexport
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.junit4;bundle-version="4.8.2",
com.sap.sse.common,
com.sap.sailing.domain.test;bundle-version="1.0.0",
com.tractrac.clientmodule;bundle-version="3.0.7"
+5
View File
@@ -0,0 +1,5 @@
source.. = src/,\
resources/
output.. = bin/
bin.includes = META-INF/,\
.
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>root</artifactId>
<groupId>com.sap.sailing</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>com.sap.sailing.xmlexport.test</artifactId>
<packaging>eclipse-test-plugin</packaging>
</project>
@@ -0,0 +1,643 @@
stored-uri:event_20141001_ESSNice-Race_1.mtb
StartReplay:1
// Input from params_static:
// Input from event_parameters:
DefaultPanel:
ReCalcDirAndSpeed:1
CompMarkerUUID:2dee0384-2c45-11e4-a9f6-14dae9614d7b
CodanIsSponsor:0
DefaultTailLength:60
APzoomChangeTime:2500
disableAutoProduce:0
autoProduce:0
APstartLineShowOfLeg:0.25
APsideOfStartLine:0.30
APstartSwitch:0.8
APwholeLegBehindMarks:0.15
APmarkSwitch:0.13
APmarkZoomBehindMarks:0.10
APmarkZoomInFrontOfMarks:0.20
PopupMarkerUUID:84199024-2c45-11e4-a9f6-14dae9614d7b
ManualUrl:http://www.tractrac.com/files/userguide_sailing.pdf
//live-uri:tcp://192.168.1.203:4400
//stored-uri:tcp://192.168.1.203:4401
Marker1UUID:2dee0384-2c45-11e4-a9f6-14dae9614d7b
Marker1Type:RGBMarkerFactory
Marker1Directional:1
Marker1Image:markers/boat_FF0000_big.png
Marker1Length:5
Marker1MinPixelSize:30
Startlocation:7.269026586914038,43.68669104379883
MaxDiffTime:1200
MaxMetersPerSecond:20
PrecisionMeters:20
ShortAvgTime:180
LongAvgTime:900
TimeZone:2
CompMarkerTimeout:60
FramesPerSecond:8
replayspeedup:5
MatchRaceClock:0
MatchRaceClockNo:3
MatchRaceClockSpacing:300
Minimap:1
MinimapUseLayers:2
Minimapgeorect:7.241326904296898,43.705766636035165,7.296516491699208,43.67209091170523
MinimapMarkerUUID:84199024-2c45-11e4-a9f6-14dae9614d7b
Marker4UUID:84199024-2c45-11e4-a9f6-14dae9614d7b
Marker4Type:RGBmarkerFactory
Marker4Directional:1
Marker4Image:markers/boat_FF0000_small.png
MetersPerPixel:18
MetersPerPixelMax:30
MetersPerPixelMin:0.2
isMatchRace:0
DefaultDistanceUnits:meters
weatherEnabled:0
DefaultSpeedUnits:KmH
showRaceClock:1
BackGroundImage:graphics/background.jpg
DisableRotation:0
ControlPointMarkerRadius:13
disableselection:0
disableleaderline:0
DisableChangeRace:0
PopUpRow1Name:
PopUpRow1Type:Name
PopUpRow2Name:Knots
PopUpRow2Type:BoatSpeed
PopUpRow3Name:Ranking
PopUpRow3Type:RowNumber
PopUpRow4Name:Sail
PopUpRow4Type:Ini
PopUpRow5Name:After
PopUpRow5Type:BoatAfter
WindEstimator:0
MapUrl:http://tile.traclive.dk/ttm
ResultColumn1Name:#
ResultColumn1Size:20
ResultColumn1Type:RowNumber
ResultColumn2Name:sail
ResultColumn2Size:45
ResultColumn2Type:Ini
ResultColumn3Name:name
ResultColumn3Size:110
ResultColumn3Type:Name
ResultColumn4Name:after
ResultColumn4Size:45
ResultColumn4Type:BoatAfter
ResultColumn5Name:kts
ResultColumn5Size:40
ResultColumn5Type:BoatSpeed
DisableLeaderboard:0
DisableAnalysis:0
TableFontSize:11
compInitialsFontSize:11
AutoRotate:0
MassStart:0
SegmentFile:segments.php
StartType:Mass
RaceHandicapSystem:NONE
TeamCompetitionType:NONE
LiveDelaySecs: 6
//-------- AUTO GENERATED PARAMETERS START ----------------
EventID:8638bc00-2aad-0132-18bc-448a5b8481d8
EventName:ESS Nice 2014
EventDB:event_20141001_ESSNice
EventStartTime:2014-09-30 22:00:00
EventEndTime:2014-10-05 21:00:00
EventType:a1b74ca0-fdd8-11dc-8811-005056c00008
RaceID:09f4b690-2bc6-0132-1eef-10b11c4ed8fd
RaceName:Race 1
RaceStartTime:2014-10-02 12:02:00
RaceEndTime:
RaceTrackingStartTime:2014-10-02 11:58:14
RaceTrackingEndTime:2014-10-02 12:17:02
RaceDefaultRouteUUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
RaceHandicapSystem:NONE
Image1UUID:64a7b348-83db-11e2-88c0-10bf48d758ce
Image1Type:Logo
Image1Description:http://germanmaster.traclive.dk/events/event_20100806_SailforGol/images/SUI.gif
Image1Image:http://germanmaster.traclive.dk/events/event_20100806_SailforGol/images/SUI.gif
Image2UUID:64c3a8fa-83db-11e2-88c0-10bf48d758ce
Image2Type:Logo
Image2Description:http://germanmaster.traclive.dk/events/event_20100806_SailforGol/images/NZL.gif
Image2Image:http://germanmaster.traclive.dk/events/event_20100806_SailforGol/images/NZL.gif
Image3UUID:651130a2-83db-11e2-88c0-10bf48d758ce
Image3Type:Logo
Image3Description:http://germanmaster.traclive.dk/events/event_20100806_SailforGol/images/KOR.gif
Image3Image:http://germanmaster.traclive.dk/events/event_20100806_SailforGol/images/KOR.gif
Image4UUID:653c1ab0-83db-11e2-88c0-10bf48d758ce
Image4Type:Logo
Image4Description:http://germanmaster.traclive.dk/events/event_20100806_SailforGol/images/AUT.gif
Image4Image:http://germanmaster.traclive.dk/events/event_20100806_SailforGol/images/AUT.gif
Image5UUID:65637da8-83db-11e2-88c0-10bf48d758ce
Image5Type:Logo
Image5Description:http://germanmaster.traclive.dk/events/event_20100806_SailforGol/images/DEN.gif
Image5Image:http://germanmaster.traclive.dk/events/event_20100806_SailforGol/images/DEN.gif
Image6UUID:65875138-83db-11e2-88c0-10bf48d758ce
Image6Type:Logo
Image6Description:http://germanmaster.traclive.dk/events/event_20100806_SailforGol/images/OMN.gif
Image6Image:http://germanmaster.traclive.dk/events/event_20100806_SailforGol/images/OMN.gif
Class1UUID:648ee25a-83db-11e2-88c0-10bf48d758ce
Class1Name:Extreme40
Team1UUID:649f1dbe-83db-11e2-88c0-10bf48d758ce
Team1Name:TeamA
Team1Comp1UUID:648bd4f2-83db-11e2-88c0-10bf48d758ce
Team2UUID:64bf0854-83db-11e2-88c0-10bf48d758ce
Team2Name:TeamB
Team2Comp1UUID:64bbff7e-83db-11e2-88c0-10bf48d758ce
Team3UUID:64dd7988-83db-11e2-88c0-10bf48d758ce
Team3Name:TeamC
Team3Comp1UUID:64da7c24-83db-11e2-88c0-10bf48d758ce
Team4UUID:64ffc402-83db-11e2-88c0-10bf48d758ce
Team4Name:TeamD
Team5UUID:65351d82-83db-11e2-88c0-10bf48d758ce
Team5Name:TeamE
Team5Comp1UUID:65322500-83db-11e2-88c0-10bf48d758ce
Team6UUID:655ed82a-83db-11e2-88c0-10bf48d758ce
Team6Name:TeamF
Team6Comp1UUID:655bd56c-83db-11e2-88c0-10bf48d758ce
Team7UUID:65829fa8-83db-11e2-88c0-10bf48d758ce
Team7Name:TeamG
Team7Comp1UUID:657fa5a0-83db-11e2-88c0-10bf48d758ce
Team8UUID:e4459a20-83db-11e2-88c0-10bf48d758ce
Team8Name:TeamH
Team9UUID:a73aabc0-d6d6-0130-8be2-60a44ce903c3
Team9Name:TeamI
Team9Comp1UUID:93085e80-7ad9-0131-e5b3-60a44ce903c3
Team10UUID:bbf81f60-d6d6-0130-8be3-60a44ce903c3
Team10Name:TeamJ
Team10Comp1UUID:f097f4f0-7ad9-0131-e5b4-60a44ce903c3
Team11UUID:65659280-eda3-0130-c5c0-10b11c4ed8fd
Team11Name:TeamK
Team11Comp1UUID:19dc3eb0-7ada-0131-e5b5-60a44ce903c3
Team12UUID:9ee14560-77af-0131-e5af-60a44ce903c3
Team12Name:TeamL
Team12Comp1UUID:5e15e7c0-7ada-0131-e5b6-60a44ce903c3
Team13UUID:b9677300-7ad7-0131-e5b0-60a44ce903c3
Team13Name:TeamM
Team13Comp1UUID:84e68b70-7ada-0131-e5b7-60a44ce903c3
Team14UUID:c9689a00-7ad7-0131-e5b1-60a44ce903c3
Team14Name:TeamN
Team15UUID:d5712f30-7ad7-0131-e5b2-60a44ce903c3
Team15Name:TeamO
Comp1UUID:648bd4f2-83db-11e2-88c0-10bf48d758ce
Comp1Name:Alinghi
Comp1NameShort:Alinghi
Comp1Color:00FF00
Comp1Nationality:SUI
Comp1Description:
Comp1Handicap:1.0000000000
Comp1HandicapDistance:0.00000
Comp1StartTime:2014-10-02 12:02:00
Comp1PictureUUID:64a7b348-83db-11e2-88c0-10bf48d758ce
Comp1ClassUUID:648ee25a-83db-11e2-88c0-10bf48d758ce
Comp1RouteUUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
Comp2UUID:64bbff7e-83db-11e2-88c0-10bf48d758ce
Comp2Name:GAC Pindar
Comp2NameShort:GAC Pindar
Comp2Color:000080
Comp2Nationality:AUS
Comp2Description:
Comp2Handicap:1.0000000000
Comp2HandicapDistance:0.00000
Comp2StartTime:2014-10-02 12:02:00
Comp2PictureUUID:64c3a8fa-83db-11e2-88c0-10bf48d758ce
Comp2ClassUUID:648ee25a-83db-11e2-88c0-10bf48d758ce
Comp2RouteUUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
Comp3UUID:64da7c24-83db-11e2-88c0-10bf48d758ce
Comp3Name:Realteam by Realstone
Comp3NameShort:Realstone
Comp3Color:000000
Comp3Nationality:AFG
Comp3Description:
Comp3Handicap:1.0000000000
Comp3HandicapDistance:0.00000
Comp3StartTime:2014-10-02 12:02:00
Comp3PictureUUID:64a7b348-83db-11e2-88c0-10bf48d758ce
Comp3ClassUUID:648ee25a-83db-11e2-88c0-10bf48d758ce
Comp3RouteUUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
Comp4UUID:65322500-83db-11e2-88c0-10bf48d758ce
Comp4Name:Red Bull Sailing Team
Comp4NameShort:Red Bull
Comp4Color:008080
Comp4Nationality:AUT
Comp4Description:
Comp4Handicap:1.0000000000
Comp4HandicapDistance:0.00000
Comp4StartTime:2014-10-02 12:02:00
Comp4PictureUUID:653c1ab0-83db-11e2-88c0-10bf48d758ce
Comp4ClassUUID:648ee25a-83db-11e2-88c0-10bf48d758ce
Comp4RouteUUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
Comp5UUID:655bd56c-83db-11e2-88c0-10bf48d758ce
Comp5Name:SAP Extreme Sailing Team
Comp5NameShort:SAP
Comp5Color:FFFFFF
Comp5Nationality:DEN
Comp5Description:
Comp5Handicap:1.0000000000
Comp5HandicapDistance:0.00000
Comp5StartTime:2014-10-02 12:02:00
Comp5PictureUUID:65637da8-83db-11e2-88c0-10bf48d758ce
Comp5ClassUUID:648ee25a-83db-11e2-88c0-10bf48d758ce
Comp5RouteUUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
Comp6UUID:657fa5a0-83db-11e2-88c0-10bf48d758ce
Comp6Name:The Wave, Muscat
Comp6NameShort:The Wave
Comp6Color:800080
Comp6Nationality:OMA
Comp6Description:
Comp6Handicap:1.0000000000
Comp6HandicapDistance:0.00000
Comp6StartTime:2014-10-02 12:02:00
Comp6PictureUUID:65875138-83db-11e2-88c0-10bf48d758ce
Comp6ClassUUID:648ee25a-83db-11e2-88c0-10bf48d758ce
Comp6RouteUUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
Comp7UUID:93085e80-7ad9-0131-e5b3-60a44ce903c3
Comp7Name:Emirates Team New Zealand
Comp7NameShort:Emirates NZ
Comp7Color:CC9900
Comp7Nationality:NZL
Comp7Description:
Comp7Handicap:1.0000000000
Comp7HandicapDistance:0.00000
Comp7StartTime:2014-10-02 12:02:00
Comp7PictureUUID:64c3a8fa-83db-11e2-88c0-10bf48d758ce
Comp7ClassUUID:648ee25a-83db-11e2-88c0-10bf48d758ce
Comp7RouteUUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
Comp8UUID:f097f4f0-7ad9-0131-e5b4-60a44ce903c3
Comp8Name:Gazprom Team Russia
Comp8NameShort:Team Russia
Comp8Color:999900
Comp8Nationality:RUS
Comp8Description:
Comp8Handicap:1.0000000000
Comp8HandicapDistance:0.00000
Comp8StartTime:2014-10-02 12:02:00
Comp8ClassUUID:648ee25a-83db-11e2-88c0-10bf48d758ce
Comp8RouteUUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
Comp9UUID:19dc3eb0-7ada-0131-e5b5-60a44ce903c3
Comp9Name:Groupama sailing team
Comp9NameShort:Groupama
Comp9Color:33CC00
Comp9Nationality:AFG
Comp9Description:
Comp9Handicap:1.0000000000
Comp9HandicapDistance:0.00000
Comp9StartTime:2014-10-02 12:02:00
Comp9ClassUUID:648ee25a-83db-11e2-88c0-10bf48d758ce
Comp9RouteUUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
Comp10UUID:5e15e7c0-7ada-0131-e5b6-60a44ce903c3
Comp10Name:J.P. Morgan BAR
Comp10NameShort:J.P. Morgan
Comp10Color:CCFF00
Comp10Nationality:GBR
Comp10Description:
Comp10Handicap:1.0000000000
Comp10HandicapDistance:0.00000
Comp10StartTime:2014-10-02 12:02:00
Comp10ClassUUID:648ee25a-83db-11e2-88c0-10bf48d758ce
Comp10RouteUUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
Comp11UUID:84e68b70-7ada-0131-e5b7-60a44ce903c3
Comp11Name:Oman Air
Comp11NameShort:Oman Air
Comp11Color:CCFF99
Comp11Nationality:OMA
Comp11Description:
Comp11Handicap:1.0000000000
Comp11HandicapDistance:0.00000
Comp11StartTime:2014-10-02 12:02:00
Comp11PictureUUID:65875138-83db-11e2-88c0-10bf48d758ce
Comp11ClassUUID:648ee25a-83db-11e2-88c0-10bf48d758ce
Comp11RouteUUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
ControlPoint1UUID:1100ea60-7adb-0131-e5b8-60a44ce903c3
ControlPoint1Name:Red-Green
ControlPoint1HasTwoPoints:1
ControlPoint1ShortName:RG
ControlPoint1DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Red###BREAKLINE###P1.Shape=Conical###BREAKLINE###P1.Name=Red###BREAKLINE###P1.UUID=5427c7d2-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Green###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=Green###BREAKLINE###P2.UUID=785c3e44-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint1Mark1Lon:7.273181
ControlPoint1Mark1Lat:43.688370
ControlPoint1Mark2Lon:7.272257
ControlPoint1Mark2Lat:43.687305
ControlPoint2UUID:1286f15e-83be-11e2-88c0-10bf48d758ce
ControlPoint2Name:Blue
ControlPoint2HasTwoPoints:0
ControlPoint2ShortName:Bl
ControlPoint2DataSheet:Name=Blue###BREAKLINE###Type=Buoy###BREAKLINE###Color=Blue###BREAKLINE###Shape=Conical
ControlPoint2Mark1Lon:7.269418
ControlPoint2Mark1Lat:43.687290
ControlPoint3UUID:1a94c6a0-7adc-0131-e5f4-60a44ce903c3
ControlPoint3Name:Black Conical-Blue
ControlPoint3HasTwoPoints:1
ControlPoint3ShortName:BB
ControlPoint3DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Black###BREAKLINE###P1.Shape=Conical###BREAKLINE###P1.Pattern=Checkered###BREAKLINE###P1.Name=Black Conical###BREAKLINE###P1.UUID=d78695ea-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Blue###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=Blue###BREAKLINE###P2.UUID=1286f15e-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint3Mark1Lon:7.272432
ControlPoint3Mark1Lat:43.692131
ControlPoint3Mark2Lon:7.269418
ControlPoint3Mark2Lat:43.687290
ControlPoint4UUID:2ce99970-2c47-0132-20ce-10b11c4ed8fd
ControlPoint4Name:Black Conical-White P
ControlPoint4HasTwoPoints:1
ControlPoint4ShortName:F
ControlPoint4DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Black###BREAKLINE###P1.Shape=Conical###BREAKLINE###P1.Pattern=Checkered###BREAKLINE###P1.Name=Black Conical###BREAKLINE###P1.UUID=d78695ea-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=White###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=White P###BREAKLINE###P2.UUID=e9ec42f8-83bd-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint4Mark1Lon:7.272432
ControlPoint4Mark1Lat:43.692131
ControlPoint4Mark2Lon:7.271063
ControlPoint4Mark2Lat:43.691803
ControlPoint5UUID:2dc7d9d0-7b84-0131-b9c3-10b11c4ed8fd
ControlPoint5Name:Black Cylinder - Black Conical
ControlPoint5HasTwoPoints:1
ControlPoint5ShortName:BB
ControlPoint5DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Black###BREAKLINE###P1.Shape=Cylinder###BREAKLINE###P1.Pattern=Checkered###BREAKLINE###P1.Name=Black Cylinder###BREAKLINE###P1.UUID=b153dfd6-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Black###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Pattern=Checkered###BREAKLINE###P2.Name=Black Conical###BREAKLINE###P2.UUID=d78695ea-83be-11e2-88c0-10bf48d758ce
ControlPoint5Mark1Lon:7.269445
ControlPoint5Mark1Lat:43.687302
ControlPoint5Mark2Lon:7.272432
ControlPoint5Mark2Lat:43.692131
ControlPoint6UUID:2e37b410-7adc-0131-e5fe-60a44ce903c3
ControlPoint6Name:Black Conical-Yellow (white S)
ControlPoint6HasTwoPoints:1
ControlPoint6ShortName:BY
ControlPoint6DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Black###BREAKLINE###P1.Shape=Conical###BREAKLINE###P1.Pattern=Checkered###BREAKLINE###P1.Name=Black Conical###BREAKLINE###P1.UUID=d78695ea-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Yellow###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=Yellow###BREAKLINE###P2.UUID=3fdd2402-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint6Mark1Lon:7.272432
ControlPoint6Mark1Lat:43.692131
ControlPoint6Mark2Lon:7.269320
ControlPoint6Mark2Lat:43.687366
ControlPoint7UUID:3240586c-83c0-11e2-88c0-10bf48d758ce
ControlPoint7Name:Finish Pole
ControlPoint7HasTwoPoints:0
ControlPoint7ShortName:F
ControlPoint7DataSheet:Color=Black###BREAKLINE###Type=Landmark###BREAKLINE###Name=Finish Pole
ControlPoint7Mark1Lon:7.271467
ControlPoint7Mark1Lat:43.694897
ControlPoint8UUID:37cb36e0-7adb-0131-e5c2-60a44ce903c3
ControlPoint8Name:Red-Blue
ControlPoint8HasTwoPoints:1
ControlPoint8ShortName:RB
ControlPoint8DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Red###BREAKLINE###P1.Shape=Conical###BREAKLINE###P1.Name=Red###BREAKLINE###P1.UUID=5427c7d2-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Blue###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=Blue###BREAKLINE###P2.UUID=1286f15e-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint8Mark1Lon:7.273181
ControlPoint8Mark1Lat:43.688370
ControlPoint8Mark2Lon:7.269418
ControlPoint8Mark2Lat:43.687290
ControlPoint9UUID:3e6c1c94-83bf-11e2-88c0-10bf48d758ce
ControlPoint9Name:Race Committee
ControlPoint9HasTwoPoints:0
ControlPoint9ShortName:RC
ControlPoint9DataSheet:Type=StartBoat###BREAKLINE###Name=Race Committee
ControlPoint9Mark1Lon:7.267022
ControlPoint9Mark1Lat:43.691895
ControlPoint10UUID:3fdd2402-83be-11e2-88c0-10bf48d758ce
ControlPoint10Name:Yellow
ControlPoint10HasTwoPoints:0
ControlPoint10ShortName:Y
ControlPoint10DataSheet:Type=Buoy###BREAKLINE###Color=Yellow###BREAKLINE###Shape=Conical###BREAKLINE###Name=Yellow
ControlPoint10Mark1Lon:7.269320
ControlPoint10Mark1Lat:43.687366
ControlPoint11UUID:4c304720-7adc-0131-e608-60a44ce903c3
ControlPoint11Name:Black Conical-Red
ControlPoint11HasTwoPoints:1
ControlPoint11ShortName:BR
ControlPoint11DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Black###BREAKLINE###P1.Shape=Conical###BREAKLINE###P1.Pattern=Checkered###BREAKLINE###P1.Name=Black Conical###BREAKLINE###P1.UUID=d78695ea-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Red###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=Red###BREAKLINE###P2.UUID=5427c7d2-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint11Mark1Lon:7.272432
ControlPoint11Mark1Lat:43.692131
ControlPoint11Mark2Lon:7.273181
ControlPoint11Mark2Lat:43.688370
ControlPoint12UUID:4e0c2a90-7adb-0131-e5cc-60a44ce903c3
ControlPoint12Name:Red-Yellow
ControlPoint12HasTwoPoints:1
ControlPoint12ShortName:RY
ControlPoint12DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Red###BREAKLINE###P1.Shape=Conical###BREAKLINE###P1.Name=Red###BREAKLINE###P1.UUID=5427c7d2-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Yellow###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=Yellow###BREAKLINE###P2.UUID=3fdd2402-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint12Mark1Lon:7.273181
ControlPoint12Mark1Lat:43.688370
ControlPoint12Mark2Lon:7.269320
ControlPoint12Mark2Lat:43.687366
ControlPoint13UUID:5427c7d2-83be-11e2-88c0-10bf48d758ce
ControlPoint13Name:Red
ControlPoint13HasTwoPoints:0
ControlPoint13ShortName:R
ControlPoint13DataSheet:Type=Buoy###BREAKLINE###Color=Red###BREAKLINE###Shape=Conical###BREAKLINE###Name=Red
ControlPoint13Mark1Lon:7.273181
ControlPoint13Mark1Lat:43.688370
ControlPoint14UUID:621831d0-7adc-0131-e612-60a44ce903c3
ControlPoint14Name:Black Conical-Green
ControlPoint14HasTwoPoints:1
ControlPoint14ShortName:BG
ControlPoint14DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Black###BREAKLINE###P1.Shape=Conical###BREAKLINE###P1.Pattern=Checkered###BREAKLINE###P1.Name=Black Conical###BREAKLINE###P1.UUID=d78695ea-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Green###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=Green###BREAKLINE###P2.UUID=785c3e44-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint14Mark1Lon:7.272432
ControlPoint14Mark1Lat:43.692131
ControlPoint14Mark2Lon:7.272257
ControlPoint14Mark2Lat:43.687305
ControlPoint15UUID:77b9e620-7adb-0131-e5d6-60a44ce903c3
ControlPoint15Name:Green-Blue
ControlPoint15HasTwoPoints:1
ControlPoint15ShortName:GB
ControlPoint15DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Green###BREAKLINE###P1.Shape=Conical###BREAKLINE###P1.Name=Green###BREAKLINE###P1.UUID=785c3e44-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Blue###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=Blue###BREAKLINE###P2.UUID=1286f15e-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint15Mark1Lon:7.272257
ControlPoint15Mark1Lat:43.687305
ControlPoint15Mark2Lon:7.269418
ControlPoint15Mark2Lat:43.687290
ControlPoint16UUID:785c3e44-83be-11e2-88c0-10bf48d758ce
ControlPoint16Name:Green
ControlPoint16HasTwoPoints:0
ControlPoint16ShortName:G
ControlPoint16DataSheet:Type=Buoy###BREAKLINE###Color=Green###BREAKLINE###Shape=Conical###BREAKLINE###Name=Green
ControlPoint16Mark1Lon:7.272257
ControlPoint16Mark1Lat:43.687305
ControlPoint17UUID:7d9d1730-b3e8-0131-1d10-10b11c4ed8fd
ControlPoint17Name:Race Committee - Finish Pole
ControlPoint17HasTwoPoints:1
ControlPoint17ShortName:RF
ControlPoint17DataSheet:P1.Type=StartBoat###BREAKLINE###P1.Name=Race Committee###BREAKLINE###P1.UUID=3e6c1c94-83bf-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Color=Black###BREAKLINE###P2.Type=Landmark###BREAKLINE###P2.Name=Finish Pole###BREAKLINE###P2.UUID=3240586c-83c0-11e2-88c0-10bf48d758ce
ControlPoint17Mark1Lon:7.267022
ControlPoint17Mark1Lat:43.691895
ControlPoint17Mark2Lon:7.271342
ControlPoint17Mark2Lat:43.694851
ControlPoint18UUID:88ef6d40-7adc-0131-e61c-60a44ce903c3
ControlPoint18Name:Finish Pole-Cylinder
ControlPoint18HasTwoPoints:1
ControlPoint18ShortName:F
ControlPoint18DataSheet:P1.Color=Black###BREAKLINE###P1.Type=Landmark###BREAKLINE###P1.Name=Finish Pole###BREAKLINE###P1.UUID=3240586c-83c0-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Black###BREAKLINE###P2.Shape=Cylinder###BREAKLINE###P2.Pattern=Checkered###BREAKLINE###P2.Name=Black Cylinder###BREAKLINE###P2.UUID=b153dfd6-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint18Mark1Lon:7.271342
ControlPoint18Mark1Lat:43.694851
ControlPoint18Mark2Lon:7.269445
ControlPoint18Mark2Lat:43.687302
ControlPoint19UUID:8f9a4ee0-7adb-0131-e5e0-60a44ce903c3
ControlPoint19Name:Green-Yellow
ControlPoint19HasTwoPoints:1
ControlPoint19ShortName:GY
ControlPoint19DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Green###BREAKLINE###P1.Shape=Conical###BREAKLINE###P1.Name=Green###BREAKLINE###P1.UUID=785c3e44-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Yellow###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=Yellow###BREAKLINE###P2.UUID=3fdd2402-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint19Mark1Lon:7.272257
ControlPoint19Mark1Lat:43.687305
ControlPoint19Mark2Lon:7.269320
ControlPoint19Mark2Lat:43.687366
ControlPoint20UUID:a0f71190-7adb-0131-e5ea-60a44ce903c3
ControlPoint20Name:Blue-Yellow
ControlPoint20HasTwoPoints:1
ControlPoint20ShortName:BY
ControlPoint20DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Blue###BREAKLINE###P1.Shape=Conical###BREAKLINE###P1.Name=Blue###BREAKLINE###P1.UUID=1286f15e-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Yellow###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=Yellow###BREAKLINE###P2.UUID=3fdd2402-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint20Mark1Lon:7.269418
ControlPoint20Mark1Lat:43.687290
ControlPoint20Mark2Lon:7.269320
ControlPoint20Mark2Lat:43.687366
ControlPoint21UUID:a68c6350-7adc-0131-e626-60a44ce903c3
ControlPoint21Name:RC-Black Conical
ControlPoint21HasTwoPoints:1
ControlPoint21ShortName:S
ControlPoint21DataSheet:P1.Type=StartBoat###BREAKLINE###P1.Name=Race Committee###BREAKLINE###P1.UUID=3e6c1c94-83bf-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Black###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Pattern=Checkered###BREAKLINE###P2.Name=Black Conical###BREAKLINE###P2.UUID=d78695ea-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint21Mark1Lon:7.267022
ControlPoint21Mark1Lat:43.691895
ControlPoint21Mark2Lon:7.272432
ControlPoint21Mark2Lat:43.692131
ControlPoint22UUID:b153dfd6-83be-11e2-88c0-10bf48d758ce
ControlPoint22Name:Black Cylinder
ControlPoint22HasTwoPoints:0
ControlPoint22ShortName:B
ControlPoint22DataSheet:Type=Buoy###BREAKLINE###Color=Black###BREAKLINE###Shape=Cylinder###BREAKLINE###Pattern=Checkered###BREAKLINE###Name=Black Cylinder
ControlPoint22Mark1Lon:7.269445
ControlPoint22Mark1Lat:43.687302
ControlPoint23UUID:b62e0bf0-7adc-0131-e630-60a44ce903c3
ControlPoint23Name:RC-Black Cylinder
ControlPoint23HasTwoPoints:1
ControlPoint23ShortName:S
ControlPoint23DataSheet:P1.Type=StartBoat###BREAKLINE###P1.Name=Race Committee###BREAKLINE###P1.UUID=3e6c1c94-83bf-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Black###BREAKLINE###P2.Shape=Cylinder###BREAKLINE###P2.Pattern=Checkered###BREAKLINE###P2.Name=Black Cylinder###BREAKLINE###P2.UUID=b153dfd6-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint23Mark1Lon:7.267022
ControlPoint23Mark1Lat:43.691895
ControlPoint23Mark2Lon:7.269445
ControlPoint23Mark2Lat:43.687302
ControlPoint24UUID:bd1fc330-7c10-0131-9c24-10b11c4ed8fd
ControlPoint24Name:Black Cylinder-Yellow
ControlPoint24HasTwoPoints:1
ControlPoint24ShortName:S
ControlPoint24DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=Black###BREAKLINE###P1.Shape=Cylinder###BREAKLINE###P1.Pattern=Checkered###BREAKLINE###P1.Name=Black Cylinder###BREAKLINE###P1.UUID=b153dfd6-83be-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Yellow###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=Yellow###BREAKLINE###P2.UUID=3fdd2402-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint24Mark1Lon:7.269445
ControlPoint24Mark1Lat:43.687302
ControlPoint24Mark2Lon:7.269320
ControlPoint24Mark2Lat:43.687366
ControlPoint25UUID:bf6777e6-83bd-11e2-88c0-10bf48d758ce
ControlPoint25Name:White S
ControlPoint25HasTwoPoints:0
ControlPoint25ShortName:W
ControlPoint25DataSheet:Type=Buoy###BREAKLINE###Color=White###BREAKLINE###Shape=Conical###BREAKLINE###Name=White S
ControlPoint25Mark1Lon:7.268352
ControlPoint25Mark1Lat:43.691936
ControlPoint26UUID:cd3c1dc0-7c11-0131-9c2e-10b11c4ed8fd
ControlPoint26Name:Finish Pole-Conical
ControlPoint26HasTwoPoints:1
ControlPoint26ShortName:S
ControlPoint26DataSheet:P1.Color=Black###BREAKLINE###P1.Type=Landmark###BREAKLINE###P1.Name=Finish Pole###BREAKLINE###P1.UUID=3240586c-83c0-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Black###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Pattern=Checkered###BREAKLINE###P2.Name=Black Conical###BREAKLINE###P2.UUID=d78695ea-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint26Mark1Lon:7.271342
ControlPoint26Mark1Lat:43.694851
ControlPoint26Mark2Lon:7.272432
ControlPoint26Mark2Lat:43.692131
ControlPoint27UUID:d39a0d00-7adc-0131-e63a-60a44ce903c3
ControlPoint27Name:White Gate
ControlPoint27HasTwoPoints:1
ControlPoint27ShortName:W
ControlPoint27DataSheet:P1.Type=Buoy###BREAKLINE###P1.Color=White###BREAKLINE###P1.Shape=Conical###BREAKLINE###P1.Name=White S###BREAKLINE###P1.UUID=bf6777e6-83bd-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=White###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=White P###BREAKLINE###P2.UUID=e9ec42f8-83bd-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint27Mark1Lon:7.268352
ControlPoint27Mark1Lat:43.691936
ControlPoint27Mark2Lon:7.271063
ControlPoint27Mark2Lat:43.691803
ControlPoint28UUID:d78695ea-83be-11e2-88c0-10bf48d758ce
ControlPoint28Name:Black Conical
ControlPoint28HasTwoPoints:0
ControlPoint28ShortName:B
ControlPoint28DataSheet:Type=Buoy###BREAKLINE###Color=Black###BREAKLINE###Shape=Conical###BREAKLINE###Pattern=Checkered###BREAKLINE###Name=Black Conical
ControlPoint28Mark1Lon:7.272432
ControlPoint28Mark1Lat:43.692131
ControlPoint29UUID:e9ec42f8-83bd-11e2-88c0-10bf48d758ce
ControlPoint29Name:White P
ControlPoint29HasTwoPoints:0
ControlPoint29ShortName:W
ControlPoint29DataSheet:Type=Buoy###BREAKLINE###Color=White###BREAKLINE###Shape=Conical###BREAKLINE###Name=White P
ControlPoint29Mark1Lon:7.271063
ControlPoint29Mark1Lat:43.691803
ControlPoint30UUID:eff23330-7b84-0131-b9d2-10b11c4ed8fd
ControlPoint30Name:RC-Red
ControlPoint30HasTwoPoints:1
ControlPoint30ShortName:S
ControlPoint30DataSheet:P1.Type=StartBoat###BREAKLINE###P1.Name=Race Committee###BREAKLINE###P1.UUID=3e6c1c94-83bf-11e2-88c0-10bf48d758ce###BREAKLINE###P2.Type=Buoy###BREAKLINE###P2.Color=Red###BREAKLINE###P2.Shape=Conical###BREAKLINE###P2.Name=Red###BREAKLINE###P2.UUID=5427c7d2-83be-11e2-88c0-10bf48d758ce###BREAKLINE###
ControlPoint30Mark1Lon:7.267022
ControlPoint30Mark1Lat:43.691895
ControlPoint30Mark2Lon:7.273181
ControlPoint30Mark2Lat:43.688370
SegmentFile:segments.php
Route1UUID:09f125d0-2bc6-0132-1eee-10b11c4ed8fd
Route1Description:Race 1
Route1Length:0
Route1DataSheet:CourseDiagram=Course###BREAKLINE###Seq.1=Line###BREAKLINE###Seq.2=Port###BREAKLINE###Seq.3=Gate###BREAKLINE###Seq.4=Port###BREAKLINE###Seq.5=Line###BREAKLINE###
Route1ControlPoint1UUID:d39a0d00-7adc-0131-e63a-60a44ce903c3
Route1ControlPoint2UUID:785c3e44-83be-11e2-88c0-10bf48d758ce
Route1ControlPoint3UUID:2ce99970-2c47-0132-20ce-10b11c4ed8fd
//-------- AUTO GENERATED PARAMETERS END ------------------
@@ -0,0 +1,76 @@
package com.sap.sailing.xmlexport.test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import org.junit.Test;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.impl.WindSourceImpl;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.HighPointFirstGets10LastBreaksTie;
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
import com.sap.sailing.domain.test.OnlineTracTracBasedTest;
import com.sap.sailing.domain.tracking.impl.WindImpl;
import com.sap.sailing.domain.tractracadapter.ReceiverType;
import com.sap.sailing.xmlexport.LeaderboardData;
public class XMLExportTest extends OnlineTracTracBasedTest {
public XMLExportTest() throws MalformedURLException, URISyntaxException {
super();
}
private void setUpESS2014Nice(String raceNumber) {
URI storedUri;
try {
storedUri = new URI("file:///" + new File("resources/" + getFileName() + raceNumber + ".mtb").getCanonicalPath().replace('\\', '/'));
super.setUp(new URL("file:///" + new File("resources/" + getFileName() + raceNumber + ".txt").getCanonicalPath()),
/* liveUri */null, /* storedUri */storedUri,
new ReceiverType[] { ReceiverType.MARKPASSINGS, ReceiverType.RACECOURSE, ReceiverType.MARKPOSITIONS, ReceiverType.RAWPOSITIONS });
} catch (Exception ex) {
ex.printStackTrace();
}
boolean result = getTrackedRace().recordWind(new WindImpl(/* position */null, getTrackedRace().getStartOfRace(), new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(65))),
new WindSourceImpl(WindSourceType.WEB));
assert result==true;
}
protected String getExpectedEventName() {
return "ESS Nice 2014";
}
protected String getFileName() {
return "event_20141001_ESSNice-Race_";
}
@Test
public void testExportingESSNice2014() {
setUpESS2014Nice("1");
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("ESS 2014 Nice", new ThresholdBasedResultDiscardingRuleImpl(new int[] {0}), new HighPointFirstGets10LastBreaksTie(),
null);
leaderboard.addRace(getTrackedRace(), "R1", false);
LeaderboardData leaderboardData = new LeaderboardData(leaderboard);
try {
leaderboardData.perform();
} catch (Exception e) {
e.printStackTrace();
fail("No exception should occur");
}
String resultData = leaderboardData.getResultXML();
assertNotNull(resultData);
assertTrue(resultData.length()>261000);
}
}
@@ -1,6 +1,7 @@
package com.sap.sailing.xmlexport;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import java.util.NavigableSet;
import java.util.regex.Matcher;
@@ -41,11 +42,21 @@ public abstract class ExportAction {
private HttpServletResponse res;
private RacingEventService service;
private Leaderboard leaderboard;
protected final boolean useProvidedLeaderboard;
private String resultingXMLData;
public ExportAction(HttpServletRequest req, HttpServletResponse res, RacingEventService service) {
this.req = req;
this.res = res;
this.service = service;
this.leaderboard = null;
this.useProvidedLeaderboard = false;
}
public ExportAction(Leaderboard leaderboard) {
this.leaderboard = leaderboard;
this.useProvidedLeaderboard = true;
}
public String getAttribute(String name) {
@@ -55,15 +66,21 @@ public abstract class ExportAction {
public RacingEventService getService() {
return service;
}
public String getResultXML() {
return resultingXMLData;
}
public Leaderboard getLeaderboard() throws IOException, ServletException {
final String leaderboardName = getAttribute("name");
if (leaderboardName == null) {
throw new ServletException("Use the name= parameter to specify the leaderboard");
}
final Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
if (leaderboard == null) {
throw new ServletException("Leaderboard " + leaderboardName + " not found.");
if (!useProvidedLeaderboard) {
final String leaderboardName = getAttribute("name");
if (leaderboardName == null) {
throw new ServletException("Use the name= parameter to specify the leaderboard");
}
leaderboard = getService().getLeaderboardByName(leaderboardName);
if (leaderboard == null) {
throw new ServletException("Leaderboard " + leaderboardName + " not found.");
}
}
return leaderboard;
}
@@ -315,13 +332,22 @@ public abstract class ExportAction {
format.setEncoding("UTF-8");
XMLOutputter xmlOutputter = new XMLOutputter(format);
res.setContentType("text/xml");
res.addHeader("Content-Disposition", "attachment; filename=" + fileName);
try {
xmlOutputter.output(element, res.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
if (!useProvidedLeaderboard) {
res.setContentType("text/xml");
res.addHeader("Content-Disposition", "attachment; filename=" + fileName);
try {
xmlOutputter.output(element, res.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
} else {
StringWriter resultStringWriter = new StringWriter();
try {
xmlOutputter.output(element, resultStringWriter);
resultingXMLData = resultStringWriter.toString();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@@ -74,6 +74,10 @@ public class LeaderboardData extends ExportAction {
public LeaderboardData(HttpServletRequest req, HttpServletResponse res, RacingEventService service) {
super(req, res, service);
}
public LeaderboardData(Leaderboard leaderboard) {
super(leaderboard);
}
/**
* Creates XML for a leaderboard. Expects a list of generated competitors and races XML elements that are associated with the leaderboard.
@@ -907,6 +911,7 @@ public class LeaderboardData extends ExportAction {
}
}
log.info("Finished XML export of leaderboard " + leaderboard.getName() + " in " + MillisecondsTimePoint.now().minus(timeSpent.asMillis()).asMillis() + " milliseconds");
sendDocument(createLeaderboardXML(leaderboard, competitorElements, racesElements, leaderboardConfidenceAndErrorMessages), leaderboard.getName() + ".xml");
Element dataToExport = createLeaderboardXML(leaderboard, competitorElements, racesElements, leaderboardConfidenceAndErrorMessages);
sendDocument(dataToExport, leaderboard.getName() + ".xml");
}
}
+1
View File
@@ -67,6 +67,7 @@
<module>com.sap.sailing.www</module>
<module>com.sap.sailing.www.events</module>
<module>com.sap.sailing.xmlexport</module>
<module>com.sap.sailing.xmlexport.test</module>
<module>com.google.gwt.osgi</module>
<module>com.tractrac.clientmodule</module>
<module>org.json.simple</module>