Merge remote-tracking branch 'server/master'

This commit is contained in:
Axel Uhl
2012-11-16 11:53:06 +01:00
79 changed files with 846 additions and 733 deletions
+5 -5
View File
@@ -473,7 +473,7 @@ into one in the future.
positions to be returned; if not specified,
known boat positions are listed until the
"end of time"
action=showwaypoints: shows the positions of a race's marks / buoys
action=showwaypoints: shows the positions of a course marks
at a specified point in time; if no time/timeasmillis
is provided, the race start time is used; if that is
not available, the start of tracking is used;
@@ -482,10 +482,10 @@ into one in the future.
available, the current time is used. The output
is an array of JSON objects with following format each:
{ "name": ..., // waypoint name
"buoys": [ { // usually one or two buoys
"name": ..., // buoy name
"lat": ..., // optional; if buoy pos known
"lng": ... } ... ] } // optionsl; if buoy pos known
"marks": [ { // usually one mark or two marks in case of a gate
"name": ..., // mark name
"lat": ..., // optional; if mark pos known
"lng": ... } ... ] } // optionsl; if mark pos known
regattaname: name of the regatta, as returned by the "listevents"
action on the /moderator servlet
racename: name of the race, as returned by the "listevents"
@@ -0,0 +1,3 @@
package com.sap.sailing.domain.common;
public enum NauticSide { PORT, STARBOARD };
@@ -1,3 +0,0 @@
package com.sap.sailing.domain.common;
public enum PassingDirection { PORT, STARBOARD };
@@ -22,7 +22,7 @@ import org.junit.Test;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
@@ -187,17 +187,17 @@ public class EndToEndListeningStoreAndFowardTest {
}
}
}
Set<Buoy> buoys = new HashSet<Buoy>();
Set<Mark> marks = new HashSet<Mark>();
for (Waypoint waypoint : race.getCourse().getWaypoints()) {
for (Buoy buoy : waypoint.getBuoys()) {
buoys.add(buoy);
for (Mark mark : waypoint.getMarks()) {
marks.add(mark);
}
}
for (Buoy buoy : buoys) {
final GPSFixTrack<Buoy, GPSFix> track = trackedRace.getOrCreateTrack(buoy);
for (Mark mark : marks) {
final GPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
track.lockForRead();
try {
assertTrue("Track of buoy " + buoy + " empty",
assertTrue("Track of mark " + mark + " empty",
!Util.isEmpty(track.getRawFixes()));
} finally {
track.unlockAfterRead();
@@ -251,17 +251,17 @@ public class EndToEndListeningStoreAndFowardTest {
}
}
}
Set<Buoy> buoys = new HashSet<Buoy>();
Set<Mark> marks = new HashSet<Mark>();
for (Waypoint waypoint : race.getCourse().getWaypoints()) {
for (Buoy buoy : waypoint.getBuoys()) {
buoys.add(buoy);
for (Mark mark : waypoint.getMarks()) {
marks.add(mark);
}
}
for (Buoy buoy : buoys) {
final GPSFixTrack<Buoy, GPSFix> track = trackedRace.getOrCreateTrack(buoy);
for (Mark mark : marks) {
final GPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
track.lockForRead();
try {
assertTrue("Track of buoy " + buoy + " empty", !Util.isEmpty(track.getRawFixes()));
assertTrue("Track of mark " + mark + " empty", !Util.isEmpty(track.getRawFixes()));
} finally {
track.unlockAfterRead();
}
@@ -89,7 +89,7 @@ public class SimpleDomainFactoryTest {
}
@Test
public void testCourseConfigForBuoy() throws PatchFailedException {
public void testCourseConfigForMark() throws PatchFailedException {
DomainFactory domainFactory = DomainFactory.INSTANCE;
Regatta regatta = new RegattaImpl("TestEvent", /* boatClass */ null, new RacingEventServiceImpl(),
com.sap.sailing.domain.base.DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT));
@@ -1,7 +1,6 @@
package com.sap.sailing.domain.swisstimingadapter;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Nationality;
@@ -31,7 +30,7 @@ public interface DomainFactory {
RaceDefinition createRaceDefinition(Regatta regatta, Race race, StartList startList, com.sap.sailing.domain.swisstimingadapter.Course course);
Buoy getOrCreateBuoy(String trackerID);
com.sap.sailing.domain.base.Mark getOrCreateMark(String trackerID);
GPSFixMoving createGPSFix(TimePoint timePointOfTransmission, Fix fix);
@@ -11,7 +11,6 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Nationality;
@@ -199,13 +198,13 @@ public class DomainFactoryImpl implements DomainFactory {
if (result == null) {
switch (Util.size(devices)) {
case 1:
result = getOrCreateBuoy(devices.iterator().next());
result = getOrCreateMark(devices.iterator().next());
break;
case 2:
Iterator<String> buoyNameIter = devices.iterator();
String left = buoyNameIter.next();
String right = buoyNameIter.next();
result = baseDomainFactory.createGate(getOrCreateBuoy(left), getOrCreateBuoy(right), left + "/" + right);
Iterator<String> markNameIter = devices.iterator();
String left = markNameIter.next();
String right = markNameIter.next();
result = baseDomainFactory.createGate(getOrCreateMark(left), getOrCreateMark(right), left + "/" + right);
break;
default:
throw new RuntimeException(
@@ -224,8 +223,8 @@ public class DomainFactoryImpl implements DomainFactory {
* {@link MessageType#RPD RPD} message
*/
@Override
public Buoy getOrCreateBuoy(String id) {
return baseDomainFactory.getOrCreateBuoy(id);
public com.sap.sailing.domain.base.Mark getOrCreateMark(String id) {
return baseDomainFactory.getOrCreateMark(id);
}
@Override
@@ -12,10 +12,10 @@ import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.Distance;
@@ -36,14 +36,14 @@ import com.sap.sailing.domain.swisstimingadapter.SwissTimingRaceTracker;
import com.sap.sailing.domain.tracking.AbstractRaceTrackerImpl;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceTracker;
import com.sap.sailing.domain.tracking.RacesHandle;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
@@ -179,8 +179,8 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
case TIMINGSCORING:
case UNIDENTIFIED:
String trackerID = fix.getBoatID();
Buoy buoy = domainFactory.getOrCreateBuoy(trackerID);
trackedRace.recordFix(buoy, gpsFix);
Mark mark = domainFactory.getOrCreateMark(trackerID);
trackedRace.recordFix(mark, gpsFix);
break;
case COMPETITOR:
Competitor competitor = domainFactory.getCompetitorByBoatID(fix.getBoatID());
@@ -13,7 +13,7 @@ import org.junit.Test;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BuoyImpl;
import com.sap.sailing.domain.base.impl.MarkImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.impl.Util;
@@ -32,7 +32,7 @@ public class CourseTest {
@Test
public void testCourseWithOneWaypoint() {
List<Waypoint> waypoints = new ArrayList<Waypoint>();
waypoints.add(new WaypointImpl(new BuoyImpl("Test Buoy")));
waypoints.add(new WaypointImpl(new MarkImpl("Test Mark")));
Course course = new CourseImpl("Test Course", waypoints);
assertEquals(1, Util.size(course.getWaypoints()));
assertEquals(0, Util.size(course.getLegs()));
@@ -41,11 +41,11 @@ public class CourseTest {
@Test
public void testAddWaypointToCourseWithOneWaypoint() {
List<Waypoint> waypoints = new ArrayList<Waypoint>();
waypoints.add(new WaypointImpl(new BuoyImpl("Test Buoy")));
waypoints.add(new WaypointImpl(new MarkImpl("Test Mark")));
Course course = new CourseImpl("Test Course", waypoints);
assertEquals(1, Util.size(course.getWaypoints()));
assertEquals(0, Util.size(course.getLegs()));
course.addWaypoint(1, new WaypointImpl(new BuoyImpl("Second Buoy")));
course.addWaypoint(1, new WaypointImpl(new MarkImpl("Second Mark")));
assertEquals(2, Util.size(course.getWaypoints()));
assertEquals(1, Util.size(course.getLegs()));
}
@@ -56,7 +56,7 @@ public class CourseTest {
Course course = new CourseImpl("Test Course", waypoints);
assertEquals(0, Util.size(course.getWaypoints()));
assertEquals(0, Util.size(course.getLegs()));
course.addWaypoint(0, new WaypointImpl(new BuoyImpl("First Buoy")));
course.addWaypoint(0, new WaypointImpl(new MarkImpl("First Mark")));
assertEquals(1, Util.size(course.getWaypoints()));
assertEquals(0, Util.size(course.getLegs()));
}
@@ -64,8 +64,8 @@ public class CourseTest {
@Test
public void testRemoveWaypointToCourseWithOneWaypoint() {
List<Waypoint> waypoints = new ArrayList<Waypoint>();
waypoints.add(new WaypointImpl(new BuoyImpl("Test Buoy")));
waypoints.add(new WaypointImpl(new BuoyImpl("Second Buoy")));
waypoints.add(new WaypointImpl(new MarkImpl("Test Mark")));
waypoints.add(new WaypointImpl(new MarkImpl("Second Mark")));
Course course = new CourseImpl("Test Course", waypoints);
assertEquals(2, Util.size(course.getWaypoints()));
assertEquals(1, Util.size(course.getLegs()));
@@ -78,7 +78,7 @@ public class CourseTest {
public void testRemoveWaypointToEmptyCourse() {
Iterable<Waypoint> waypoints = Collections.emptyList();
Course course = new CourseImpl("Test Course", waypoints);
course.addWaypoint(0, new WaypointImpl(new BuoyImpl("First Buoy")));
course.addWaypoint(0, new WaypointImpl(new MarkImpl("First Mark")));
assertEquals(1, Util.size(course.getWaypoints()));
assertEquals(0, Util.size(course.getLegs()));
course.removeWaypoint(0);
@@ -89,14 +89,14 @@ public class CourseTest {
@Test
public void testInsertWaypointToCourseWithTwoWaypoints() {
List<Waypoint> waypoints = new ArrayList<Waypoint>();
final WaypointImpl wp1 = new WaypointImpl(new BuoyImpl("Test Buoy 1"));
final WaypointImpl wp1 = new WaypointImpl(new MarkImpl("Test Mark 1"));
waypoints.add(wp1);
final WaypointImpl wp2 = new WaypointImpl(new BuoyImpl("Test Buoy 2"));
final WaypointImpl wp2 = new WaypointImpl(new MarkImpl("Test Mark 2"));
waypoints.add(wp2);
Course course = new CourseImpl("Test Course", waypoints);
assertEquals(2, Util.size(course.getWaypoints()));
assertEquals(1, Util.size(course.getLegs()));
final WaypointImpl wp1_5 = new WaypointImpl(new BuoyImpl("Test Buoy 1.5"));
final WaypointImpl wp1_5 = new WaypointImpl(new MarkImpl("Test Mark 1.5"));
course.addWaypoint(1, wp1_5);
assertEquals(3, Util.size(course.getWaypoints()));
assertEquals(2, Util.size(course.getLegs()));
@@ -109,11 +109,11 @@ public class CourseTest {
@Test
public void testRemovetWaypointFromCourseWithThreeWaypoints() {
List<Waypoint> waypoints = new ArrayList<Waypoint>();
final WaypointImpl wp1 = new WaypointImpl(new BuoyImpl("Test Buoy 1"));
final WaypointImpl wp1 = new WaypointImpl(new MarkImpl("Test Mark 1"));
waypoints.add(wp1);
final WaypointImpl wp2 = new WaypointImpl(new BuoyImpl("Test Buoy 2"));
final WaypointImpl wp2 = new WaypointImpl(new MarkImpl("Test Mark 2"));
waypoints.add(wp2);
final WaypointImpl wp3 = new WaypointImpl(new BuoyImpl("Test Buoy 3"));
final WaypointImpl wp3 = new WaypointImpl(new MarkImpl("Test Mark 3"));
waypoints.add(wp3);
Course course = new CourseImpl("Test Course", waypoints);
assertEquals(3, Util.size(course.getWaypoints()));
@@ -26,7 +26,7 @@ import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BuoyImpl;
import com.sap.sailing.domain.base.impl.MarkImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.impl.Util;
@@ -130,10 +130,10 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest {
@Test
public void testWaypointListDiff() {
Waypoint wp1 = new WaypointImpl(new BuoyImpl("b1"));
Waypoint wp2 = new WaypointImpl(new BuoyImpl("b2"));
Waypoint wp3 = new WaypointImpl(new BuoyImpl("b3"));
Waypoint wp4 = new WaypointImpl(new BuoyImpl("b4"));
Waypoint wp1 = new WaypointImpl(new MarkImpl("b1"));
Waypoint wp2 = new WaypointImpl(new MarkImpl("b2"));
Waypoint wp3 = new WaypointImpl(new MarkImpl("b3"));
Waypoint wp4 = new WaypointImpl(new MarkImpl("b4"));
List<Waypoint> waypoints = new ArrayList<Waypoint>(4);
waypoints.add(wp1);
waypoints.add(wp2);
@@ -24,7 +24,7 @@ import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BuoyImpl;
import com.sap.sailing.domain.base.impl.MarkImpl;
import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.base.impl.GateImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
@@ -731,8 +731,8 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
for (Competitor[] competitorList : competitorLists) {
RaceColumn raceColumn = columnIter.next();
final Map<Competitor, TimePoint> lastMarkPassingTimes = lastMarkPassingTimesForCompetitors[i];
final Waypoint start = new WaypointImpl(new GateImpl(new BuoyImpl("Left StartBuoy"), new BuoyImpl("Right StartBuoy"), "Start"));
final Waypoint finish = new WaypointImpl(new BuoyImpl("FinishBuoy"));
final Waypoint start = new WaypointImpl(new GateImpl(new MarkImpl("Left StartBuoy"), new MarkImpl("Right StartBuoy"), "Start"));
final Waypoint finish = new WaypointImpl(new MarkImpl("FinishBuoy"));
TrackedRace trackedRace = new MockedTrackedRaceWithStartTimeAndRanks(startTimes[i], Arrays.asList(competitorList)) {
private static final long serialVersionUID = 1L;
@Override
@@ -16,7 +16,7 @@ import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
@@ -63,16 +63,16 @@ public class ManeuverAnalysisIDMChampionsFinalTest extends AbstractManeuverDetec
public static void fixApproximateMarkPositionsForWindReadOut(DynamicTrackedRace race) {
TimePoint epoch = new MillisecondsTimePoint(0l);
TimePoint now = MillisecondsTimePoint.now();
Map<String, Position> buoyPositions = new HashMap<String, Position>();
buoyPositions.put("G2 Start-Finish (left)", new DegreePosition(53.96003300000019, 10.878697000000084));
buoyPositions.put("G2 Start-Finish (right)", new DegreePosition(53.9674420000693, 10.894410000058738));
buoyPositions.put("G2 Mark4 (right)", new DegreePosition(53.96002200000019, 10.878875000000063));
buoyPositions.put("G2 Mark4 (left)", new DegreePosition(53.9599880000002, 10.878665000000069));
buoyPositions.put("G2 Mark1", new DegreePosition(53.96355800000006, 10.885751999999806));
Map<String, Position> markPositions = new HashMap<String, Position>();
markPositions.put("G2 Start-Finish (left)", new DegreePosition(53.96003300000019, 10.878697000000084));
markPositions.put("G2 Start-Finish (right)", new DegreePosition(53.9674420000693, 10.894410000058738));
markPositions.put("G2 Mark4 (right)", new DegreePosition(53.96002200000019, 10.878875000000063));
markPositions.put("G2 Mark4 (left)", new DegreePosition(53.9599880000002, 10.878665000000069));
markPositions.put("G2 Mark1", new DegreePosition(53.96355800000006, 10.885751999999806));
for (Waypoint w : race.getRace().getCourse().getWaypoints()) {
for (Buoy buoy : w.getBuoys()) {
race.getOrCreateTrack(buoy).addGPSFix(new GPSFixImpl(buoyPositions.get(buoy.getName()), epoch));
race.getOrCreateTrack(buoy).addGPSFix(new GPSFixImpl(buoyPositions.get(buoy.getName()), now));
for (Mark mark : w.getMarks()) {
race.getOrCreateTrack(mark).addGPSFix(new GPSFixImpl(markPositions.get(mark.getName()), epoch));
race.getOrCreateTrack(mark).addGPSFix(new GPSFixImpl(markPositions.get(mark.getName()), now));
}
}
}
@@ -16,7 +16,7 @@ import java.util.TimeZone;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
@@ -53,15 +53,15 @@ public class ManeuverDetectionOnMdM2011SemifinalTest extends OnlineTracTracBased
/* raceId */ "01ea3604-02ef-11e1-9efc-406186cbf87c", new ReceiverType[] { ReceiverType.MARKPASSINGS, ReceiverType.RACECOURSE, ReceiverType.RAWPOSITIONS });
TimePoint epoch = new MillisecondsTimePoint(0l);
TimePoint now = MillisecondsTimePoint.now();
Map<String, Position> buoyPositions = new HashMap<String, Position>();
buoyPositions.put("CR Start (left)", new DegreePosition(53.562944999999985, 10.010104000000046));
buoyPositions.put("CR Start (right)", new DegreePosition(53.562944999999985, 10.010104000000046));
buoyPositions.put("Leeward mark", new DegreePosition(53.562145000000015, 10.009252));
buoyPositions.put("Luvtonne", new DegreePosition(53.560581899999995, 10.005657));
Map<String, Position> markPositions = new HashMap<String, Position>();
markPositions.put("CR Start (left)", new DegreePosition(53.562944999999985, 10.010104000000046));
markPositions.put("CR Start (right)", new DegreePosition(53.562944999999985, 10.010104000000046));
markPositions.put("Leeward mark", new DegreePosition(53.562145000000015, 10.009252));
markPositions.put("Luvtonne", new DegreePosition(53.560581899999995, 10.005657));
for (Waypoint w : getTrackedRace().getRace().getCourse().getWaypoints()) {
for (Buoy buoy : w.getBuoys()) {
getTrackedRace().getOrCreateTrack(buoy).addGPSFix(new GPSFixImpl(buoyPositions.get(buoy.getName()), epoch));
getTrackedRace().getOrCreateTrack(buoy).addGPSFix(new GPSFixImpl(buoyPositions.get(buoy.getName()), now));
for (Mark mark : w.getMarks()) {
getTrackedRace().getOrCreateTrack(mark).addGPSFix(new GPSFixImpl(markPositions.get(mark.getName()), epoch));
getTrackedRace().getOrCreateTrack(mark).addGPSFix(new GPSFixImpl(markPositions.get(mark.getName()), now));
}
}
getTrackedRace().recordWind(new WindImpl(/* position */ null, MillisecondsTimePoint.now(),
@@ -14,7 +14,7 @@ import java.util.Set;
import org.junit.Test;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Nationality;
@@ -88,21 +88,21 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
}
@Test
public void testIdentityStabilityOfBuoySerialization() throws ClassNotFoundException, IOException {
public void testIdentityStabilityOfMarkSerialization() throws ClassNotFoundException, IOException {
DomainFactory senderDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
Buoy sendersBuoy1 = senderDomainFactory.getOrCreateBuoy("TestBuoy1");
Buoy receiversBuoy1 = cloneBySerialization(sendersBuoy1, receiverDomainFactory);
Buoy receiversSecondCopyOfBuoy1 = cloneBySerialization(sendersBuoy1, receiverDomainFactory);
assertSame(receiversBuoy1, receiversSecondCopyOfBuoy1);
Mark sendersMark1 = senderDomainFactory.getOrCreateMark("TestBuoy1");
Mark receiversMark1 = cloneBySerialization(sendersMark1, receiverDomainFactory);
Mark receiversSecondCopyOfMark1 = cloneBySerialization(sendersMark1, receiverDomainFactory);
assertSame(receiversMark1, receiversSecondCopyOfMark1);
}
@Test
public void testIdentityStabilityOfWaypointSerialization() throws ClassNotFoundException, IOException {
DomainFactory senderDomainFactory = new DomainFactoryImpl();
DomainFactory receiverDomainFactory = new DomainFactoryImpl();
Buoy sendersBuoy1 = senderDomainFactory.getOrCreateBuoy("TestBuoy1");
Waypoint sendersWaypoint1 = senderDomainFactory.createWaypoint(sendersBuoy1);
Mark sendersMark1 = senderDomainFactory.getOrCreateMark("TestBuoy1");
Waypoint sendersWaypoint1 = senderDomainFactory.createWaypoint(sendersMark1);
Waypoint receiversWaypoint1 = cloneBySerialization(sendersWaypoint1, receiverDomainFactory);
Waypoint receiversSecondCopyOfWaypoint1 = cloneBySerialization(sendersWaypoint1, receiverDomainFactory);
assertSame(receiversWaypoint1, receiversSecondCopyOfWaypoint1);
@@ -17,7 +17,7 @@ import java.util.regex.Pattern;
import org.junit.Before;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.RaceDefinition;
@@ -156,20 +156,20 @@ public abstract class OnlineTracTracBasedTest extends AbstractTracTracLiveTest {
public static void fixApproximateMarkPositionsForWindReadOut(DynamicTrackedRace race, TimePoint timePointForFixes) {
TimePoint epoch = new MillisecondsTimePoint(0l);
TimePoint now = MillisecondsTimePoint.now();
Map<String, Position> buoyPositions = new HashMap<String, Position>();
buoyPositions.put("K Start (left)", new DegreePosition(54.497439439999994, 10.205943000000001));
buoyPositions.put("K Start (right)", new DegreePosition(54.500209999999996, 10.20206472));
buoyPositions.put("K Mark4 (right)", new DegreePosition(54.499422999999986, 10.200381692));
buoyPositions.put("K Mark4 (left)", new DegreePosition(54.498954999999995, 10.200982));
buoyPositions.put("K Mark1", new DegreePosition(54.489738990000006, 10.17079423000015));
buoyPositions.put("K Finish (left)", new DegreePosition(54.48918199999999, 10.17003714));
buoyPositions.put("K Finish (right)", new DegreePosition(54.48891756, 10.170632146666675));
Map<String, Position> markPositions = new HashMap<String, Position>();
markPositions.put("K Start (left)", new DegreePosition(54.497439439999994, 10.205943000000001));
markPositions.put("K Start (right)", new DegreePosition(54.500209999999996, 10.20206472));
markPositions.put("K Mark4 (right)", new DegreePosition(54.499422999999986, 10.200381692));
markPositions.put("K Mark4 (left)", new DegreePosition(54.498954999999995, 10.200982));
markPositions.put("K Mark1", new DegreePosition(54.489738990000006, 10.17079423000015));
markPositions.put("K Finish (left)", new DegreePosition(54.48918199999999, 10.17003714));
markPositions.put("K Finish (right)", new DegreePosition(54.48891756, 10.170632146666675));
for (Waypoint w : race.getRace().getCourse().getWaypoints()) {
for (Buoy buoy : w.getBuoys()) {
race.getOrCreateTrack(buoy).addGPSFix(new GPSFixImpl(buoyPositions.get(buoy.getName()), epoch));
race.getOrCreateTrack(buoy).addGPSFix(new GPSFixImpl(buoyPositions.get(buoy.getName()),
for (Mark mark : w.getMarks()) {
race.getOrCreateTrack(mark).addGPSFix(new GPSFixImpl(markPositions.get(mark.getName()), epoch));
race.getOrCreateTrack(mark).addGPSFix(new GPSFixImpl(markPositions.get(mark.getName()),
timePointForFixes));
race.getOrCreateTrack(buoy).addGPSFix(new GPSFixImpl(buoyPositions.get(buoy.getName()), now));
race.getOrCreateTrack(mark).addGPSFix(new GPSFixImpl(markPositions.get(mark.getName()), now));
}
}
}
@@ -11,7 +11,7 @@ import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course;
@@ -20,7 +20,7 @@ import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.BuoyImpl;
import com.sap.sailing.domain.base.impl.MarkImpl;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.GateImpl;
@@ -86,11 +86,11 @@ public class ReachingLegTest extends TrackBasedTest {
TrackedRegatta trackedRegatta = new TrackedRegattaImpl(regatta);
List<Waypoint> waypoints = new ArrayList<Waypoint>();
// create a two-lap upwind/downwind course:
BuoyImpl left = new BuoyImpl("Left lee gate buoy");
BuoyImpl right = new BuoyImpl("Right lee gate buoy");
MarkImpl left = new MarkImpl("Left lee gate buoy");
MarkImpl right = new MarkImpl("Right lee gate buoy");
ControlPoint leeGate = new GateImpl(left, right, "Lee Gate");
Buoy windwardMark = new BuoyImpl("Windward mark");
Buoy offsetMark = new BuoyImpl("Offset mark");
Mark windwardMark = new MarkImpl("Windward mark");
Mark offsetMark = new MarkImpl("Offset mark");
waypoints.add(new WaypointImpl(leeGate));
waypoints.add(new WaypointImpl(windwardMark));
waypoints.add(new WaypointImpl(offsetMark));
@@ -46,7 +46,7 @@ public class TackTest extends StoredTrackBasedTestWithTrackedRace {
@Test
public void testWindRoughlyFromNorth() {
// as the upwind leg points roughtly north, the wind is expected to come roughly from the north
Wind wind = getTrackedRace().getWind(getTrackedRace().getOrCreateTrack(getTrackedRace().getRace().getCourse().getFirstWaypoint().getBuoys().iterator().next()).
Wind wind = getTrackedRace().getWind(getTrackedRace().getOrCreateTrack(getTrackedRace().getRace().getCourse().getFirstWaypoint().getMarks().iterator().next()).
getEstimatedPosition(MillisecondsTimePoint.now(), /* extrapolate */ false),
MillisecondsTimePoint.now());
assertEquals(0., wind.getFrom().getDifferenceTo(new DegreeBearingImpl(0)).getDegrees(), 1.);
@@ -5,7 +5,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course;
@@ -15,7 +15,7 @@ import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.BuoyImpl;
import com.sap.sailing.domain.base.impl.MarkImpl;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.GateImpl;
@@ -96,10 +96,10 @@ public abstract class TrackBasedTest {
TrackedRegatta trackedRegatta = new TrackedRegattaImpl(regatta);
List<Waypoint> waypoints = new ArrayList<Waypoint>();
// create a two-lap upwind/downwind course:
BuoyImpl left = new BuoyImpl("Left lee gate buoy");
BuoyImpl right = new BuoyImpl("Right lee gate buoy");
MarkImpl left = new MarkImpl("Left lee gate buoy");
MarkImpl right = new MarkImpl("Right lee gate buoy");
ControlPoint leeGate = new GateImpl(left, right, "Lee Gate");
Buoy windwardMark = new BuoyImpl("Windward mark");
Mark windwardMark = new MarkImpl("Windward mark");
waypoints.add(new WaypointImpl(leeGate));
waypoints.add(new WaypointImpl(windwardMark));
waypoints.add(new WaypointImpl(leeGate));
@@ -180,7 +180,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
Distance d = new NauticalMileDistance(1);
Wind wind = getTrackedRace().getWind(null, checkTime, getTrackedRace().getWindSources(WindSourceType.TRACK_BASED_ESTIMATION));
Position newWindwardMarkPosition = leewardGatePosition.translateGreatCircle(wind.getBearing(), d);
getTrackedRace().getOrCreateTrack(windwardMark.getBuoys().iterator().next()).addGPSFix(
getTrackedRace().getOrCreateTrack(windwardMark.getMarks().iterator().next()).addGPSFix(
new GPSFixImpl(newWindwardMarkPosition, checkTime));
assertEquals(LegType.DOWNWIND, firstLeg.getLegType(fixTime));
Wind estimatedWindDirectionDownwind = track.getAveragedWind(/* position */ null, checkTime);
@@ -15,7 +15,7 @@ import java.util.Set;
import org.junit.Test;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.DomainFactory;
@@ -246,10 +246,10 @@ public class WindTest {
@Test
public void testWindEstimationReturnsNullIfNoUpwindStartAndNoOtherWindDataAvailable() {
DomainFactory domainFactory = DomainFactory.INSTANCE;
Buoy startFinishLeft = domainFactory.getOrCreateBuoy("Start/Finish left");
Buoy startFinishRight = domainFactory.getOrCreateBuoy("Start/Finish right");
Mark startFinishLeft = domainFactory.getOrCreateMark("Start/Finish left");
Mark startFinishRight = domainFactory.getOrCreateMark("Start/Finish right");
ControlPoint startFinish = domainFactory.createGate(startFinishLeft, startFinishRight, "Start/Finish");
ControlPoint top = domainFactory.getOrCreateBuoy("Top");
ControlPoint top = domainFactory.getOrCreateMark("Top");
Waypoint w1 = domainFactory.createWaypoint(startFinish);
Waypoint w2 = domainFactory.createWaypoint(top);
Waypoint w3 = domainFactory.createWaypoint(startFinish);
@@ -4,7 +4,7 @@ import java.util.List;
import java.util.NavigableSet;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.Regatta;
@@ -154,7 +154,7 @@ public class MockedTrackedRace implements DynamicTrackedRace {
}
@Override
public DynamicGPSFixTrack<Buoy, GPSFix> getOrCreateTrack(Buoy buoy) {
public DynamicGPSFixTrack<Mark, GPSFix> getOrCreateTrack(Mark mark) {
// TODO Auto-generated method stub
return null;
}
@@ -607,7 +607,7 @@ public class MockedTrackedRace implements DynamicTrackedRace {
}
@Override
public void recordFix(Buoy buoy, GPSFix fix) {
public void recordFix(Mark mark, GPSFix fix) {
// TODO Auto-generated method stub
}
@@ -672,7 +672,7 @@ public class MockedTrackedRace implements DynamicTrackedRace {
}
@Override
public Iterable<Buoy> getBuoys() {
public Iterable<Mark> getMarks() {
// TODO Auto-generated method stub
return null;
}
@@ -5,7 +5,7 @@ import java.util.Collections;
import java.util.List;
import java.util.NavigableSet;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.RaceDefinition;
@@ -193,7 +193,7 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
}
@Override
public GPSFixTrack<Buoy, GPSFix> getOrCreateTrack(Buoy buoy) {
public GPSFixTrack<Mark, GPSFix> getOrCreateTrack(Mark mark) {
// TODO Auto-generated method stub
return null;
}
@@ -435,7 +435,7 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
}
@Override
public Iterable<Buoy> getBuoys() {
public Iterable<Mark> getMarks() {
// TODO Auto-generated method stub
return null;
}
@@ -12,7 +12,7 @@ import java.util.List;
import com.maptrack.client.io.TypeController;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Nationality;
import com.sap.sailing.domain.base.Person;
@@ -189,11 +189,11 @@ public interface DomainFactory {
DynamicRaceDefinitionSet raceDefinitionSetToUpdate);
/**
* The record may be for a single buoy or a gate. If for a gate, the
* The record may be for a single mark or a gate. If for a gate, the
* {@link ControlPointPositionData#getIndex() index} is used to determine
* which of its buoys is affected.
* which of its marks is affected.
*/
Buoy getBuoy(ControlPoint controlPoint, ControlPointPositionData record);
Mark getMark(ControlPoint controlPoint, ControlPointPositionData record);
com.sap.sailing.domain.base.ControlPoint getOrCreateControlPoint(ControlPoint controlPoint);
@@ -20,7 +20,7 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Nationality;
@@ -144,17 +144,17 @@ public class DomainFactoryImpl implements DomainFactory {
if (domainControlPoint == null) {
String controlPointName = controlPoint.getName();
Map<String, String> controlPointMetadata = parseControlPointMetadata(controlPoint);
String buoyColor = controlPointMetadata.get("Color");
String buoyShape = controlPointMetadata.get("Shape");
String buoyPattern = controlPointMetadata.get("Pattern");
String markColor = controlPointMetadata.get("Color");
String markShape = controlPointMetadata.get("Shape");
String markPattern = controlPointMetadata.get("Pattern");
if (controlPoint.getHasTwoPoints()) {
// it's a gate
Buoy leftBuoy = baseDomainFactory.getOrCreateBuoy(controlPointName + " (left)", buoyColor, buoyShape, buoyPattern);
Buoy rightBuoy = baseDomainFactory.getOrCreateBuoy(controlPointName + " (right)", buoyColor, buoyShape, buoyPattern);
domainControlPoint = baseDomainFactory.createGate(leftBuoy, rightBuoy, controlPointName);
Mark leftMark = baseDomainFactory.getOrCreateMark(controlPointName + " (left)", markColor, markShape, markPattern);
Mark rightMark = baseDomainFactory.getOrCreateMark(controlPointName + " (right)", markColor, markShape, markPattern);
domainControlPoint = baseDomainFactory.createGate(leftMark, rightMark, controlPointName);
} else {
Buoy buoy = baseDomainFactory.getOrCreateBuoy(controlPointName, buoyColor, buoyShape, buoyPattern);
domainControlPoint = buoy;
Mark mark = baseDomainFactory.getOrCreateMark(controlPointName, markColor, markShape, markPattern);
domainControlPoint = mark;
}
controlPointCache.put(controlPoint, domainControlPoint);
}
@@ -497,10 +497,10 @@ public class DomainFactoryImpl implements DomainFactory {
}
@Override
public Buoy getBuoy(ControlPoint controlPoint, ControlPointPositionData record) {
public Mark getMark(ControlPoint controlPoint, ControlPointPositionData record) {
com.sap.sailing.domain.base.ControlPoint myControlPoint = getOrCreateControlPoint(controlPoint);
Buoy result;
Iterator<Buoy> iter = myControlPoint.getBuoys().iterator();
Mark result;
Iterator<Mark> iter = myControlPoint.getMarks().iterator();
if (controlPoint.getHasTwoPoints()) {
if (record.getIndex() == 0) {
result = iter.next();
@@ -5,7 +5,7 @@ import java.util.List;
import java.util.logging.Logger;
import com.maptrack.client.io.TypeController;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
@@ -81,7 +81,7 @@ public class MarkPositionReceiver extends AbstractReceiverWithQueue<ControlPoint
/**
* The listeners returned will, when added to a controller, receive events about the
* position changes of marks during a race. Receiving such an event updates the Buoy's
* position changes of marks during a race. Receiving such an event updates the mark's
* {@link GPSFixTrack} in the {@link TrackedRegatta}. Starts a thread for this receiver,
* blocking for events received.
*/
@@ -113,15 +113,15 @@ public class MarkPositionReceiver extends AbstractReceiverWithQueue<ControlPoint
System.out.println();
}
}
Buoy buoy = getDomainFactory().getBuoy(event.getA(), event.getB());
Mark mark = getDomainFactory().getMark(event.getA(), event.getB());
for (Race tractracRace : getTracTracEvent().getRaceList()) {
DynamicTrackedRace trackedRace = getTrackedRace(tractracRace);
if (trackedRace != null) {
GPSFixMoving markPosition = getDomainFactory().createGPSFixMoving(event.getB());
if (getSimulator() != null) {
getSimulator().scheduleMarkPosition(buoy, markPosition);
getSimulator().scheduleMarkPosition(mark, markPosition);
} else {
trackedRace.recordFix(buoy, markPosition);
trackedRace.recordFix(mark, markPosition);
}
} else {
logger.warning("Couldn't find tracked race for race " + tractracRace.getName()
@@ -8,7 +8,7 @@ import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
@@ -213,18 +213,18 @@ public class Simulator {
}
public void scheduleMarkPosition(final Buoy buoy, GPSFixMoving markFix) {
public void scheduleMarkPosition(final Mark mark, GPSFixMoving markFix) {
final TimePoint transformedTimepoint = advance(markFix.getTimePoint());
final GPSFixMoving transformedMarkFix = new GPSFixMovingImpl(markFix.getPosition(), transformedTimepoint, markFix.getSpeed());
long waitTime = getWaitTimeInMillisUntil(transformedMarkFix.getTimePoint());
if (waitTime <= 0) {
trackedRace.recordFix(buoy, transformedMarkFix);
trackedRace.recordFix(mark, transformedMarkFix);
} else {
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
trackedRace.recordFix(buoy, transformedMarkFix);
trackedRace.recordFix(mark, transformedMarkFix);
} catch (Throwable t) {
logger.throwing(Simulator.class.getName(), "scheduleMarkPosition", t);
}
@@ -23,7 +23,7 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import com.maptrack.client.io.TypeController;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceDefinition;
@@ -247,14 +247,14 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
for (ControlPoint controlPoint : event.getControlPointList()) {
com.sap.sailing.domain.base.ControlPoint domainControlPoint = domainFactory.getOrCreateControlPoint(controlPoint);
boolean first = true;
for (Buoy buoy : domainControlPoint.getBuoys()) {
for (Mark mark : domainControlPoint.getMarks()) {
for (RaceDefinition raceDefinition : raceDefinitions) {
DynamicTrackedRace trackedRace = getTrackedRegatta().getExistingTrackedRace(
raceDefinition);
if (trackedRace != null) {
DynamicGPSFixTrack<Buoy, GPSFix> buoyTrack = trackedRace.getOrCreateTrack(buoy);
if (buoyTrack.getFirstRawFix() == null) {
buoyTrack.addGPSFix(new GPSFixImpl(new DegreePosition(first ? controlPoint
DynamicGPSFixTrack<Mark, GPSFix> markTrack = trackedRace.getOrCreateTrack(mark);
if (markTrack.getFirstRawFix() == null) {
markTrack.addGPSFix(new GPSFixImpl(new DegreePosition(first ? controlPoint
.getLat1() : controlPoint.getLat2(), first ? controlPoint.getLon1()
: controlPoint.getLon2()), MillisecondsTimePoint.now()));
}
@@ -3,5 +3,5 @@ package com.sap.sailing.domain.base;
import com.sap.sailing.domain.common.Named;
public interface ControlPoint extends Named {
Iterable<Buoy> getBuoys();
Iterable<Mark> getMarks();
}
@@ -76,6 +76,6 @@ public interface Course extends Named {
*/
void update(List<ControlPoint> newControlPoints, DomainFactory baseDomainFactory) throws PatchFailedException;
Iterable<Leg> getLegsAdjacentTo(Buoy buoy);
Iterable<Leg> getLegsAdjacentTo(Mark mark);
}
@@ -19,16 +19,16 @@ public interface DomainFactory {
*/
Nationality getOrCreateNationality(String threeLetterIOCCode);
Buoy getOrCreateBuoy(String id);
Mark getOrCreateMark(String id);
/**
* If the buoy with ID <code>id</code> already exists, it is returned. Its color may differ from <code>color</code>
* in that case. Otherwise, a new {@link Buoy} is created with <code>color</code> as its {@link Buoy#getColor()}
* and <code>shape</code> as its {@link Buoy#getShape()}.
* If the single mark with ID <code>id</code> already exists, it is returned. Its color may differ from <code>color</code>
* in that case. Otherwise, a new {@link Mark} is created with <code>color</code> as its {@link Mark#getColor()}
* and <code>shape</code> as its {@link Mark#getShape()}.
*/
Buoy getOrCreateBuoy(String id, String color, String shape, String pattern);
Mark getOrCreateMark(String id, String color, String shape, String pattern);
Gate createGate(Buoy left, Buoy right, String name);
Gate createGate(Mark left, Mark right, String name);
/**
* The waypoint created is weakly cached so that when requested again by
@@ -1,7 +1,7 @@
package com.sap.sailing.domain.base;
public interface Gate extends ControlPoint {
Buoy getLeft();
Mark getLeft();
Buoy getRight();
Mark getRight();
}
@@ -2,13 +2,13 @@ package com.sap.sailing.domain.base;
/**
* A buoy's name is used as its ID which is only identifying the buoy uniquely within a single race or course
* A marks name is used as its ID which is only identifying the mark uniquely within a single race or course
* definition.
*
* @author Axel Uhl (D043530)
*
*/
public interface Buoy extends WithID, ControlPoint, IsManagedByDomainFactory {
public interface Mark extends WithID, ControlPoint, IsManagedByDomainFactory {
public String getColor();
public String getShape();
public String getPattern();
@@ -1,10 +1,11 @@
package com.sap.sailing.domain.base;
import com.sap.sailing.domain.common.Named;
import com.sap.sailing.domain.common.NauticSide;
/**
* Waypoints constitute {@link Course}s and demarcate their {@link Leg}s. A waypoint's position is defined by a
* {@link ControlPoint}, such as a {@link Buoy} or a {@link Gate}. The same control point can be used by multiple
* {@link ControlPoint}, such as a {@link Mark} or a {@link Gate}. The same control point can be used by multiple
* waypoints.<p>
*
* @author Axel Uhl (d043530)
@@ -13,5 +14,11 @@ import com.sap.sailing.domain.common.Named;
public interface Waypoint extends Named, WithID, IsManagedByDomainFactory {
ControlPoint getControlPoint();
Iterable<Buoy> getBuoys();
Iterable<Mark> getMarks();
/**
* Return the passing side for the waypoint. Null is allowed e.g. when the waypoint is a gate.
* @return
*/
NauticSide getPassingSide();
}
@@ -14,7 +14,7 @@ import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.CourseListener;
@@ -273,12 +273,12 @@ public class CourseImpl extends NamedImpl implements Course {
}
}
private ControlPoint getControlPointForBuoy(Buoy buoy) {
private ControlPoint getControlPointForMark(Mark mark) {
lockForRead();
try {
for (ControlPoint controlPoint : getControlPoints()) {
for (Buoy controlPointBuoy : controlPoint.getBuoys()) {
if (buoy == controlPointBuoy) {
for (Mark controlPointMark : controlPoint.getMarks()) {
if (mark == controlPointMark) {
return controlPoint;
}
}
@@ -290,21 +290,21 @@ public class CourseImpl extends NamedImpl implements Course {
}
@Override
public Iterable<Leg> getLegsAdjacentTo(Buoy buoy) {
public Iterable<Leg> getLegsAdjacentTo(Mark mark) {
lockForRead();
try {
Set<Leg> result = new HashSet<Leg>();
ControlPoint controlPointForBuoy = getControlPointForBuoy(buoy);
if (controlPointForBuoy != null) {
ControlPoint controlPointForMark = getControlPointForMark(mark);
if (controlPointForMark != null) {
boolean first = true;
for (Leg leg : getLegs()) {
if (first) {
if (leg.getFrom().getControlPoint() == controlPointForBuoy) {
if (leg.getFrom().getControlPoint() == controlPointForMark) {
result.add(leg);
}
first = false;
}
if (leg.getTo().getControlPoint() == controlPointForBuoy) {
if (leg.getTo().getControlPoint() == controlPointForMark) {
result.add(leg);
}
}
@@ -16,7 +16,7 @@ import java.util.concurrent.ConcurrentHashMap;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.DomainFactory;
@@ -42,7 +42,7 @@ public class DomainFactoryImpl implements DomainFactory {
*/
private final Map<String, Nationality> nationalityCache;
private final Map<String, Buoy> buoyCache;
private final Map<String, Mark> markCache;
private final Map<String, BoatClass> boatClassCache;
@@ -85,7 +85,7 @@ public class DomainFactoryImpl implements DomainFactory {
public DomainFactoryImpl() {
waypointCacheReferenceQueue = new ReferenceQueue<Waypoint>();
nationalityCache = new HashMap<String, Nationality>();
buoyCache = new HashMap<String, Buoy>();
markCache = new HashMap<String, Mark>();
boatClassCache = new HashMap<String, BoatClass>();
competitorCache = new HashMap<Serializable, Competitor>();
waypointCache = new ConcurrentHashMap<Serializable, WeakWaypointReference>();
@@ -110,27 +110,27 @@ public class DomainFactoryImpl implements DomainFactory {
* {@link MessageType#RPD RPD} message
*/
@Override
public Buoy getOrCreateBuoy(String id) {
Buoy result = buoyCache.get(id);
public Mark getOrCreateMark(String id) {
Mark result = markCache.get(id);
if (result == null) {
result = new BuoyImpl(id);
buoyCache.put(id, result);
result = new MarkImpl(id);
markCache.put(id, result);
}
return result;
}
@Override
public Buoy getOrCreateBuoy(String id, String color, String shape, String pattern) {
Buoy result = buoyCache.get(id);
public Mark getOrCreateMark(String id, String color, String shape, String pattern) {
Mark result = markCache.get(id);
if (result == null) {
result = new BuoyImpl(id, color, shape, pattern);
buoyCache.put(id, result);
result = new MarkImpl(id, color, shape, pattern);
markCache.put(id, result);
}
return result;
}
@Override
public Gate createGate(Buoy left, Buoy right, String name) {
public Gate createGate(Mark left, Mark right, String name) {
return new GateImpl(left, right, name);
}
@@ -3,16 +3,16 @@ package com.sap.sailing.domain.base.impl;
import java.util.ArrayList;
import java.util.Collection;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Gate;
public class GateImpl implements Gate {
private static final long serialVersionUID = 2807354812133070574L;
private final Buoy left;
private final Buoy right;
private final Mark left;
private final Mark right;
private final String name;
public GateImpl(Buoy left, Buoy right, String name) {
public GateImpl(Mark left, Mark right, String name) {
super();
this.left = left;
this.right = right;
@@ -20,12 +20,12 @@ public class GateImpl implements Gate {
}
@Override
public Buoy getLeft() {
public Mark getLeft() {
return left;
}
@Override
public Buoy getRight() {
public Mark getRight() {
return right;
}
@@ -40,8 +40,8 @@ public class GateImpl implements Gate {
}
@Override
public Iterable<Buoy> getBuoys() {
Collection<Buoy> result = new ArrayList<Buoy>(2);
public Iterable<Mark> getMarks() {
Collection<Mark> result = new ArrayList<Mark>(2);
result.add(getLeft());
result.add(getRight());
return result;
@@ -3,39 +3,39 @@ package com.sap.sailing.domain.base.impl;
import java.io.Serializable;
import java.util.Collections;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.common.impl.NamedImpl;
public class BuoyImpl extends NamedImpl implements Buoy {
public class MarkImpl extends NamedImpl implements Mark {
private static final long serialVersionUID = 1900673146064411979L;
private final String color;
private final String shape;
private final String pattern;
public BuoyImpl(String name) {
public MarkImpl(String name) {
super(name);
color = null;
shape = null;
pattern = null;
}
public BuoyImpl(String name, String color) {
public MarkImpl(String name, String color) {
super(name);
this.color = color;
shape = null;
pattern = null;
}
public BuoyImpl(String name, String color, String shape) {
public MarkImpl(String name, String color, String shape) {
super(name);
this.color = color;
this.shape = shape;
pattern = null;
}
public BuoyImpl(String name, String color, String shape, String pattern) {
public MarkImpl(String name, String color, String shape, String pattern) {
super(name);
this.color = color;
this.shape = shape;
@@ -49,14 +49,14 @@ public class BuoyImpl extends NamedImpl implements Buoy {
@SuppressWarnings("unchecked")
@Override
public Iterable<Buoy> getBuoys() {
Iterable<? extends Buoy> result = Collections.singleton(this);
return (Iterable<Buoy>) result;
public Iterable<Mark> getMarks() {
Iterable<? extends Mark> result = Collections.singleton(this);
return (Iterable<Mark>) result;
}
@Override
public Buoy resolve(DomainFactory domainFactory) {
Buoy result = domainFactory.getOrCreateBuoy(getName(), color, shape, pattern);
public Mark resolve(DomainFactory domainFactory) {
Mark result = domainFactory.getOrCreateMark(getName(), color, shape, pattern);
return result;
}
@@ -1,21 +1,28 @@
package com.sap.sailing.domain.base.impl;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.NauticSide;
public class WaypointImpl implements Waypoint {
private static final long serialVersionUID = 1600863368078653897L;
private final ControlPoint controlPoint;
private static int idCounter = 1;
private final int id;
private final NauticSide passingSide;
public WaypointImpl(ControlPoint controlPoint) {
this(controlPoint, null);
}
public WaypointImpl(ControlPoint controlPoint, NauticSide passingSide) {
this.controlPoint = controlPoint;
this.passingSide = passingSide;
id = idCounter++;
}
@Override
public ControlPoint getControlPoint() {
return controlPoint;
@@ -32,8 +39,8 @@ public class WaypointImpl implements Waypoint {
}
@Override
public Iterable<Buoy> getBuoys() {
return getControlPoint().getBuoys();
public Iterable<Mark> getMarks() {
return getControlPoint().getMarks();
}
@Override
@@ -45,5 +52,10 @@ public class WaypointImpl implements Waypoint {
public Waypoint resolve(DomainFactory domainFactory) {
return domainFactory.getExistingWaypointByIdOrCache(this);
}
@Override
public NauticSide getPassingSide() {
return passingSide;
}
}
@@ -1,7 +0,0 @@
package com.sap.sailing.domain.tracking;
import com.sap.sailing.domain.base.Buoy;
public interface BuoyGPSFix extends GPSFixMoving {
Buoy getBuoy();
}
@@ -1,6 +1,6 @@
package com.sap.sailing.domain.tracking;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.WindSource;
@@ -8,7 +8,7 @@ import com.sap.sailing.domain.common.WindSource;
public interface DynamicTrackedRace extends TrackedRace {
void recordFix(Competitor competitor, GPSFixMoving fix);
void recordFix(Buoy buoy, GPSFix fix);
void recordFix(Mark mark, GPSFix fix);
void recordWind(Wind wind, WindSource windSource);
@@ -20,10 +20,10 @@ public interface DynamicTrackedRace extends TrackedRace {
DynamicGPSFixTrack<Competitor, GPSFixMoving> getTrack(Competitor competitor);
/**
* Yields the track describing <code>buoy</code>'s movement over time; never <code>null</code> because a
* new track will be created in case no track was present for <code>buoy</code> so far.
* Yields the track describing <code>mark</code>'s movement over time; never <code>null</code> because a
* new track will be created in case no track was present for <code>mark</code> so far.
*/
DynamicGPSFixTrack<Buoy, GPSFix> getOrCreateTrack(Buoy buoy);
DynamicGPSFixTrack<Mark, GPSFix> getOrCreateTrack(Mark mark);
/**
* Updates all mark passings for <code>competitor</code> for this race. The
@@ -0,0 +1,7 @@
package com.sap.sailing.domain.tracking;
import com.sap.sailing.domain.base.Mark;
public interface MarkGPSFix extends GPSFixMoving {
Mark getMark();
}
@@ -2,7 +2,7 @@ package com.sap.sailing.domain.tracking;
import java.util.Map;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.TimePoint;
@@ -12,7 +12,7 @@ import com.sap.sailing.domain.common.WindSource;
public interface RaceChangeListener {
void competitorPositionChanged(GPSFixMoving fix, Competitor competitor);
void buoyPositionChanged(GPSFix fix, Buoy buoy);
void markPositionChanged(GPSFix fix, Mark mark);
/**
* Invoked after the mark passings have been updated in the {@link TrackedRace}.
@@ -174,9 +174,9 @@ public interface TrackedLegOfCompetitor extends Serializable {
/**
* If the current {@link #getLeg() leg} is +/- {@link TrackedLegImpl#UPWIND_DOWNWIND_TOLERANCE_IN_DEG} degrees
* co-linear with the wind's bearing, the competitor's position is projected onto the line crossing
* <code>buoy</code> in the wind's bearing, and the distance from the projection to the <code>buoy</code> is
* <code>mark</code> in the wind's bearing, and the distance from the projection to the <code>mark</code> is
* returned. Otherwise, it is assumed that the leg is neither an upwind nor a downwind leg, and hence the along-track
* distance to <code>buoy</code> is returned.
* distance to <code>mark</code> is returned.
*
* @param at
* the wind estimation is performed for this point in time
@@ -5,7 +5,7 @@ import java.util.List;
import java.util.NavigableSet;
import java.util.SortedSet;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Leg;
@@ -185,19 +185,19 @@ public interface TrackedRace extends Serializable {
MarkPassing getMarkPassing(Competitor competitor, Waypoint waypoint);
/**
* Yields the track describing <code>buoy</code>'s movement over time; never <code>null</code> because a
* new track will be created in case no track was present for <code>buoy</code> so far.
* Yields the track describing <code>mark</code>'s movement over time; never <code>null</code> because a
* new track will be created in case no track was present for <code>mark</code> so far.
*/
GPSFixTrack<Buoy, GPSFix> getOrCreateTrack(Buoy buoy);
GPSFixTrack<Mark, GPSFix> getOrCreateTrack(Mark mark);
/**
* Retrieves all buoys assigned to the race. They are not necessarily part of the race course.
* Retrieves all marks assigned to the race. They are not necessarily part of the race course.
*/
Iterable<Buoy> getBuoys();
Iterable<Mark> getMarks();
/**
* If the <code>waypoint</code> only has one {@link #getBuoys() buoy}, its position at time <code>timePoint</code>
* is returned. Otherwise, the center of gravity between the buoys' positions is computed and returned.
* If the <code>waypoint</code> only has one {@link #getMarks() mark}, its position at time <code>timePoint</code>
* is returned. Otherwise, the center of gravity between the mark positions is computed and returned.
*/
Position getApproximatePosition(Waypoint waypoint, TimePoint timePoint);
@@ -2,7 +2,7 @@ package com.sap.sailing.domain.tracking.impl;
import java.util.Map;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.TimePoint;
@@ -24,7 +24,7 @@ public abstract class AbstractRaceChangeListener implements RaceChangeListener {
}
@Override
public void buoyPositionChanged(GPSFix fix, Buoy buoy) {
public void markPositionChanged(GPSFix fix, Mark mark) {
}
@Override
@@ -6,7 +6,7 @@ import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Timed;
@@ -31,7 +31,7 @@ import com.sap.sailing.util.impl.SmartFutureCache.UpdateInterval;
/**
* (Re-)computing the cross track error for a competitor causes significant amounts of CPU cycles. The cross track error
* is aggregated for each competitor per race and per leg. The calculation uses the same base data and can be combined.
* The results can be cached. Cache invalidation becomes necessary as mark passings, buoy positions and boat positions
* The results can be cached. Cache invalidation becomes necessary as mark passings, mark positions and boat positions
* change. For this purpose, this cache subscribes itself as a listener to the {@link TrackedRace} to which it belongs
* and manages cache invalidations autonomously.
*
@@ -324,8 +324,8 @@ public class CrossTrackErrorCache extends AbstractRaceChangeListener {
}
@Override
public void buoyPositionChanged(GPSFix fix, Buoy buoy) {
TimePoint from = owner.getOrCreateTrack(buoy).getEstimatedPositionTimePeriodAffectedBy(fix).getA();
public void markPositionChanged(GPSFix fix, Mark mark) {
TimePoint from = owner.getOrCreateTrack(mark).getEstimatedPositionTimePeriodAffectedBy(fix).getA();
for (Competitor competitor : cachePerCompetitor.keySet()) {
invalidate(competitor, from);
}
@@ -14,7 +14,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.RaceDefinition;
@@ -103,8 +103,8 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
}
@Override
public void recordFix(Buoy buoy, GPSFix fix) {
getOrCreateTrack(buoy).addGPSFix(fix);
public void recordFix(Mark mark, GPSFix fix) {
getOrCreateTrack(mark).addGPSFix(fix);
}
@Override
@@ -114,8 +114,8 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
getTrack(competitor).setMillisecondsOverWhichToAverage(millisecondsOverWhichToAverageSpeed);
}
for (Waypoint waypoint : getRace().getCourse().getWaypoints()) {
for (Buoy buoy : waypoint.getBuoys()) {
getOrCreateTrack(buoy).setMillisecondsOverWhichToAverage(millisecondsOverWhichToAverageSpeed);
for (Mark mark : waypoint.getMarks()) {
getOrCreateTrack(mark).setMillisecondsOverWhichToAverage(millisecondsOverWhichToAverageSpeed);
}
}
updated(/* time point */null);
@@ -155,25 +155,25 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
}
@Override
public DynamicGPSFixTrack<Buoy, GPSFix> getOrCreateTrack(Buoy buoy) {
return (DynamicGPSFixTrack<Buoy, GPSFix>) super.getOrCreateTrack(buoy);
public DynamicGPSFixTrack<Mark, GPSFix> getOrCreateTrack(Mark mark) {
return (DynamicGPSFixTrack<Mark, GPSFix>) super.getOrCreateTrack(mark);
}
@Override
protected DynamicGPSFixTrackImpl<Buoy> createBuoyTrack(Buoy buoy) {
DynamicGPSFixTrackImpl<Buoy> result = super.createBuoyTrack(buoy);
result.addListener(new GPSTrackListener<Buoy, GPSFix>() {
protected DynamicGPSFixTrackImpl<Mark> createMarkTrack(Mark mark) {
DynamicGPSFixTrackImpl<Mark> result = super.createMarkTrack(mark);
result.addListener(new GPSTrackListener<Mark, GPSFix>() {
private static final long serialVersionUID = -2855787105725103732L;
@Override
public void gpsFixReceived(GPSFix fix, Buoy buoy) {
notifyListeners(fix, buoy);
public void gpsFixReceived(GPSFix fix, Mark mark) {
notifyListeners(fix, mark);
}
@Override
public void speedAveragingChanged(long oldMillisecondsOverWhichToAverage,
long newMillisecondsOverWhichToAverage) {
// nobody can currently listen for the change of the buoy speed averaging because buoy speed is not a value used
// nobody can currently listen for the change of the mark speed averaging because mark speed is not a value used
}
@Override
@@ -246,14 +246,14 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
}
}
private void notifyListeners(GPSFix fix, Buoy buoy) {
private void notifyListeners(GPSFix fix, Mark mark) {
RaceChangeListener[] listeners;
synchronized (getListeners()) {
listeners = getListeners().toArray(new RaceChangeListener[getListeners().size()]);
}
for (RaceChangeListener listener : listeners) {
try {
listener.buoyPositionChanged(fix, buoy);
listener.markPositionChanged(fix, mark);
} catch (Throwable t) {
logger.log(Level.SEVERE, "RaceChangeListener " + listener + " threw exception " + t.getMessage());
logger.throwing(DynamicTrackedRaceImpl.class.getName(), "notifyListeners(GPSFix, Competitor)", t);
@@ -13,7 +13,7 @@ import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.base.Waypoint;
@@ -534,11 +534,11 @@ public class TrackBasedEstimationWindTrackImpl extends VirtualWindTrackImpl impl
}
@Override
public void buoyPositionChanged(GPSFix fix, Buoy buoy) {
public void markPositionChanged(GPSFix fix, Mark mark) {
assert fix != null && fix.getTimePoint() != null;
// A buoy position change can mean a leg type change. The interval over which the wind estimation is affected
// depends on how the GPS track computes the estimated buoy position. Ask it:
Pair<TimePoint, TimePoint> interval = getTrackedRace().getOrCreateTrack(buoy).getEstimatedPositionTimePeriodAffectedBy(fix);
// A mark position change can mean a leg type change. The interval over which the wind estimation is affected
// depends on how the GPS track computes the estimated mark position. Ask it:
Pair<TimePoint, TimePoint> interval = getTrackedRace().getOrCreateTrack(mark).getEstimatedPositionTimePeriodAffectedBy(fix);
WindWithConfidence<TimePoint> startOfInvalidation = getDummyFixWithConfidence(interval.getA());
TimePoint endOfInvalidation = interval.getB();
scheduleCacheRefresh(startOfInvalidation, endOfInvalidation);
@@ -8,7 +8,7 @@ import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Waypoint;
@@ -156,9 +156,9 @@ public class TrackedLegImpl implements TrackedLeg, RaceChangeListener {
@Override
public Bearing getLegBearing(TimePoint at) {
Position startBuoyPos = getTrackedRace().getApproximatePosition(getLeg().getFrom(), at);
Position endBuoyPos = getTrackedRace().getApproximatePosition(getLeg().getTo(), at);
Bearing legBearing = (startBuoyPos != null && endBuoyPos != null) ? startBuoyPos.getBearingGreatCircle(endBuoyPos) : null;
Position startMarkPos = getTrackedRace().getApproximatePosition(getLeg().getFrom(), at);
Position endMarkPos = getTrackedRace().getApproximatePosition(getLeg().getTo(), at);
Bearing legBearing = (startMarkPos != null && endMarkPos != null) ? startMarkPos.getBearingGreatCircle(endMarkPos) : null;
return legBearing;
}
@@ -170,9 +170,9 @@ public class TrackedLegImpl implements TrackedLeg, RaceChangeListener {
private Wind getWindOnLeg(TimePoint at) {
Wind wind;
Position approximateLegStartPosition = getTrackedRace().getOrCreateTrack(
getLeg().getFrom().getBuoys().iterator().next()).getEstimatedPosition(at, false);
getLeg().getFrom().getMarks().iterator().next()).getEstimatedPosition(at, false);
Position approximateLegEndPosition = getTrackedRace().getOrCreateTrack(
getLeg().getTo().getBuoys().iterator().next()).getEstimatedPosition(at, false);
getLeg().getTo().getMarks().iterator().next()).getEstimatedPosition(at, false);
if (approximateLegStartPosition == null || approximateLegEndPosition == null) {
wind = null;
} else {
@@ -217,7 +217,7 @@ public class TrackedLegImpl implements TrackedLeg, RaceChangeListener {
}
@Override
public void buoyPositionChanged(GPSFix fix, Buoy buoy) {
public void markPositionChanged(GPSFix fix, Mark mark) {
clearCaches();
}
@@ -3,7 +3,7 @@ package com.sap.sailing.domain.tracking.impl;
import java.util.Iterator;
import java.util.List;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.SpeedWithBearing;
@@ -166,8 +166,8 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
return Distance.NULL;
} else {
Distance result = null;
for (Buoy buoy : getLeg().getTo().getBuoys()) {
Distance d = getWindwardDistanceTo(buoy, timePoint);
for (Mark mark : getLeg().getTo().getMarks()) {
Distance d = getWindwardDistanceTo(mark, timePoint);
if (result == null || d != null && d.compareTo(result) < 0) {
result = d;
}
@@ -178,29 +178,29 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
/**
* If the current {@link #getLeg() leg} is +/- {@link #UPWIND_DOWNWIND_TOLERANCE_IN_DEG} degrees collinear with the
* wind's bearing, the competitor's position is projected onto the line crossing <code>buoy</code> in the wind's
* bearing, and the distance from the projection to the <code>buoy</code> is returned. Otherwise, it is assumed that
* the leg is neither an upwind nor a downwind leg, and hence the true distance to <code>buoy</code> is returned.
* wind's bearing, the competitor's position is projected onto the line crossing <code>mark</code> in the wind's
* bearing, and the distance from the projection to the <code>mark</code> is returned. Otherwise, it is assumed that
* the leg is neither an upwind nor a downwind leg, and hence the true distance to <code>mark</code> is returned.
*/
private Distance getWindwardDistanceTo(Buoy buoy, TimePoint at) throws NoWindException {
private Distance getWindwardDistanceTo(Mark mark, TimePoint at) throws NoWindException {
Position estimatedPosition = getTrackedRace().getTrack(getCompetitor()).getEstimatedPosition(at, false);
if (!hasStartedLeg(at) || estimatedPosition == null) {
// covers the case with no fixes for this leg yet, also if the mark passing has already been received
estimatedPosition = getTrackedRace().getOrCreateTrack(getLeg().getFrom().getBuoys().iterator().next())
estimatedPosition = getTrackedRace().getOrCreateTrack(getLeg().getFrom().getMarks().iterator().next())
.getEstimatedPosition(at, false);
}
if (estimatedPosition == null) { // may happen if mark positions haven't been received yet
return null;
}
return getWindwardDistance(estimatedPosition, getTrackedRace().getOrCreateTrack(buoy).getEstimatedPosition(at, false),
return getWindwardDistance(estimatedPosition, getTrackedRace().getOrCreateTrack(mark).getEstimatedPosition(at, false),
at);
}
/**
* If the current {@link #getLeg() leg} is +/- {@link TrackedLegImpl#UPWIND_DOWNWIND_TOLERANCE_IN_DEG} degrees collinear with the
* wind's bearing, the competitor's position is projected onto the line crossing <code>buoy</code> in the wind's
* bearing, and the distance from the projection to the <code>buoy</code> is returned. Otherwise, it is assumed that
* the leg is neither an upwind nor a downwind leg, and hence the along-track distance to <code>buoy</code> is returned.
* wind's bearing, the competitor's position is projected onto the line crossing <code>mark</code> in the wind's
* bearing, and the distance from the projection to the <code>mark</code> is returned. Otherwise, it is assumed that
* the leg is neither an upwind nor a downwind leg, and hence the along-track distance to <code>mark</code> is returned.
*
* @param at the wind estimation is performed for this point in time
*/
@@ -29,7 +29,7 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.base.BearingWithConfidence;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.CourseChange;
@@ -108,7 +108,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
private final Set<WindSource> windSourcesToExclude;
/**
* Keeps the oldest timestamp that is fed into this tracked race, either from a boat fix, a buoy fix, a race
* Keeps the oldest timestamp that is fed into this tracked race, either from a boat fix, a mark fix, a race
* start/finish or a course definition.
*/
private TimePoint timePointOfOldestEvent;
@@ -195,11 +195,11 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
private transient Map<TimePoint, Future<Wind>> directionFromStartToNextMarkCache;
private final ConcurrentHashMap<Buoy, GPSFixTrack<Buoy, GPSFix>> buoyTracks;
private final ConcurrentHashMap<Mark, GPSFixTrack<Mark, GPSFix>> markTracks;
protected long millisecondsOverWhichToAverageSpeed;
private final Map<Buoy, StartToNextMarkCacheInvalidationListener> startToNextMarkCacheInvalidationListeners;
private final Map<Mark, StartToNextMarkCacheInvalidationListener> startToNextMarkCacheInvalidationListeners;
protected long millisecondsOverWhichToAverageWind;
@@ -251,18 +251,18 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
this.millisecondsOverWhichToAverageSpeed = millisecondsOverWhichToAverageSpeed;
this.millisecondsOverWhichToAverageWind = millisecondsOverWhichToAverageWind;
this.delayToLiveInMillis = delayToLiveInMillis;
this.startToNextMarkCacheInvalidationListeners = new ConcurrentHashMap<Buoy, TrackedRaceImpl.StartToNextMarkCacheInvalidationListener>();
this.startToNextMarkCacheInvalidationListeners = new ConcurrentHashMap<Mark, TrackedRaceImpl.StartToNextMarkCacheInvalidationListener>();
this.maneuverCache = createManeuverCache();
this.buoyTracks = new ConcurrentHashMap<Buoy, GPSFixTrack<Buoy, GPSFix>>();
this.markTracks = new ConcurrentHashMap<Mark, GPSFixTrack<Mark, GPSFix>>();
this.crossTrackErrorCache = new CrossTrackErrorCache(this);
int i = 0;
for (Waypoint waypoint : race.getCourse().getWaypoints()) {
for (Buoy buoy : waypoint.getBuoys()) {
getOrCreateTrack(buoy);
for (Mark mark : waypoint.getMarks()) {
getOrCreateTrack(mark);
if (i < 2) {
// add cache invalidation listeners for first and second waypoint's buoys for
// add cache invalidation listeners for first and second waypoint's marks for
// directionFromStartToNextMarkCache
addStartToNextMarkCacheInvalidationListener(buoy);
addStartToNextMarkCacheInvalidationListener(mark);
}
}
i++;
@@ -954,25 +954,25 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
}
/**
* This method was a synchronization bottleneck when it was using a regular HashMap for {@link #buoyTracks}.
* It is frequently used, and the most frequent case is that the <code>get</code> call on {@link #buoyTracks}
* succeeds with a non-<code>null</code> result. To improve performance for this case, {@link #buoyTracks} now is
* This method was a synchronization bottleneck when it was using a regular HashMap for {@link #markTracks}.
* It is frequently used, and the most frequent case is that the <code>get</code> call on {@link #markTracks}
* succeeds with a non-<code>null</code> result. To improve performance for this case, {@link #markTracks} now is
* a {@link ConcurrentHashMap} that can be read while writes are going on without locking or synchronization.
* Only if the <code>get</code> call does not provide a result, the entire procedure is repeated, this time with
* synchronization to avoid duplicate track creation for the same buoy.
* synchronization to avoid duplicate track creation for the same mark.
*/
@Override
public GPSFixTrack<Buoy, GPSFix> getOrCreateTrack(Buoy buoy) {
GPSFixTrack<Buoy, GPSFix> result = buoyTracks.get(buoy);
public GPSFixTrack<Mark, GPSFix> getOrCreateTrack(Mark mark) {
GPSFixTrack<Mark, GPSFix> result = markTracks.get(mark);
if (result == null) {
// try again, this time with more expensive synchronization
synchronized (buoyTracks) {
synchronized (markTracks) {
LockUtil.lockForRead(serializationLock);
try {
result = buoyTracks.get(buoy);
result = markTracks.get(mark);
if (result == null) {
result = createBuoyTrack(buoy);
buoyTracks.put(buoy, result);
result = createMarkTrack(mark);
markTracks.put(mark, result);
}
} finally {
LockUtil.unlockAfterRead(serializationLock);
@@ -982,15 +982,15 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
return result;
}
protected DynamicGPSFixTrackImpl<Buoy> createBuoyTrack(Buoy buoy) {
return new DynamicGPSFixTrackImpl<Buoy>(buoy, millisecondsOverWhichToAverageSpeed);
protected DynamicGPSFixTrackImpl<Mark> createMarkTrack(Mark mark) {
return new DynamicGPSFixTrackImpl<Mark>(mark, millisecondsOverWhichToAverageSpeed);
}
@Override
public Position getApproximatePosition(Waypoint waypoint, TimePoint timePoint) {
Position result = null;
for (Buoy buoy : waypoint.getBuoys()) {
Position nextPos = getOrCreateTrack(buoy).getEstimatedPosition(timePoint, /* extrapolate */false);
for (Mark mark : waypoint.getMarks()) {
Position nextPos = getOrCreateTrack(mark).getEstimatedPosition(timePoint, /* extrapolate */false);
if (result == null) {
result = nextPos;
} else if (nextPos != null) {
@@ -1289,8 +1289,8 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
// assuming that getRace().getCourse()'s write lock is held by the current thread
updateStartToNextMarkCacheInvalidationCacheListenersAfterWaypointAdded(zeroBasedIndex, waypointThatGotAdded);
getOrCreateMarkPassingsInOrderAsNavigableSet(waypointThatGotAdded);
for (Buoy buoy : waypointThatGotAdded.getBuoys()) {
getOrCreateTrack(buoy);
for (Mark mark : waypointThatGotAdded.getMarks()) {
getOrCreateTrack(mark);
}
// a waypoint got added; this means that a leg got added as well; but we shouldn't claim we know where
// in the leg list of the course the leg was added; that's an implementation secret of CourseImpl. So try:
@@ -1319,7 +1319,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
private void updateStartToNextMarkCacheInvalidationCacheListenersAfterWaypointAdded(int zeroBasedIndex,
Waypoint waypointThatGotAdded) {
if (zeroBasedIndex < 2) {
// the observing listener on any previous buoy will be GCed; we need to ensure
// the observing listener on any previous mark will be GCed; we need to ensure
// that the cache is recomputed
clearDirectionFromStartToNextMarkCache();
Iterator<Waypoint> waypointsIter = getRace().getCourse().getWaypoints().iterator();
@@ -1342,17 +1342,17 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
}
private void addStartToNextMarkCacheInvalidationListener(Waypoint waypoint) {
for (Buoy buoy : waypoint.getBuoys()) {
addStartToNextMarkCacheInvalidationListener(buoy);
for (Mark mark : waypoint.getMarks()) {
addStartToNextMarkCacheInvalidationListener(mark);
}
}
private void addStartToNextMarkCacheInvalidationListener(Buoy buoy) {
GPSFixTrack<Buoy, GPSFix> track = getOrCreateTrack(buoy);
private void addStartToNextMarkCacheInvalidationListener(Mark mark) {
GPSFixTrack<Mark, GPSFix> track = getOrCreateTrack(mark);
StartToNextMarkCacheInvalidationListener listener = new StartToNextMarkCacheInvalidationListener(track);
LockUtil.lockForRead(serializationLock);
try {
startToNextMarkCacheInvalidationListeners.put(buoy, listener);
startToNextMarkCacheInvalidationListeners.put(mark, listener);
} finally {
LockUtil.unlockAfterRead(serializationLock);
}
@@ -1360,18 +1360,18 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
}
private void stopAndRemoveStartToNextMarkCacheInvalidationListener(Waypoint waypoint) {
for (Buoy buoy : waypoint.getBuoys()) {
stopAndRemoveStartToNextMarkCacheInvalidationListener(buoy);
for (Mark mark : waypoint.getMarks()) {
stopAndRemoveStartToNextMarkCacheInvalidationListener(mark);
}
}
private void stopAndRemoveStartToNextMarkCacheInvalidationListener(Buoy buoy) {
StartToNextMarkCacheInvalidationListener listener = startToNextMarkCacheInvalidationListeners.get(buoy);
private void stopAndRemoveStartToNextMarkCacheInvalidationListener(Mark mark) {
StartToNextMarkCacheInvalidationListener listener = startToNextMarkCacheInvalidationListeners.get(mark);
if (listener != null) {
listener.stopListening();
LockUtil.lockForRead(serializationLock);
try {
startToNextMarkCacheInvalidationListeners.remove(buoy);
startToNextMarkCacheInvalidationListeners.remove(mark);
} finally {
LockUtil.unlockAfterRead(serializationLock);
}
@@ -1424,7 +1424,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
private void updateStartToNextMarkCacheInvalidationCacheListenersAfterWaypointRemoved(int zeroBasedIndex,
Waypoint waypointThatGotRemoved) {
if (zeroBasedIndex < 2) {
// the observing listener on any previous buoy will be GCed; we need to ensure
// the observing listener on any previous mark will be GCed; we need to ensure
// that the cache is recomputed
clearDirectionFromStartToNextMarkCache();
stopAndRemoveStartToNextMarkCacheInvalidationListener(waypointThatGotRemoved);
@@ -1994,11 +1994,11 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
return getRace().getBoatClass().getApproximateManeuverDurationInMilliseconds();
}
private class StartToNextMarkCacheInvalidationListener implements GPSTrackListener<Buoy, GPSFix> {
private class StartToNextMarkCacheInvalidationListener implements GPSTrackListener<Mark, GPSFix> {
private static final long serialVersionUID = 3540278554797445085L;
private final GPSFixTrack<Buoy, GPSFix> listeningTo;
private final GPSFixTrack<Mark, GPSFix> listeningTo;
public StartToNextMarkCacheInvalidationListener(GPSFixTrack<Buoy, GPSFix> listeningTo) {
public StartToNextMarkCacheInvalidationListener(GPSFixTrack<Mark, GPSFix> listeningTo) {
this.listeningTo = listeningTo;
}
@@ -2007,7 +2007,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
}
@Override
public void gpsFixReceived(GPSFix fix, Buoy buoy) {
public void gpsFixReceived(GPSFix fix, Mark mark) {
clearDirectionFromStartToNextMarkCache();
}
@@ -2051,10 +2051,10 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
}
@Override
public Iterable<Buoy> getBuoys() {
public Iterable<Mark> getMarks() {
while (true) {
try {
return new HashSet<Buoy>(buoyTracks.keySet());
return new HashSet<Mark>(markTracks.keySet());
} catch (ConcurrentModificationException cme) {
logger.info("Caught " + cme + "; trying again.");
}
+1 -1
View File
@@ -182,7 +182,7 @@ input.magnifier {
font-weight: 500;
}
.leaderboardGroupPanel-Fleet {
.leaderboardGroupPanel-TableText {
padding: 5px 8px;
display: block;
float: left;
@@ -11,6 +11,7 @@ import java.util.Set;
import com.google.gwt.cell.client.SafeHtmlCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.FontWeight;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.safehtml.shared.SafeHtml;
@@ -22,7 +23,9 @@ import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.MultiSelectionModel;
@@ -36,10 +39,10 @@ import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.BuoyDTO;
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
import com.sap.sailing.gwt.ui.shared.GateDTO;
import com.sap.sailing.gwt.ui.shared.RaceBuoysDTO;
import com.sap.sailing.gwt.ui.shared.MarkDTO;
import com.sap.sailing.gwt.ui.shared.RaceCourseMarksDTO;
/**
* A panel that has a race selection (inherited from {@link AbstractRaceManagementPanel}) and which adds a table
@@ -51,77 +54,77 @@ import com.sap.sailing.gwt.ui.shared.RaceBuoysDTO;
*/
public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
/**
* Represents one buoy assignment for a control point. Gates have multiple such records, one for each of their buoys.
* Represents one mark assignment for a control point. Gates have multiple such records, one for each of their marks.
*
* @author Axel Uhl (D043530)
*/
private static class ControlPointAndOldAndNewBuoy {
private static class ControlPointAndOldAndNewMark {
private final ControlPointDTO controlPoint;
private final BuoyDTO oldBuoy;
private BuoyDTO newBuoy;
public ControlPointAndOldAndNewBuoy(ControlPointDTO controlPoint, BuoyDTO oldBuoy) {
private final MarkDTO oldMark;
private MarkDTO newMark;
public ControlPointAndOldAndNewMark(ControlPointDTO controlPoint, MarkDTO oldMark) {
super();
this.controlPoint = controlPoint;
this.oldBuoy = oldBuoy;
this.newBuoy = oldBuoy;
this.oldMark = oldMark;
this.newMark = oldMark;
}
public BuoyDTO getNewBuoy() {
return newBuoy;
public MarkDTO getNewMark() {
return newMark;
}
public void setNewBuoy(BuoyDTO newBuoy) {
this.newBuoy = newBuoy;
public void setNewMark(MarkDTO newMark) {
this.newMark = newMark;
}
public ControlPointDTO getControlPoint() {
return controlPoint;
}
public BuoyDTO getOldBuoy() {
return oldBuoy;
public MarkDTO getOldMark() {
return oldMark;
}
}
private class ControlPointCreationDialog extends DataEntryDialog<ControlPointDTO> {
private final CellTable<BuoyDTO> buoysTable;
private final MultiSelectionModel<BuoyDTO> selectionModel;
private final CellTable<MarkDTO> marksTable;
private final MultiSelectionModel<MarkDTO> selectionModel;
public ControlPointCreationDialog(final StringMessages stringMessages, AdminConsoleTableResources tableRes,
List<BuoyDTO> buoys, DialogCallback<ControlPointDTO> callback) {
super(stringMessages.controlPoint(), stringMessages.selectOneBuoyOrTwoBuoysForGate(),
List<MarkDTO> marks, DialogCallback<ControlPointDTO> callback) {
super(stringMessages.controlPoint(), stringMessages.selectOneMarkOrTwoMarksForGate(),
stringMessages.ok(), stringMessages.cancel(), new Validator<ControlPointDTO>() {
@Override
public String getErrorMessage(ControlPointDTO valueToValidate) {
if (valueToValidate == null) {
return stringMessages.selectOneBuoyOrTwoBuoysForGate();
return stringMessages.selectOneMarkOrTwoMarksForGate();
} else {
return null;
}
}
}, /* animationEnabled */ false, callback);
selectionModel = new MultiSelectionModel<BuoyDTO>();
selectionModel = new MultiSelectionModel<MarkDTO>();
selectionModel.addSelectionChangeHandler(new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
validate();
}
});
buoysTable = createBuoysTable(stringMessages, tableRes, selectionModel);
ListDataProvider<BuoyDTO> buoyDataProvider = new ListDataProvider<BuoyDTO>();
buoyDataProvider.getList().addAll(buoys);
buoyDataProvider.addDataDisplay(buoysTable);
marksTable = createAvailableMarksTable(stringMessages, tableRes, selectionModel);
ListDataProvider<MarkDTO> markDataProvider = new ListDataProvider<MarkDTO>();
markDataProvider.getList().addAll(marks);
markDataProvider.addDataDisplay(marksTable);
}
@Override
protected ControlPointDTO getResult() {
ControlPointDTO result = null;
Set<BuoyDTO> selection = selectionModel.getSelectedSet();
Set<MarkDTO> selection = selectionModel.getSelectedSet();
if (selection.size() == 1) {
result = selectionModel.getSelectedSet().iterator().next();
} else if (selection.size() == 2) {
Iterator<BuoyDTO> i = selectionModel.getSelectedSet().iterator();
BuoyDTO first = i.next();
BuoyDTO second = i.next();
BuoyDTO left;
BuoyDTO right;
Iterator<MarkDTO> i = selectionModel.getSelectedSet().iterator();
MarkDTO first = i.next();
MarkDTO second = i.next();
MarkDTO left;
MarkDTO right;
String gateName;
if (first.name.toLowerCase().contains("left")) {
left = first;
@@ -138,35 +141,35 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
@Override
protected Widget getAdditionalWidget() {
return buoysTable;
return marksTable;
}
}
private static final String REGEX_FOR_LEFT = "( \\()?[lL][eE][fF][tT]\\)?";
/**
* A table that lists the buoys for which events have been received for the race selected. Note that this list may
* be longer than the list of buoys actually used by the control points backing the course's waypoints because of
* the possibility of spare marks / buoys.
* A table that lists the marks for which events have been received for the race selected. Note that this list may
* be longer than the list of marks actually used by the control points backing the course's waypoints because of
* the possibility of spare marks.
*/
private final CellTable<BuoyDTO> buoysTable;
private final ListDataProvider<BuoyDTO> buoyDataProvider;
private final SingleSelectionModel<BuoyDTO> buoySelectionModel;
private final CellTable<MarkDTO> marksTable;
private final ListDataProvider<MarkDTO> markDataProvider;
private final SingleSelectionModel<MarkDTO> markSelectionModel;
/**
* A table that lists the product of Waypoint x ControlPoint x Buoy plus a hint as to the number of mark passings.
* A table that lists the product of Waypoint x ControlPoint x Mark plus a hint as to the number of mark passings.
* The (multi-)selection on this table can be used as either a selection of waypoints or a selection of control points
* or a selection of buoys.
* or a selection of marks.
*/
private final CellTable<ControlPointAndOldAndNewBuoy> controlPointsTable;
private final MultiSelectionModel<ControlPointAndOldAndNewBuoy> controlPointsSelectionModel;
private final ListDataProvider<ControlPointAndOldAndNewBuoy> controlPointDataProvider;
private final CellTable<ControlPointAndOldAndNewMark> controlPointsTable;
private final MultiSelectionModel<ControlPointAndOldAndNewMark> controlPointsSelectionModel;
private final ListDataProvider<ControlPointAndOldAndNewMark> controlPointDataProvider;
/**
* When for a control point's buoy a replacement buoy is defined (see {@link #updateNewBuoy(Set, BuoyDTO)}),
* When for a control point's mark a replacement mark is defined (see {@link #updateNewMark(Set, MarkDTO)}),
* the control point needs to be replaced before {@link #saveCourse(SailingServiceAsync, StringMessages) saving}.
* Those control points are added to this set. When the buoy is reset to the original buoy for all the control
* point's buoys, the control point is removed from this set again. {@link #saveCourse(SailingServiceAsync, StringMessages)}
* Those control points are added to this set. When the mark is reset to the original mark for all the control
* point's marks, the control point is removed from this set again. {@link #saveCourse(SailingServiceAsync, StringMessages)}
* then is responsible for creating replacement {@link ControlPointDTO}s before sending the new control point list to the
* server.
*/
@@ -174,24 +177,32 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
private final HorizontalPanel courseActionsPanel;
private final Handler buoySelectionChangeHandler;
private final Handler markSelectionChangeHandler;
private final Button insertWaypointBefore;
private final Button insertWaypointAfter;
private final Button removeWaypointBtn;
private boolean ignoreWaypointAndOldAndNewBuoySelectionChange;
private boolean ignoreWaypointAndOldAndNewMarkSelectionChange;
public RaceCourseManagementPanel(final SailingServiceAsync sailingService, ErrorReporter errorReporter,
RegattaRefresher regattaRefresher, final StringMessages stringMessages) {
super(sailingService, errorReporter, regattaRefresher, stringMessages);
controlPointsNeedingReplacement = new HashSet<ControlPointDTO>();
Grid grid = new Grid(1, 2);
grid.setCellPadding(10);
Grid grid = new Grid(2, 2);
grid.setCellPadding(5);
selectedRaceContentPanel.add(grid);
Label currentRaceCourseLabel = new Label("Current race course");
currentRaceCourseLabel.getElement().getStyle().setFontWeight(FontWeight.BOLD);
grid.setWidget(0, 0, currentRaceCourseLabel);
Label availableMarksLabel = new Label("Available marks");
availableMarksLabel.getElement().getStyle().setFontWeight(FontWeight.BOLD);
grid.setWidget(0, 1, availableMarksLabel);
grid.getRowFormatter().setVerticalAlign(1, HasVerticalAlignment.ALIGN_TOP);
final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
controlPointsTable = new CellTable<ControlPointAndOldAndNewBuoy>(/* pageSize */10000, tableRes);
grid.setWidget(0, 0, controlPointsTable);
controlPointsSelectionModel = new MultiSelectionModel<ControlPointAndOldAndNewBuoy>();
controlPointsTable = new CellTable<ControlPointAndOldAndNewMark>(/* pageSize */10000, tableRes);
grid.setWidget(1, 0, controlPointsTable);
controlPointsSelectionModel = new MultiSelectionModel<ControlPointAndOldAndNewMark>();
controlPointsTable.setSelectionModel(controlPointsSelectionModel);
controlPointsSelectionModel.addSelectionChangeHandler(new Handler() {
@Override
@@ -199,45 +210,45 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
handleControlPointSelectionChange();
}
});
TextColumn<ControlPointAndOldAndNewBuoy> nameColumn = new TextColumn<ControlPointAndOldAndNewBuoy>() {
TextColumn<ControlPointAndOldAndNewMark> nameColumn = new TextColumn<ControlPointAndOldAndNewMark>() {
@Override
public String getValue(ControlPointAndOldAndNewBuoy cpaoanb) {
public String getValue(ControlPointAndOldAndNewMark cpaoanb) {
return cpaoanb.getControlPoint().name;
}
};
controlPointsTable.addColumn(nameColumn, stringMessages.controlPoint());
TextColumn<ControlPointAndOldAndNewBuoy> oldBuoyColumn = new TextColumn<ControlPointAndOldAndNewBuoy>() {
TextColumn<ControlPointAndOldAndNewMark> oldMarkColumn = new TextColumn<ControlPointAndOldAndNewMark>() {
@Override
public String getValue(ControlPointAndOldAndNewBuoy cpaoanb) {
return "" + cpaoanb.getOldBuoy().name;
public String getValue(ControlPointAndOldAndNewMark cpaoanb) {
return "" + cpaoanb.getOldMark().name;
}
};
controlPointsTable.addColumn(oldBuoyColumn, stringMessages.buoy());
TextColumn<ControlPointAndOldAndNewBuoy> newBuoyColumn = new TextColumn<ControlPointAndOldAndNewBuoy>() {
controlPointsTable.addColumn(oldMarkColumn, stringMessages.mark());
TextColumn<ControlPointAndOldAndNewMark> newMarkColumn = new TextColumn<ControlPointAndOldAndNewMark>() {
@Override
public String getValue(ControlPointAndOldAndNewBuoy cpaoanb) {
return "" + cpaoanb.getNewBuoy().name;
public String getValue(ControlPointAndOldAndNewMark cpaoanb) {
return "" + cpaoanb.getNewMark().name;
}
};
controlPointsTable.addColumn(newBuoyColumn, stringMessages.newBuoy());
controlPointDataProvider = new ListDataProvider<ControlPointAndOldAndNewBuoy>();
controlPointsTable.addColumn(newMarkColumn, stringMessages.newMark());
controlPointDataProvider = new ListDataProvider<ControlPointAndOldAndNewMark>();
controlPointDataProvider.addDataDisplay(controlPointsTable);
// race buoys table
buoyDataProvider = new ListDataProvider<BuoyDTO>();
buoySelectionChangeHandler = new Handler() {
// race course marks table
markDataProvider = new ListDataProvider<MarkDTO>();
markSelectionChangeHandler = new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
if (!ignoreWaypointAndOldAndNewBuoySelectionChange) {
updateNewBuoy(controlPointsSelectionModel.getSelectedSet(), buoySelectionModel.getSelectedObject());
if (!ignoreWaypointAndOldAndNewMarkSelectionChange) {
updateNewMark(controlPointsSelectionModel.getSelectedSet(), markSelectionModel.getSelectedObject());
}
}
};
buoySelectionModel = new SingleSelectionModel<BuoyDTO>();
buoysTable = createBuoysTable(stringMessages, tableRes, buoySelectionModel);
buoysTable.getSelectionModel().addSelectionChangeHandler(buoySelectionChangeHandler);
buoyDataProvider.addDataDisplay(buoysTable);
grid.setWidget(0, 1, buoysTable);
markSelectionModel = new SingleSelectionModel<MarkDTO>();
marksTable = createAvailableMarksTable(stringMessages, tableRes, markSelectionModel);
marksTable.getSelectionModel().addSelectionChangeHandler(markSelectionChangeHandler);
markDataProvider.addDataDisplay(marksTable);
grid.setWidget(1, 1, marksTable);
courseActionsPanel = new HorizontalPanel();
courseActionsPanel.setSpacing(10);
@@ -274,7 +285,7 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
refreshBtn.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
refreshSelectedRaceData();
refreshSelectedRaceData ();
}
});
courseActionsPanel.add(refreshBtn);
@@ -291,32 +302,32 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
}
private void handleControlPointSelectionChange() {
ignoreWaypointAndOldAndNewBuoySelectionChange = true;
ignoreWaypointAndOldAndNewMarkSelectionChange = true;
try {
buoySelectionModel.setSelected(buoySelectionModel.getSelectedObject(), false);
markSelectionModel.setSelected(markSelectionModel.getSelectedObject(), false);
final int selectionSize = controlPointsSelectionModel.getSelectedSet().size();
insertWaypointAfter.setEnabled(selectionSize==1);
insertWaypointBefore.setEnabled(selectionSize==1);
removeWaypointBtn.setEnabled(selectionSize>=1);
if (selectionSize == 1) {
BuoyDTO newBuoy = controlPointsSelectionModel.getSelectedSet().iterator().next().getNewBuoy();
if (newBuoy != null) {
for (BuoyDTO buoyDTO : buoyDataProvider.getList()) {
if (buoyDTO.name.equals(newBuoy.name)) {
buoySelectionModel.setSelected(buoyDTO, true);
MarkDTO newMark = controlPointsSelectionModel.getSelectedSet().iterator().next().getNewMark();
if (newMark != null) {
for (MarkDTO markDTO : markDataProvider.getList()) {
if (markDTO.name.equals(newMark.name)) {
markSelectionModel.setSelected(markDTO, true);
}
}
}
}
} finally {
ignoreWaypointAndOldAndNewBuoySelectionChange = false;
ignoreWaypointAndOldAndNewMarkSelectionChange = false;
}
}
private void saveCourse(SailingServiceAsync sailingService, final StringMessages stringMessages) {
Set<ControlPointDTO> oldControlPointsFromTableAlreadyHandled = new HashSet<ControlPointDTO>();
List<ControlPointDTO> controlPoints = new ArrayList<ControlPointDTO>();
for (ControlPointAndOldAndNewBuoy cpaoanb : controlPointDataProvider.getList()) {
for (ControlPointAndOldAndNewMark cpaoanb : controlPointDataProvider.getList()) {
if (!oldControlPointsFromTableAlreadyHandled.contains(cpaoanb.getControlPoint())) {
oldControlPointsFromTableAlreadyHandled.add(cpaoanb.getControlPoint());
ControlPointDTO controlPointToAdd;
@@ -324,7 +335,7 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
if (cpaoanb.getControlPoint() instanceof GateDTO) {
controlPointToAdd = createGate((GateDTO) cpaoanb.getControlPoint());
} else {
controlPointToAdd = cpaoanb.getNewBuoy();
controlPointToAdd = cpaoanb.getNewMark();
}
} else {
controlPointToAdd = cpaoanb.getControlPoint();
@@ -348,18 +359,18 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
/**
* When a gate needs replacement, its entries in {@link #controlPointDataProvider} are looked up, and a new
* {@link GateDTO} is created having the same name as the old gate, but using the new buoys as the gate's buoys.
* {@link GateDTO} is created having the same name as the old gate, but using the new marks as the gate's marks.
*/
private ControlPointDTO createGate(GateDTO oldGate) {
BuoyDTO newLeft = null;
BuoyDTO newRight = null;
for (ControlPointAndOldAndNewBuoy cpaoanb : controlPointDataProvider.getList()) {
MarkDTO newLeft = null;
MarkDTO newRight = null;
for (ControlPointAndOldAndNewMark cpaoanb : controlPointDataProvider.getList()) {
if (cpaoanb.getControlPoint() == oldGate) {
BuoyDTO newBuoy = cpaoanb.getNewBuoy();
if (newRight != null || newBuoy.name.matches("^.*"+REGEX_FOR_LEFT+".*$")) {
newLeft = newBuoy;
MarkDTO newMark = cpaoanb.getNewMark();
if (newRight != null || newMark.name.matches("^.*"+REGEX_FOR_LEFT+".*$")) {
newLeft = newMark;
} else {
newRight = newBuoy;
newRight = newMark;
}
}
}
@@ -367,50 +378,66 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
return new GateDTO(oldGate.name, newLeft, newRight);
}
private CellTable<BuoyDTO> createBuoysTable(final StringMessages stringMessages, AdminConsoleTableResources tableRes,
SelectionModel<BuoyDTO> selectionModel) {
CellTable<BuoyDTO> result = new CellTable<BuoyDTO>(/* pageSize */10000, tableRes);
private CellTable<MarkDTO> createAvailableMarksTable(final StringMessages stringMessages, AdminConsoleTableResources tableRes,
SelectionModel<MarkDTO> selectionModel) {
CellTable<MarkDTO> result = new CellTable<MarkDTO>(/* pageSize */10000, tableRes);
result.setSelectionModel(selectionModel);
TextColumn<BuoyDTO> buoyNameColumn = new TextColumn<BuoyDTO>() {
TextColumn<MarkDTO> markNameColumn = new TextColumn<MarkDTO>() {
@Override
public String getValue(BuoyDTO buoyDTO) {
return buoyDTO.name;
public String getValue(MarkDTO markDTO) {
return markDTO.name;
}
};
result.addColumn(buoyNameColumn, stringMessages.buoy());
result.addColumn(markNameColumn, stringMessages.mark());
final SafeHtmlCell buoyPositionCell = new SafeHtmlCell();
Column<BuoyDTO, SafeHtml> buoyPositionColumn = new Column<BuoyDTO, SafeHtml>(buoyPositionCell) {
final SafeHtmlCell markPositionCell = new SafeHtmlCell();
Column<MarkDTO, SafeHtml> markPositionColumn = new Column<MarkDTO, SafeHtml>(markPositionCell) {
@Override
public SafeHtml getValue(BuoyDTO buoy) {
public SafeHtml getValue(MarkDTO mark) {
SafeHtmlBuilder builder = new SafeHtmlBuilder();
builder.appendEscaped(buoy.position.toFormattedString());
builder.appendEscaped(mark.position.toFormattedString());
return builder.toSafeHtml();
}
};
result.addColumn(buoyPositionColumn, stringMessages.position());
result.addColumn(markPositionColumn, stringMessages.position());
TextColumn<BuoyDTO> buoyColorColumn = new TextColumn<BuoyDTO>() {
TextColumn<MarkDTO> markColorColumn = new TextColumn<MarkDTO>() {
@Override
public String getValue(BuoyDTO buoyDTO) {
return buoyDTO.color != null ? buoyDTO.color : "";
public String getValue(MarkDTO markDTO) {
return markDTO.color != null ? markDTO.color : "";
}
};
result.addColumn(buoyColorColumn, stringMessages.color());
result.addColumn(markColorColumn, stringMessages.color());
TextColumn<MarkDTO> markShapeColumn = new TextColumn<MarkDTO>() {
@Override
public String getValue(MarkDTO markDTO) {
return markDTO.shape != null ? markDTO.shape : "";
}
};
result.addColumn(markShapeColumn, stringMessages.shape());
TextColumn<MarkDTO> markPatternColumn = new TextColumn<MarkDTO>() {
@Override
public String getValue(MarkDTO markDTO) {
return markDTO.pattern != null ? markDTO.pattern : "";
}
};
result.addColumn(markPatternColumn, stringMessages.pattern());
return result;
}
private void updateNewBuoy(Set<ControlPointAndOldAndNewBuoy> selectedWaypointsAndOldAndNewBuoys, BuoyDTO selectedNewBuoy) {
if (selectedWaypointsAndOldAndNewBuoys != null) {
for (ControlPointAndOldAndNewBuoy w : selectedWaypointsAndOldAndNewBuoys) {
if (selectedNewBuoy == null) {
w.setNewBuoy(w.getOldBuoy());
private void updateNewMark(Set<ControlPointAndOldAndNewMark> selectedWaypointsAndOldAndNewMarks, MarkDTO selectedNewMark) {
if (selectedWaypointsAndOldAndNewMarks != null) {
for (ControlPointAndOldAndNewMark w : selectedWaypointsAndOldAndNewMarks) {
if (selectedNewMark == null) {
w.setNewMark(w.getOldMark());
} else {
w.setNewBuoy(selectedNewBuoy);
w.setNewMark(selectedNewMark);
}
if (w.getOldBuoy().name.equals(w.getNewBuoy().name)) {
checkIfAllBuoysOfControlPointAreUnchangedAndIfSoRememberThis(w.getControlPoint());
if (w.getOldMark().name.equals(w.getNewMark().name)) {
checkIfAllMarksOfControlPointAreUnchangedAndIfSoRememberThis(w.getControlPoint());
} else {
controlPointsNeedingReplacement.add(w.getControlPoint());
}
@@ -422,24 +449,24 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
}
}
private void checkIfAllBuoysOfControlPointAreUnchangedAndIfSoRememberThis(ControlPointDTO controlPoint) {
boolean allBuoysUnchanged = true;
for (ControlPointAndOldAndNewBuoy cpaoanb : controlPointDataProvider.getList()) {
private void checkIfAllMarksOfControlPointAreUnchangedAndIfSoRememberThis(ControlPointDTO controlPoint) {
boolean allMarksUnchanged = true;
for (ControlPointAndOldAndNewMark cpaoanb : controlPointDataProvider.getList()) {
if (cpaoanb.getControlPoint() == controlPoint) {
if (!cpaoanb.getOldBuoy().name.equals(cpaoanb.getNewBuoy().name)) {
allBuoysUnchanged = false;
if (!cpaoanb.getOldMark().name.equals(cpaoanb.getNewMark().name)) {
allMarksUnchanged = false;
break;
}
}
}
if (allBuoysUnchanged) {
if (allMarksUnchanged) {
controlPointsNeedingReplacement.remove(controlPoint);
}
}
private void insertWaypoint(final SailingServiceAsync sailingService, StringMessages stringMessages,
AdminConsoleTableResources tableRes, final boolean beforeSelection) {
new ControlPointCreationDialog(stringMessages, tableRes, buoyDataProvider.getList(), new DialogCallback<ControlPointDTO>() {
new ControlPointCreationDialog(stringMessages, tableRes, markDataProvider.getList(), new DialogCallback<ControlPointDTO>() {
@Override
public void cancel() {
// dialog cancelled, do nothing
@@ -447,12 +474,12 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
@Override
public void ok(ControlPointDTO result) {
Set<ControlPointAndOldAndNewBuoy> selectedElements = controlPointsSelectionModel.getSelectedSet();
Set<ControlPointAndOldAndNewMark> selectedElements = controlPointsSelectionModel.getSelectedSet();
if (!selectedElements.isEmpty()) {
ControlPointAndOldAndNewBuoy selectedElement = selectedElements.iterator().next();
ControlPointAndOldAndNewMark selectedElement = selectedElements.iterator().next();
int insertPos = controlPointDataProvider.getList().indexOf(selectedElement) + (beforeSelection?0:1);
for (BuoyDTO buoyDTO : result.getBuoys()) {
controlPointDataProvider.getList().add(insertPos++, new ControlPointAndOldAndNewBuoy(result, buoyDTO));
for (MarkDTO markDTO : result.getMarks()) {
controlPointDataProvider.getList().add(insertPos++, new ControlPointAndOldAndNewMark(result, markDTO));
}
}
}
@@ -466,16 +493,16 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
sailingService.getRaceCourse(singleSelectedRace, new Date(), new AsyncCallback<List<ControlPointDTO>>() {
@Override
public void onSuccess(final List<ControlPointDTO> controlPoints) {
sailingService.getRaceBuoys(singleSelectedRace, new Date(), new AsyncCallback<RaceBuoysDTO>() {
sailingService.getRaceCourseMarks(singleSelectedRace, new Date(), new AsyncCallback<RaceCourseMarksDTO>() {
@Override
public void onSuccess(RaceBuoysDTO raceBuoysDTO) {
updateCourseAndBuoysInfo(controlPoints, raceBuoysDTO);
public void onSuccess(RaceCourseMarksDTO raceCourseMarksDTO) {
updateCourseAndMarksInfo(controlPoints, raceCourseMarksDTO);
}
@Override
public void onFailure(Throwable caught) {
RaceCourseManagementPanel.this.errorReporter.reportError(
RaceCourseManagementPanel.this.stringMessages.errorTryingToObtainTheBuoysOfTheRace(
RaceCourseManagementPanel.this.stringMessages.errorTryingToObtainTheMarksOfTheRace(
caught.getMessage()));
}
});
@@ -491,37 +518,37 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
}
}
private void updateCourseAndBuoysInfo(List<ControlPointDTO> controlPoints, RaceBuoysDTO buoysDTO) {
List<ControlPointAndOldAndNewBuoy> waypointsAndOldAndNewBuoys = new ArrayList<ControlPointAndOldAndNewBuoy>();
private void updateCourseAndMarksInfo(List<ControlPointDTO> controlPoints, RaceCourseMarksDTO marksDTO) {
List<ControlPointAndOldAndNewMark> waypointsAndOldAndNewMarks = new ArrayList<ControlPointAndOldAndNewMark>();
for (ControlPointDTO controlPointDTO : controlPoints) {
for (BuoyDTO buoy : controlPointDTO.getBuoys()) {
ControlPointAndOldAndNewBuoy waypointAndOldAndNewBuoy = new ControlPointAndOldAndNewBuoy(controlPointDTO, buoy);
waypointsAndOldAndNewBuoys.add(waypointAndOldAndNewBuoy);
for (MarkDTO mark : controlPointDTO.getMarks()) {
ControlPointAndOldAndNewMark waypointAndOldAndNewMark = new ControlPointAndOldAndNewMark(controlPointDTO, mark);
waypointsAndOldAndNewMarks.add(waypointAndOldAndNewMark);
}
}
controlPointDataProvider.getList().clear();
controlPointDataProvider.getList().addAll(waypointsAndOldAndNewBuoys);
controlPointDataProvider.getList().addAll(waypointsAndOldAndNewMarks);
controlPointsNeedingReplacement.clear();
buoyDataProvider.getList().clear();
buoyDataProvider.getList().addAll(buoysDTO.buoys);
Collections.sort(buoyDataProvider.getList(), new Comparator<BuoyDTO>() {
markDataProvider.getList().clear();
markDataProvider.getList().addAll(marksDTO.marks);
Collections.sort(markDataProvider.getList(), new Comparator<MarkDTO>() {
@Override
public int compare(BuoyDTO o1, BuoyDTO o2) {
public int compare(MarkDTO o1, MarkDTO o2) {
return o1.name.compareTo(o2.name);
}
});
for (ControlPointAndOldAndNewBuoy w : controlPointsSelectionModel.getSelectedSet()) {
for (ControlPointAndOldAndNewMark w : controlPointsSelectionModel.getSelectedSet()) {
controlPointsSelectionModel.setSelected(w, false);
}
}
private void removeSelectedWaypoints(final SailingServiceAsync sailingService) {
final Set<ControlPointDTO> selectedControlPoints = new HashSet<ControlPointDTO>();
for (ControlPointAndOldAndNewBuoy cpaoanb : controlPointsSelectionModel.getSelectedSet()) {
for (ControlPointAndOldAndNewMark cpaoanb : controlPointsSelectionModel.getSelectedSet()) {
selectedControlPoints.add(cpaoanb.getControlPoint());
}
for (Iterator<ControlPointAndOldAndNewBuoy> i=controlPointDataProvider.getList().iterator(); i.hasNext(); ) {
ControlPointAndOldAndNewBuoy next = i.next();
for (Iterator<ControlPointAndOldAndNewMark> i=controlPointDataProvider.getList().iterator(); i.hasNext(); ) {
ControlPointAndOldAndNewMark next = i.next();
if (selectedControlPoints.contains(next.getControlPoint())) {
i.remove();
}
@@ -30,7 +30,7 @@ import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
import com.sap.sailing.gwt.ui.shared.ManeuverDTO;
import com.sap.sailing.gwt.ui.shared.MultiCompetitorRaceDataDTO;
import com.sap.sailing.gwt.ui.shared.QuickRankDTO;
import com.sap.sailing.gwt.ui.shared.RaceBuoysDTO;
import com.sap.sailing.gwt.ui.shared.RaceCourseMarksDTO;
import com.sap.sailing.gwt.ui.shared.RaceColumnInSeriesDTO;
import com.sap.sailing.gwt.ui.shared.RaceDTO;
import com.sap.sailing.gwt.ui.shared.RaceMapDataDTO;
@@ -254,7 +254,7 @@ public interface SailingService extends RemoteService {
Void updateLeaderboardScoreCorrectionMetadata(String leaderboardName, Date timePointOfLastCorrectionValidity,
String comment);
RaceBuoysDTO getRaceBuoys(RegattaAndRaceIdentifier raceIdentifier, Date date);
RaceCourseMarksDTO getRaceCourseMarks(RegattaAndRaceIdentifier raceIdentifier, Date date);
void updateRaceCourse(RegattaAndRaceIdentifier raceIdentifier, List<ControlPointDTO> controlPoints);
@@ -23,7 +23,7 @@ import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
import com.sap.sailing.gwt.ui.shared.CourseDTO;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sailing.gwt.ui.shared.RaceBuoysDTO;
import com.sap.sailing.gwt.ui.shared.RaceCourseMarksDTO;
import com.sap.sailing.gwt.ui.shared.RaceColumnInSeriesDTO;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
@@ -411,7 +411,7 @@ public interface SailingServiceAsync {
void addFragUrl(String result, AsyncCallback<Void> asyncCallback);
void getRaceBuoys(RegattaAndRaceIdentifier raceIdentifier, Date date, AsyncCallback<RaceBuoysDTO> callback);
void getRaceCourseMarks(RegattaAndRaceIdentifier raceIdentifier, Date date, AsyncCallback<RaceCourseMarksDTO> callback);
void addColumnsToLeaderboard(String leaderboardName, List<Pair<String, Boolean>> columnsToAdd,
AsyncCallback<Void> callback);
@@ -363,12 +363,12 @@ public interface StringMessages extends Messages {
String errorTryingToObtainLeaderboardContents(String message);
String lastScoreUpdate();
String warningBrowserUnsupported();
String newBuoy();
String newMark();
String controlPoint();
String errorUpdatingRaceCourse(String message);
String successfullyUpdatedCourse();
String selectOneBuoyOrTwoBuoysForGate();
String errorTryingToObtainTheBuoysOfTheRace(String message);
String selectOneMarkOrTwoMarksForGate();
String errorTryingToObtainTheMarksOfTheRace(String message);
String errorTryingToObtainRaceCourse(String message);
String insertWaypointBeforeSelected();
String insertWaypointAfterSelected();
@@ -429,6 +429,8 @@ public interface StringMessages extends Messages {
String averageManeuverLossInMeters();
String averageTackLossInMeters();
String averageJibeLossInMeters();
String shape();
String pattern();
String legend();
String live();
}
@@ -364,12 +364,12 @@ errorAddingFragUrl=Error adding FRAG URL: {0}
errorTryingToObtainLeaderboardContents=Error trying to obtain leaderboard contents: {0}
lastScoreUpdate=Last Score Update
warningBrowserUnsupported=Your browser is currently not supported. Please switch to a newer one.
newBuoy=New Buoy
controlPoint=Buoy/Gate
newMark=New Mark
controlPoint=Mark/Gate
errorUpdatingRaceCourse=Error updating race course: {0}
successfullyUpdatedCourse=Successfully updated race course
selectOneBuoyOrTwoBuoysForGate=Select a single buoy or two buoys to create a gate
errorTryingToObtainTheBuoysOfTheRace=Error trying to obtain the buoys of the race: {0}
selectOneMarkOrTwoMarksForGate=Select a single mark or two marks to create a gate
errorTryingToObtainTheMarksOfTheRace=Error trying to obtain the marks of the race course: {0}
errorTryingToObtainRaceCourse=Error trying to obtain the race course: {0}
insertWaypointBeforeSelected=Insert waypoint before selected
insertWaypointAfterSelected=Insert waypoint after selected
@@ -430,5 +430,7 @@ maneuverLoss=Maneuver loss
averageManeuverLossInMeters=\u2205 Maneuver Loss
averageTackLossInMeters=\u2205 Tack Loss
averageJibeLossInMeters=\u2205 Jibe Loss
shape=Shape
pattern=Pattern
legend=Legend
live=live
live=live
@@ -365,12 +365,12 @@ errorAddingFragUrl=Fehler beim Hinzufügen einer FREG URL: {0}
errorTryingToObtainLeaderboardContents=Fehler beim Berechnen der Ergebnisliste: {0}
lastScoreUpdate=Letzte Ergebnisänderung
warningBrowserUnsupported=Ihr Browser wird nicht unterstützt. Wir empfehlen den Firefox in der neuesten Version.
newBuoy=Neue Tonne
controlPoint=Tonne/Gate
newMark=Neue Marke
controlPoint=Einzelmarke/Gate
errorUpdatingRaceCourse=Fehler beim Aktualisieren des neuen Kurses: {0}
successfullyUpdatedCourse=Kurs erfolgreich aktualisiert
selectOneBuoyOrTwoBuoysForGate=Eine Tonne auswählen oder zwei Tonnen, um ein Gate zu erstellen
errorTryingToObtainTheBuoysOfTheRace=Fehler beim Ermitteln der Tonnen des Rennkurses: {0}
selectOneMarkOrTwoMarksForGate=Eine einzelne Marke auswählen oder zwei Marken, um ein Gate zu erstellen
errorTryingToObtainTheMarksOfTheRace=Fehler beim Ermitteln der Marken des Regattakurses: {0}
errorTryingToObtainRaceCourse=Fehler beim Ermitteln des Rennkurses: {0}
insertWaypointBeforeSelected=Wegpunkt nach dem selektierten einfügen
insertWaypointAfterSelected=Wegpunkt vor dem selektierten einfügen
@@ -431,5 +431,8 @@ maneuverLoss=Manöververlust
averageManeuverLossInMeters=\u2205 Manöververlust
averageTackLossInMeters=\u2205 Wendeverlust
averageJibeLossInMeters=\u2205 Halseverlust
shape=Form
pattern=Muster
legend=Legende
live=live
live=live
@@ -16,7 +16,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
@@ -101,7 +101,7 @@ public class LeaderboardDTOCache {
}
@Override
public void buoyPositionChanged(GPSFix fix, Buoy buoy) {
public void markPositionChanged(GPSFix fix, Mark mark) {
removeFromCache(leaderboard);
}
@@ -36,7 +36,7 @@ import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course;
@@ -128,7 +128,7 @@ import com.sap.sailing.geocoding.ReverseGeocoder;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.shared.BoatClassDTO;
import com.sap.sailing.gwt.ui.shared.BulkScoreCorrectionDTO;
import com.sap.sailing.gwt.ui.shared.BuoyDTO;
import com.sap.sailing.gwt.ui.shared.MarkDTO;
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
import com.sap.sailing.gwt.ui.shared.CompetitorRaceDataDTO;
import com.sap.sailing.gwt.ui.shared.ControlPointDTO;
@@ -150,7 +150,7 @@ import com.sap.sailing.gwt.ui.shared.PlacemarkDTO;
import com.sap.sailing.gwt.ui.shared.PlacemarkOrderDTO;
import com.sap.sailing.gwt.ui.shared.PositionDTO;
import com.sap.sailing.gwt.ui.shared.QuickRankDTO;
import com.sap.sailing.gwt.ui.shared.RaceBuoysDTO;
import com.sap.sailing.gwt.ui.shared.RaceCourseMarksDTO;
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
import com.sap.sailing.gwt.ui.shared.RaceColumnInSeriesDTO;
import com.sap.sailing.gwt.ui.shared.RaceDTO;
@@ -716,7 +716,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
@Override
public void buoyPositionChanged(GPSFix fix, Buoy buoy) {
public void markPositionChanged(GPSFix fix, Mark mark) {
invalidateCacheAndRemoveThisListenerFromTrackedRace();
}
@@ -879,12 +879,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
return result;
}
private BuoyDTO convertToBuoyDTO(Buoy buoy, Position position) {
BuoyDTO buoyDTO = new BuoyDTO(buoy.getName(), position.getLatDeg(), position.getLngDeg());
buoyDTO.color = buoy.getColor();
buoyDTO.shape = buoy.getShape();
buoyDTO.pattern = buoy.getPattern();
return buoyDTO;
private MarkDTO convertToMarkDTO(Mark mark, Position position) {
MarkDTO markDTO = new MarkDTO(mark.getName(), position.getLatDeg(), position.getLngDeg());
markDTO.color = mark.getColor();
markDTO.shape = mark.getShape();
markDTO.pattern = mark.getPattern();
return markDTO;
}
private RegattaDTO convertToRegattaDTO(Regatta regatta) {
@@ -1565,35 +1565,35 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
TimePoint dateAsTimePoint = new MillisecondsTimePoint(date);
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
if (trackedRace != null) {
result.buoys = new HashSet<BuoyDTO>();
result.marks = new HashSet<MarkDTO>();
result.waypointPositions = new ArrayList<PositionDTO>();
Set<Buoy> buoys = new HashSet<Buoy>();
Set<Mark> marks = new HashSet<Mark>();
Course course = trackedRace.getRace().getCourse();
for (Waypoint waypoint : course.getWaypoints()) {
Position waypointPosition = trackedRace.getApproximatePosition(waypoint, dateAsTimePoint);
if (waypointPosition != null) {
result.waypointPositions.add(new PositionDTO(waypointPosition.getLatDeg(), waypointPosition.getLngDeg()));
}
for (Buoy b : waypoint.getBuoys()) {
buoys.add(b);
for (Mark b : waypoint.getMarks()) {
marks.add(b);
}
}
for (Buoy buoy : buoys) {
GPSFixTrack<Buoy, GPSFix> track = trackedRace.getOrCreateTrack(buoy);
for (Mark mark : marks) {
GPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
Position positionAtDate = track.getEstimatedPosition(dateAsTimePoint, /* extrapolate */false);
if (positionAtDate != null) {
result.buoys.add(convertToBuoyDTO(buoy, positionAtDate));
result.marks.add(convertToMarkDTO(mark, positionAtDate));
}
}
// set the positions of start and finish
Waypoint firstWaypoint = course.getFirstWaypoint();
if (firstWaypoint != null) {
result.startBuoyPositions = getBuoyPositionDTOs(dateAsTimePoint, trackedRace, firstWaypoint);
result.startMarkPositions = getMarkPositionDTOs(dateAsTimePoint, trackedRace, firstWaypoint);
}
Waypoint lastWaypoint = course.getLastWaypoint();
if (lastWaypoint != null) {
result.finishBuoyPositions = getBuoyPositionDTOs(dateAsTimePoint, trackedRace, lastWaypoint);
result.finishMarkPositions = getMarkPositionDTOs(dateAsTimePoint, trackedRace, lastWaypoint);
}
}
}
@@ -1601,22 +1601,22 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
@Override
public RaceBuoysDTO getRaceBuoys(RegattaAndRaceIdentifier raceIdentifier, Date date) {
RaceBuoysDTO raceBuoysDTO = new RaceBuoysDTO();
public RaceCourseMarksDTO getRaceCourseMarks(RegattaAndRaceIdentifier raceIdentifier, Date date) {
RaceCourseMarksDTO raceMarksDTO = new RaceCourseMarksDTO();
TimePoint dateAsTimePoint = new MillisecondsTimePoint(date);
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
if (trackedRace != null) {
raceBuoysDTO.buoys = new HashSet<BuoyDTO>();
Iterable<Buoy> buoys = trackedRace.getBuoys();
for (Buoy buoy : buoys) {
GPSFixTrack<Buoy, GPSFix> track = trackedRace.getOrCreateTrack(buoy);
raceMarksDTO.marks = new HashSet<MarkDTO>();
Iterable<Mark> marks = trackedRace.getMarks();
for (Mark mark : marks) {
GPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
Position positionAtDate = track.getEstimatedPosition(dateAsTimePoint, /* extrapolate */false);
if (positionAtDate != null) {
raceBuoysDTO.buoys.add(convertToBuoyDTO(buoy, positionAtDate));
raceMarksDTO.marks.add(convertToMarkDTO(mark, positionAtDate));
}
}
}
return raceBuoysDTO;
return raceMarksDTO;
}
@Override
@@ -1638,15 +1638,15 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
private ControlPointDTO createControlPointDTO(ControlPoint controlPoint, TrackedRace trackedRace, TimePoint timePoint) {
ControlPointDTO result;
if (controlPoint instanceof Gate) {
final Buoy left = ((Gate) controlPoint).getLeft();
final Mark left = ((Gate) controlPoint).getLeft();
final Position leftPos = trackedRace.getOrCreateTrack(left).getEstimatedPosition(timePoint, /* extrapolate */ false);
final Buoy right = ((Gate) controlPoint).getRight();
final Mark right = ((Gate) controlPoint).getRight();
final Position rightPos = trackedRace.getOrCreateTrack(right).getEstimatedPosition(timePoint, /* extrapolate */ false);
result = new GateDTO(controlPoint.getName(), convertToBuoyDTO(left, leftPos), convertToBuoyDTO(right, rightPos));
result = new GateDTO(controlPoint.getName(), convertToMarkDTO(left, leftPos), convertToMarkDTO(right, rightPos));
} else {
final Position posOfFirst = trackedRace.getOrCreateTrack(controlPoint.getBuoys().iterator().next()).
final Position posOfFirst = trackedRace.getOrCreateTrack(controlPoint.getMarks().iterator().next()).
getEstimatedPosition(timePoint, /* extrapolate */ false);
result = new BuoyDTO(controlPoint.getName(), posOfFirst.getLatDeg(), posOfFirst.getLngDeg());
result = new MarkDTO(controlPoint.getName(), posOfFirst.getLatDeg(), posOfFirst.getLngDeg());
}
return result;
}
@@ -1672,7 +1672,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
for (int i=lastMatchPosition+1; matchFromOldCourse == null && i<Util.size(waypoints); i++) {
Waypoint waypointAtI = Util.get(waypoints, i);
ControlPoint controlPointAtI = waypointAtI.getControlPoint();
if (controlPointAtI.getName().equals(controlPointDTO.name) && buoyNamesMatch(controlPointAtI.getBuoys(), controlPointDTO.getBuoys())) {
if (controlPointAtI.getName().equals(controlPointDTO.name) && markNamesMatch(controlPointAtI.getMarks(), controlPointDTO.getMarks())) {
matchFromOldCourse = controlPointAtI;
newControlPoints.add(matchFromOldCourse);
lastMatchPosition = i;
@@ -1683,11 +1683,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
ControlPoint newControlPoint;
if (controlPointDTO instanceof GateDTO) {
GateDTO gateDTO = (GateDTO) controlPointDTO;
Buoy left = baseDomainFactory.getOrCreateBuoy(gateDTO.getLeft().name);
Buoy right = baseDomainFactory.getOrCreateBuoy(gateDTO.getRight().name);
Mark left = baseDomainFactory.getOrCreateMark(gateDTO.getLeft().name);
Mark right = baseDomainFactory.getOrCreateMark(gateDTO.getRight().name);
newControlPoint = baseDomainFactory.createGate(left, right, gateDTO.name);
} else {
newControlPoint = baseDomainFactory.getOrCreateBuoy(controlPointDTO.name);
newControlPoint = baseDomainFactory.getOrCreateMark(controlPointDTO.name);
}
newControlPoints.add(newControlPoint);
}
@@ -1700,29 +1700,29 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
}
private boolean buoyNamesMatch(Iterable<Buoy> buoys, Iterable<BuoyDTO> buoyDTOs) {
Iterator<Buoy> buoysIter = buoys.iterator();
Iterator<BuoyDTO> buoyDTOsIter = buoyDTOs.iterator();
while (buoysIter.hasNext() && buoyDTOsIter.hasNext()) {
Buoy nextBuoy = buoysIter.next();
BuoyDTO nextBuoyDTO = buoyDTOsIter.next();
if (!nextBuoy.getName().equals(nextBuoyDTO.name)) {
private boolean markNamesMatch(Iterable<Mark> marks, Iterable<MarkDTO> marksDTOs) {
Iterator<Mark> marksIter = marks.iterator();
Iterator<MarkDTO> markDTOsIter = marksDTOs.iterator();
while (marksIter.hasNext() && markDTOsIter.hasNext()) {
Mark nextMark = marksIter.next();
MarkDTO nextMarkDTO = markDTOsIter.next();
if (!nextMark.getName().equals(nextMarkDTO.name)) {
return false;
}
}
return buoysIter.hasNext() == buoyDTOsIter.hasNext();
return marksIter.hasNext() == markDTOsIter.hasNext();
}
private List<PositionDTO> getBuoyPositionDTOs(TimePoint timePoint, TrackedRace trackedRace, Waypoint waypoint) {
List<PositionDTO> startBuoyPositions = new ArrayList<PositionDTO>();
for (Buoy startBuoy : waypoint.getBuoys()) {
final Position estimatedBuoyPosition = trackedRace.getOrCreateTrack(startBuoy)
private List<PositionDTO> getMarkPositionDTOs(TimePoint timePoint, TrackedRace trackedRace, Waypoint waypoint) {
List<PositionDTO> startMarkPositions = new ArrayList<PositionDTO>();
for (Mark startMark : waypoint.getMarks()) {
final Position estimatedMarkPosition = trackedRace.getOrCreateTrack(startMark)
.getEstimatedPosition(timePoint, /* extrapolate */false);
if (estimatedBuoyPosition != null) {
startBuoyPositions.add(new PositionDTO(estimatedBuoyPosition.getLatDeg(), estimatedBuoyPosition.getLngDeg()));
if (estimatedMarkPosition != null) {
startMarkPositions.add(new PositionDTO(estimatedMarkPosition.getLatDeg(), estimatedMarkPosition.getLngDeg()));
}
}
return startBuoyPositions;
return startMarkPositions;
}
@Override
@@ -1986,9 +1986,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
Placemark finishBest = null;
// Get start postition
Iterator<Buoy> startBuoys = race.getRace().getCourse().getFirstWaypoint().getBuoys().iterator();
GPSFix startBuoyFix = startBuoys.hasNext() ? race.getOrCreateTrack(startBuoys.next()).getLastRawFix() : null;
Position startPosition = startBuoyFix != null ? startBuoyFix.getPosition() : null;
Iterator<Mark> startMarks = race.getRace().getCourse().getFirstWaypoint().getMarks().iterator();
GPSFix startMarkFix = startMarks.hasNext() ? race.getOrCreateTrack(startMarks.next()).getLastRawFix() : null;
Position startPosition = startMarkFix != null ? startMarkFix.getPosition() : null;
if (startPosition != null) {
try {
// Get distance to nearest placemark and calculate the search radius
@@ -2009,9 +2009,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
// Get finish position
Iterator<Buoy> finishBuoys = race.getRace().getCourse().getFirstWaypoint().getBuoys().iterator();
GPSFix finishBuoyFix = finishBuoys.hasNext() ? race.getOrCreateTrack(finishBuoys.next()).getLastRawFix() : null;
Position finishPosition = finishBuoyFix != null ? finishBuoyFix.getPosition() : null;
Iterator<Mark> finishMarks = race.getRace().getCourse().getFirstWaypoint().getMarks().iterator();
GPSFix finishMarkFix = finishMarks.hasNext() ? race.getOrCreateTrack(finishMarks.next()).getLastRawFix() : null;
Position finishPosition = finishMarkFix != null ? finishMarkFix.getPosition() : null;
if (startPosition != null && finishPosition != null) {
if (startPosition.getDistance(finishPosition).getKilometers() <= ReverseGeocoder.POSITION_CACHE_DISTANCE_LIMIT_IN_KM) {
finishBest = startBest;
@@ -23,5 +23,5 @@ public abstract class ControlPointDTO extends NamedDTO {
return System.identityHashCode(this);
}
public abstract Iterable<BuoyDTO> getBuoys();
public abstract Iterable<MarkDTO> getMarks();
}
@@ -7,7 +7,7 @@ import com.google.gwt.user.client.rpc.IsSerializable;
public class CourseDTO implements IsSerializable {
public List<PositionDTO> waypointPositions;
public List<PositionDTO> startBuoyPositions;
public List<PositionDTO> finishBuoyPositions;
public Set<BuoyDTO> buoys;
public List<PositionDTO> startMarkPositions;
public List<PositionDTO> finishMarkPositions;
public Set<MarkDTO> marks;
}
@@ -3,27 +3,27 @@ package com.sap.sailing.gwt.ui.shared;
import java.util.Arrays;
public class GateDTO extends ControlPointDTO {
private BuoyDTO left;
private BuoyDTO right;
private MarkDTO left;
private MarkDTO right;
public GateDTO() {}
public GateDTO(String name, BuoyDTO left, BuoyDTO right) {
public GateDTO(String name, MarkDTO left, MarkDTO right) {
super(name);
this.left = left;
this.right = right;
}
public BuoyDTO getLeft() {
public MarkDTO getLeft() {
return left;
}
public BuoyDTO getRight() {
public MarkDTO getRight() {
return right;
}
@Override
public Iterable<BuoyDTO> getBuoys() {
public Iterable<MarkDTO> getMarks() {
return Arrays.asList(left, right);
}
}
@@ -2,21 +2,21 @@ package com.sap.sailing.gwt.ui.shared;
import java.util.Collections;
public class BuoyDTO extends ControlPointDTO {
public class MarkDTO extends ControlPointDTO {
public PositionDTO position;
public String color;
public String shape;
public String pattern;
BuoyDTO() {}
MarkDTO() {}
public BuoyDTO(String name, double latDeg, double lngDeg) {
public MarkDTO(String name, double latDeg, double lngDeg) {
super(name);
this.position = new PositionDTO(latDeg, lngDeg);
}
@Override
public Iterable<BuoyDTO> getBuoys() {
public Iterable<MarkDTO> getMarks() {
return Collections.singleton(this);
}
}
@@ -4,6 +4,6 @@ import java.util.Set;
import com.google.gwt.user.client.rpc.IsSerializable;
public class RaceBuoysDTO implements IsSerializable {
public Set<BuoyDTO> buoys;
public class RaceCourseMarksDTO implements IsSerializable {
public Set<MarkDTO> marks;
}
@@ -3,7 +3,7 @@ package com.sap.sailing.gwt.ui.shared;
import java.util.List;
public class WaypointDTO extends NamedDTO {
public List<BuoyDTO> buoys;
public List<MarkDTO> marks;
public int courseIndex;
@@ -3,15 +3,15 @@ package com.sap.sailing.gwt.ui.shared.racemap;
import com.google.gwt.maps.client.overlay.Icon;
/**
* A descriptor class for display properties of a buoy icon.
* A descriptor class for display properties of a mark icon.
*/
public class BuoyIconDescriptor {
public class MarkIconDescriptor {
private final Icon icon;
private final String color;
private final String shape;
private final String pattern;
public BuoyIconDescriptor(Icon icon, String color, String shape, String pattern) {
public MarkIconDescriptor(Icon icon, String color, String shape, String pattern) {
this.icon = icon;
this.color = color;
this.shape = shape;
@@ -35,7 +35,7 @@ public class BuoyIconDescriptor {
}
/**
* An utility method to check if the buoy icon has compatible display properties.
* An utility method to check if the mark icon has compatible display properties.
* In case of null values at least one valid display property must exist and fit.
*/
public boolean isCompatible(String colorToCheck, String shapeToCheck, String patternToCheck) {
@@ -75,7 +75,7 @@ import com.sap.sailing.gwt.ui.client.TimeListener;
import com.sap.sailing.gwt.ui.client.Timer;
import com.sap.sailing.gwt.ui.client.Timer.PlayStates;
import com.sap.sailing.gwt.ui.client.WindSourceTypeFormatter;
import com.sap.sailing.gwt.ui.shared.BuoyDTO;
import com.sap.sailing.gwt.ui.shared.MarkDTO;
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
import com.sap.sailing.gwt.ui.shared.CourseDTO;
import com.sap.sailing.gwt.ui.shared.GPSFixDTO;
@@ -107,12 +107,12 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
private final Map<CompetitorDTO, Polyline> tails;
/**
* Polyline for the start line (connecting two buoys representing the start gate).
* Polyline for the start line (connecting two marks representing the start gate).
*/
private Polyline startLine;
/**
* Polyline for the finish line (connecting two buoys representing the finish gate).
* Polyline for the finish line (connecting two marks representing the finish gate).
*/
private Polyline finishLine;
@@ -162,9 +162,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
*/
private final Map<WindSource, WindSensorOverlay> windSensorOverlays;
private final Map<String, Marker> buoyMarkers;
private final Map<String, Marker> courseMarkMarkers;
private final Map<String, BuoyDTO> buoyDTOs;
private final Map<String, MarkDTO> markDTOs;
/**
* markers displayed in response to
@@ -189,7 +189,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
private List<RegattaAndRaceIdentifier> selectedRaces;
/**
* Used to check if the first initial zoom to the buoy markers was already done.
* Used to check if the first initial zoom to the mark markers was already done.
*/
private boolean mapFirstZoomDone = false;
@@ -249,8 +249,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
tails = new HashMap<CompetitorDTO, Polyline>();
firstShownFix = new HashMap<CompetitorDTO, Integer>();
lastShownFix = new HashMap<CompetitorDTO, Integer>();
buoyMarkers = new HashMap<String, Marker>();
buoyDTOs = new HashMap<String, BuoyDTO>();
courseMarkMarkers = new HashMap<String, Marker>();
markDTOs = new HashMap<String, MarkDTO>();
boatCanvasOverlays = new HashMap<CompetitorDTO, BoatCanvasOverlay>();
competitorInfoOverlays = new HashMap<CompetitorDTO, CompetitorInfoOverlay>();
windSensorOverlays = new HashMap<WindSource, WindSensorOverlay>();
@@ -383,7 +383,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
// Do mark specific actions
showMarksOnMap(raceMapDataDTO.coursePositions);
showCourseMarksOnMap(raceMapDataDTO.coursePositions);
showStartAndFinishLines(raceMapDataDTO.coursePositions);
showAdvantageLine(competitorsToShow, date);
@@ -393,12 +393,12 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
LatLngBounds bounds = settings.getZoomSettings().getNewBounds(RaceMap.this);
zoomMapToNewBounds(bounds);
mapFirstZoomDone = true;
} else if (!mapFirstZoomDone) { // Zoom once to the buoys
zoomMapToNewBounds(new BuoysBoundsCalculator().calculateNewBounds(RaceMap.this));
} else if (!mapFirstZoomDone) { // Zoom once to the marks
zoomMapToNewBounds(new CourseMarksBoundsCalculator().calculateNewBounds(RaceMap.this));
mapFirstZoomDone = true;
/*
* Reset the mapZoomedOrPannedSinceLastRaceSelection: In spite of the fact that
* the map was just zoomed to the bounds of the buoys, it was not a zoom or pan
* the map was just zoomed to the bounds of the marks, it was not a zoom or pan
* triggered by the user. As a consequence the
* mapZoomedOrPannedSinceLastRaceSelection option has to reset again.
*/
@@ -544,26 +544,26 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
}
protected void showMarksOnMap(CourseDTO courseDTO) {
protected void showCourseMarksOnMap(CourseDTO courseDTO) {
if (map != null && courseDTO != null) {
Map<String, BuoyDTO> toRemove = new HashMap<String, BuoyDTO>(buoyDTOs);
if (courseDTO.buoys != null) {
for (BuoyDTO buoyDTO : courseDTO.buoys) {
Marker buoyMarker = buoyMarkers.get(buoyDTO.name);
if (buoyMarker == null) {
buoyMarker = createBuoyMarker(buoyDTO);
buoyMarkers.put(buoyDTO.name, buoyMarker);
buoyDTOs.put(buoyDTO.name, buoyDTO);
map.addOverlay(buoyMarker);
Map<String, MarkDTO> toRemove = new HashMap<String, MarkDTO>(markDTOs);
if (courseDTO.marks != null) {
for (MarkDTO markDTO : courseDTO.marks) {
Marker markMarker = courseMarkMarkers.get(markDTO.name);
if (markMarker == null) {
markMarker = createCourseMarkMarker(markDTO);
courseMarkMarkers.put(markDTO.name, markMarker);
markDTOs.put(markDTO.name, markDTO);
map.addOverlay(markMarker);
} else {
buoyMarker.setLatLng(LatLng.newInstance(buoyDTO.position.latDeg, buoyDTO.position.lngDeg));
toRemove.remove(buoyDTO.name);
markMarker.setLatLng(LatLng.newInstance(markDTO.position.latDeg, markDTO.position.lngDeg));
toRemove.remove(markDTO.name);
}
}
for (String toRemoveBuoyName : toRemove.keySet()) {
Marker marker = buoyMarkers.remove(toRemoveBuoyName);
for (String toRemoveMarkName : toRemove.keySet()) {
Marker marker = courseMarkMarkers.remove(toRemoveMarkName);
map.removeOverlay(marker);
buoyDTOs.remove(toRemoveBuoyName);
markDTOs.remove(toRemoveMarkName);
}
}
}
@@ -806,10 +806,10 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
int numberOfLegs = lastRaceTimesInfo.legInfos.size();
// draw the start line
if (legOfLeadingCompetitor <= 1 &&
settings.getHelpLinesSettings().containsHelpLine(HelpLineTypes.STARTLINE) && courseDTO.startBuoyPositions.size() == 2) {
settings.getHelpLinesSettings().containsHelpLine(HelpLineTypes.STARTLINE) && courseDTO.startMarkPositions.size() == 2) {
LatLng[] startGatePoints = new LatLng[2];
startGatePoints[0] = LatLng.newInstance(courseDTO.startBuoyPositions.get(0).latDeg, courseDTO.startBuoyPositions.get(0).lngDeg);
startGatePoints[1] = LatLng.newInstance(courseDTO.startBuoyPositions.get(1).latDeg, courseDTO.startBuoyPositions.get(1).lngDeg);
startGatePoints[0] = LatLng.newInstance(courseDTO.startMarkPositions.get(0).latDeg, courseDTO.startMarkPositions.get(0).lngDeg);
startGatePoints[1] = LatLng.newInstance(courseDTO.startMarkPositions.get(1).latDeg, courseDTO.startMarkPositions.get(1).lngDeg);
if (startLine == null) {
PolylineOptions options = PolylineOptions.newInstance(/* clickable must be true for hover sensititivy*/ true, /* geodesic */true);
startLine = new Polyline(startGatePoints, /* color */ "#FFFFFF", /* width */ 1, /* opacity */1.0, options);
@@ -842,10 +842,10 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
// draw the finish line
if (legOfLeadingCompetitor > 0 && legOfLeadingCompetitor == numberOfLegs &&
settings.getHelpLinesSettings().containsHelpLine(HelpLineTypes.FINISHLINE) && courseDTO.finishBuoyPositions.size() == 2) {
settings.getHelpLinesSettings().containsHelpLine(HelpLineTypes.FINISHLINE) && courseDTO.finishMarkPositions.size() == 2) {
LatLng[] finishGatePoints = new LatLng[2];
finishGatePoints[0] = LatLng.newInstance(courseDTO.finishBuoyPositions.get(0).latDeg, courseDTO.finishBuoyPositions.get(0).lngDeg);
finishGatePoints[1] = LatLng.newInstance(courseDTO.finishBuoyPositions.get(1).latDeg, courseDTO.finishBuoyPositions.get(1).lngDeg);
finishGatePoints[0] = LatLng.newInstance(courseDTO.finishMarkPositions.get(0).latDeg, courseDTO.finishMarkPositions.get(0).lngDeg);
finishGatePoints[1] = LatLng.newInstance(courseDTO.finishMarkPositions.get(1).latDeg, courseDTO.finishMarkPositions.get(1).lngDeg);
if(finishLine == null) {
PolylineOptions options = PolylineOptions.newInstance(/* clickable must be true for hover sensitivity */ true, /* geodesic */true);
finishLine = new Polyline(finishGatePoints, /* color */ "#000000", /* width */ 1, /* opacity */1.0, options);
@@ -951,23 +951,23 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
return !settings.isShowOnlySelectedCompetitors() && competitorSelection.isSelected(competitorDTO);
}
protected Marker createBuoyMarker(final BuoyDTO markDTO) {
protected Marker createCourseMarkMarker(final MarkDTO markDTO) {
MarkerOptions options = MarkerOptions.newInstance();
final Icon markIcon = raceMapImageManager.resolveBuoyIcon(markDTO.color, markDTO.shape, markDTO.pattern);
final Icon markIcon = raceMapImageManager.resolveMarkIcon(markDTO.color, markDTO.shape, markDTO.pattern);
if (markIcon != null) {
options.setIcon(markIcon);
}
options.setTitle(markDTO.name);
final Marker buoyMarker = new Marker(LatLng.newInstance(markDTO.position.latDeg, markDTO.position.lngDeg),
final Marker courseMarkMarker = new Marker(LatLng.newInstance(markDTO.position.latDeg, markDTO.position.lngDeg),
options);
buoyMarker.addMarkerClickHandler(new MarkerClickHandler() {
courseMarkMarker.addMarkerClickHandler(new MarkerClickHandler() {
@Override
public void onClick(MarkerClickEvent event) {
LatLng latlng = buoyMarker.getLatLng();
LatLng latlng = courseMarkMarker.getLatLng();
showMarkInfoWindow(markDTO, latlng);
}
});
return buoyMarker;
return courseMarkMarker;
}
private CompetitorInfoOverlay createCompetitorInfoOverlay(final CompetitorDTO competitorDTO) {
@@ -1002,7 +1002,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
return windSensorOverlay;
}
private void showMarkInfoWindow(BuoyDTO markDTO, LatLng latlng) {
private void showMarkInfoWindow(MarkDTO markDTO, LatLng latlng) {
map.getInfoWindow().open(latlng, new InfoWindowContent(getInfoWindowContent(markDTO)));
}
@@ -1047,7 +1047,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
return flowPanel;
}
private Widget getInfoWindowContent(BuoyDTO markDTO) {
private Widget getInfoWindowContent(MarkDTO markDTO) {
VerticalPanel vPanel = new VerticalPanel();
vPanel.add(createInfoWindowLabelAndValue(stringMessages.mark(), markDTO.name));
vPanel.add(createInfoWindowLabelAndValue(stringMessages.position(), formatPosition(markDTO.position.latDeg, markDTO.position.lngDeg)));
@@ -1722,13 +1722,13 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
public static class BuoysBoundsCalculator implements LatLngBoundsCalculator {
public static class CourseMarksBoundsCalculator implements LatLngBoundsCalculator {
@Override
public LatLngBounds calculateNewBounds(RaceMap forMap) {
LatLngBounds newBounds = null;
Iterable<BuoyDTO> marksToZoom = forMap.buoyDTOs.values();
Iterable<MarkDTO> marksToZoom = forMap.markDTOs.values();
if (marksToZoom != null) {
for (BuoyDTO markDTO : marksToZoom) {
for (MarkDTO markDTO : marksToZoom) {
LatLng markLatLng = LatLng.newInstance(markDTO.position.latDeg, markDTO.position.lngDeg);
LatLngBounds bounds = LatLngBounds.newInstance(markLatLng, markLatLng);
if (newBounds == null) {
@@ -28,18 +28,18 @@ public class RaceMapImageManager {
protected ImageTransformer expeditionWindIconTransformer;
/**
* The default icon for a buoy
* The default icon for a course mark
*/
private Icon defaultBuoyIcon;
private Icon defaultCourseMarkIcon;
private final List<BuoyIconDescriptor> buoyIconDescriptors;
private final List<MarkIconDescriptor> markIconDescriptors;
protected Map<Pair<ManeuverType, Tack>, Icon> maneuverIconsForTypeAndTargetTack;
private static RaceMapResources resources = GWT.create(RaceMapResources.class);
public RaceMapImageManager() {
buoyIconDescriptors = new ArrayList<BuoyIconDescriptor>();
markIconDescriptors = new ArrayList<MarkIconDescriptor>();
maneuverIconsForTypeAndTargetTack = new HashMap<Pair<ManeuverType, Tack>, Icon>();
@@ -47,10 +47,10 @@ public class RaceMapImageManager {
expeditionWindIconTransformer = new ImageTransformer(resources.expeditionWindIcon());
}
public Icon resolveBuoyIcon(String color, String shape, String pattern) {
Icon result = defaultBuoyIcon;
public Icon resolveMarkIcon(String color, String shape, String pattern) {
Icon result = defaultCourseMarkIcon;
for (BuoyIconDescriptor iconDescriptor: buoyIconDescriptors) {
for (MarkIconDescriptor iconDescriptor: markIconDescriptors) {
if(iconDescriptor.isCompatible(color, shape, pattern)) {
result = iconDescriptor.getIcon();
break;
@@ -66,20 +66,20 @@ public class RaceMapImageManager {
*/
public void loadMapIcons(MapWidget map) {
if(map != null) {
defaultBuoyIcon = Icon.newInstance(resources.buoyIcon().getSafeUri().asString());
defaultBuoyIcon.setIconSize(Size.newInstance(19, 28));
defaultBuoyIcon.setIconAnchor(Point.newInstance(6, 15));
defaultCourseMarkIcon = Icon.newInstance(resources.buoyIcon().getSafeUri().asString());
defaultCourseMarkIcon.setIconSize(Size.newInstance(19, 28));
defaultCourseMarkIcon.setIconAnchor(Point.newInstance(6, 15));
createBuoyIconDescriptor(resources.buoyRedIcon(), "red", null, null);
createBuoyIconDescriptor(resources.buoyGreenIcon(), "green", null, null);
createBuoyIconDescriptor(resources.buoyYellowIcon(), "yellow", null, null);
createBuoyIconDescriptor(resources.buoyGreyIcon(), "grey", null, null);
createBuoyIconDescriptor(resources.buoyWhiteIcon(), "white", null, null);
createBuoyIconDescriptor(resources.buoyWhiteConeIcon(), "white", "conical", null);
createBuoyIconDescriptor(resources.buoyBlackIcon(), "black", null, null);
createBuoyIconDescriptor(resources.buoyBlackConeIcon(), "black", "conical", null);
createBuoyIconDescriptor(resources.buoyDarkOrangeIcon(), "orange", null, null);
createBuoyIconDescriptor(resources.buoyBlackFinishIcon(), "black", "cylinder", "checkered");
createMarkIconDescriptor(resources.buoyRedIcon(), "red", null, null);
createMarkIconDescriptor(resources.buoyGreenIcon(), "green", null, null);
createMarkIconDescriptor(resources.buoyYellowIcon(), "yellow", null, null);
createMarkIconDescriptor(resources.buoyGreyIcon(), "grey", null, null);
createMarkIconDescriptor(resources.buoyWhiteIcon(), "white", null, null);
createMarkIconDescriptor(resources.buoyWhiteConeIcon(), "white", "conical", null);
createMarkIconDescriptor(resources.buoyBlackIcon(), "black", null, null);
createMarkIconDescriptor(resources.buoyBlackConeIcon(), "black", "conical", null);
createMarkIconDescriptor(resources.buoyDarkOrangeIcon(), "orange", null, null);
createMarkIconDescriptor(resources.buoyBlackFinishIcon(), "black", "cylinder", "checkered");
Icon tackToStarboardIcon = Icon
.newInstance("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=T|00FF00|000000");
@@ -137,12 +137,12 @@ public class RaceMapImageManager {
}
}
private void createBuoyIconDescriptor(ImageResource imgResource, String color, String shape, String pattern) {
private void createMarkIconDescriptor(ImageResource imgResource, String color, String shape, String pattern) {
Icon icon = Icon.newInstance(imgResource.getSafeUri().asString());
icon.setIconSize(Size.newInstance(19, 28));
icon.setIconAnchor(Point.newInstance(6, 15));
BuoyIconDescriptor buoyIconDescriptor = new BuoyIconDescriptor(icon, color, shape, pattern);
buoyIconDescriptors.add(buoyIconDescriptor);
MarkIconDescriptor markIconDescriptor = new MarkIconDescriptor(icon, color, shape, pattern);
markIconDescriptors.add(markIconDescriptor);
}
public ImageTransformer getCombinedWindIconTransformer() {
@@ -16,7 +16,7 @@ public class RaceMapZoomSettings {
*/
public enum ZoomTypes {
NONE(null), WINDSENSORS(new RaceMap.WindSensorsBoundsCalculator()), BOATS(new RaceMap.BoatsBoundsCalculator()),
TAILS(new RaceMap.TailsBoundsCalculator()), BUOYS(new RaceMap.BuoysBoundsCalculator());
TAILS(new RaceMap.TailsBoundsCalculator()), BUOYS(new RaceMap.CourseMarksBoundsCalculator());
private LatLngBoundsCalculator calculator;
@@ -5,10 +5,12 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import com.google.gwt.cell.client.SafeHtmlCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.FontWeight;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
@@ -81,8 +83,11 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
private static final String STYLE_ACTIVE_BUTTON = STYLE_NAME_PREFIX + "ActiveButton";
private static final String STYLE_ACTIVE_LEADERBOARD = STYLE_NAME_PREFIX + "ActiveLeaderboard";
private static final String STYLE_LEGEND = STYLE_NAME_PREFIX + "Legend";
private static final String STYLE_TABLE_TEXT = STYLE_NAME_PREFIX + "TableText";
private static final String STYLE_COLORBOX = STYLE_NAME_PREFIX + "ColorBox";
private static final String STYLE_BOATCLASS = STYLE_NAME_PREFIX + "BoatClass";
private enum RacesRenderStrategy { DEFAULT, ESS40 };
private enum RaceRenderingStrategy { DEFAULT, ESS40 };
private final SailingServiceAsync sailingService;
private final StringMessages stringMessages;
@@ -98,7 +103,7 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
private final boolean isEmbedded;
private final boolean showRaceDetails;
private RacesRenderStrategy racesRenderStrategy = RacesRenderStrategy.DEFAULT;
private RaceRenderingStrategy raceRenderingStrategy = RaceRenderingStrategy.DEFAULT;
public LeaderboardGroupPanel(SailingServiceAsync sailingService, StringMessages stringConstants,
ErrorReporter errorReporter, final String groupName, String root, String viewMode, boolean embedded, boolean showRaceDetails) {
@@ -165,6 +170,10 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
}
private void createdPageContent() {
if(leaderboardGroup.name.equals("Extreme Sailing Series")) {
raceRenderingStrategy = RaceRenderingStrategy.ESS40;
}
if (!isEmbedded) {
Label groupNameLabel = new Label(leaderboardGroup.name + ":");
groupNameLabel.setStyleName(STYLE_NAME_PREFIX + "GroupName");
@@ -205,7 +214,7 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
text = strippedLeaderboardDTO.name;
}
SafeHtmlBuilder b = new SafeHtmlBuilder();
b.append(TEXTTEMPLATE.textWithClass(text, STYLE_NAME_PREFIX + "BoatClass"));
b.append(TEXTTEMPLATE.textWithClass(text, STYLE_BOATCLASS));
return b.toSafeHtml();
}
};
@@ -221,24 +230,24 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
+ (isEmbedded ? "&embedded=true" : "")
+ "&leaderboardGroupName=" + leaderboardGroup.name + "&root=" + root
+ (debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr=" + debugParam : ""));
return getAnchor(link, stringMessages.overview(), STYLE_ACTIVE_LEADERBOARD);
return getAnchor(link, stringMessages.leaderboard(), STYLE_ACTIVE_LEADERBOARD);
}
};
LeaderboardGroupFullTableResources tableResources = GWT.create(LeaderboardGroupFullTableResources.class);
CellTable<StrippedLeaderboardDTO> leaderboardsTable = new CellTable<StrippedLeaderboardDTO>(10000, tableResources);
leaderboardsTable.setSelectionModel(new NoSelectionModel<StrippedLeaderboardDTO>());
leaderboardsTable.addColumn(leaderboardNameColumn, stringMessages.name());
leaderboardsTable.addColumn(overviewColumn, stringMessages.leaderboard());
leaderboardsTable.addColumn(leaderboardNameColumn, stringMessages.regatta());
leaderboardsTable.addColumn(overviewColumn, "");
if (showRaceDetails) {
SafeHtmlCell racesCell = new SafeHtmlCell();
Column<StrippedLeaderboardDTO, SafeHtml> racesColumn = new Column<StrippedLeaderboardDTO, SafeHtml>(
racesCell) {
@Override
public SafeHtml getValue(StrippedLeaderboardDTO leaderboard) {
switch(racesRenderStrategy) {
switch(raceRenderingStrategy) {
case DEFAULT: return leaderboardRacesToHtml(leaderboard);
case ESS40: ess40LeaderboardRacesToHtml(leaderboard);
case ESS40: return ess40LeaderboardRacesToHtml(leaderboard);
}
return null;
@@ -301,25 +310,73 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
}
} else {
List<RaceColumnDTO> raceColumns = leaderboard.getRaceList();
renderRacesToHTml(leaderboard, raceColumns, new FleetDTO("Default", 0, null), b);
renderRacesToHTml(leaderboard.name, raceColumns, new FleetDTO("Default", 0, null), b);
}
return b.toSafeHtml();
}
private SafeHtml ess40LeaderboardRacesToHtml(StrippedLeaderboardDTO leaderboard) {
SafeHtmlBuilder b = new SafeHtmlBuilder();
if (leaderboard.isRegattaLeaderboard && leaderboard.regattaName != null) {
RegattaDTO regatta = regattasByName.get(leaderboard.regattaName);
boolean renderSeriesName = Util.size(regatta.series) > 1;
for (SeriesDTO series : regatta.series) {
b.appendHtmlConstant("<div>");
renderSeriesToHtml(leaderboard, series, renderSeriesName, b);
if (!leaderboard.isRegattaLeaderboard) {
FleetDTO defaultFleet = new FleetDTO("Default", 0, null);
DateTimeFormat format = DateTimeFormat.getFormat("yyyy-MM-dd");
DateTimeFormat dayFormat = DateTimeFormat.getFormat("MMMM d");
List<RaceColumnDTO> racesWithUnknownDate = new ArrayList<RaceColumnDTO>();
Map<String, List<RaceColumnDTO>> orderedRacesByDay = new TreeMap<String, List<RaceColumnDTO>>();
List<RaceColumnDTO> lastRacesPerDayList = null;
for (RaceColumnDTO raceColumn : leaderboard.getRaceList()) {
RaceDTO race = raceColumn.getRace(defaultFleet);
if(race != null && race.startOfRace != null) {
String day = format.format(race.startOfRace);
List<RaceColumnDTO> racesPerDay = orderedRacesByDay.get(day);
if(racesPerDay == null) {
racesPerDay = new ArrayList<RaceColumnDTO>();
orderedRacesByDay.put(day, racesPerDay);
lastRacesPerDayList = racesPerDay;
}
if(!racesWithUnknownDate.isEmpty()) {
racesPerDay.addAll(racesWithUnknownDate);
racesWithUnknownDate.clear();
}
racesPerDay.add(raceColumn);
} else {
racesWithUnknownDate.add(raceColumn);
}
}
if(!racesWithUnknownDate.isEmpty()) {
if(lastRacesPerDayList == null) {
// all races have an unknown date
orderedRacesByDay.put("unknown", racesWithUnknownDate);
} else {
// add the remaining list of races with unknown date to the last day
lastRacesPerDayList.addAll(racesWithUnknownDate);
}
}
for(List<RaceColumnDTO> raceColumnsPerDay: orderedRacesByDay.values()) {
b.appendHtmlConstant("<div style=\"float:left;\">");
for (RaceColumnDTO raceColumn : raceColumnsPerDay) {
RaceDTO race = raceColumn.getRace(defaultFleet);
if(race != null && race.startOfRace != null) {
String dayAsText = dayFormat.format(race.startOfRace);
b.append(TEXTTEMPLATE.textWithClass(dayAsText, 100, STYLE_TABLE_TEXT));
break;
}
}
for (RaceColumnDTO raceColumn : raceColumnsPerDay) {
String raceColumnName = raceColumn.getRaceColumnName();
RaceDTO race = raceColumn.getRace(defaultFleet);
renderRaceLink(leaderboard.name, race, raceColumnName, b);
}
b.appendHtmlConstant("</div>");
b.appendHtmlConstant("<div style=\"clear:both;\"></div>");
b.appendHtmlConstant("</div>");
}
} else {
List<RaceColumnDTO> raceColumns = leaderboard.getRaceList();
renderRacesToHTml(leaderboard, raceColumns, new FleetDTO("Default", 0, null), b);
}
return b.toSafeHtml();
}
@@ -330,7 +387,7 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
b.appendHtmlConstant("<div style=\"float:left;\">");
if(renderSeriesName) {
b.append(TEXTTEMPLATE.textWithClass(series.name, 50, STYLE_NAME_PREFIX + "Fleet"));
b.append(TEXTTEMPLATE.textWithClass(series.name, 50, STYLE_TABLE_TEXT));
}
b.appendHtmlConstant("</div>");
@@ -344,52 +401,57 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
if (hasMultipleFleets) {
if(color != null) {
b.append(COLORBOXTEMPLATE.colorBox(color.getAsHtml(), STYLE_NAME_PREFIX + "ColorBox"));
b.append(COLORBOXTEMPLATE.colorBox(color.getAsHtml(), STYLE_COLORBOX));
}
b.append(TEXTTEMPLATE.textWithClass(fleet.name, 50, STYLE_NAME_PREFIX + "Fleet"));
b.append(TEXTTEMPLATE.textWithClass(fleet.name, 50, STYLE_TABLE_TEXT));
} else {
String displayName = fleet.name;
if ("Default".equals(fleet.name)) {
b.append(TEXTTEMPLATE.textWithClass("", 70, STYLE_NAME_PREFIX + "Fleet"));
b.append(TEXTTEMPLATE.textWithClass("", 70, STYLE_TABLE_TEXT));
} else {
b.append(TEXTTEMPLATE.textWithClass(displayName, 50, STYLE_NAME_PREFIX + "Fleet"));
b.append(TEXTTEMPLATE.textWithClass(displayName, 50, STYLE_TABLE_TEXT));
}
}
renderRacesToHTml(leaderboard, raceColumns, fleet, b);
renderRacesToHTml(leaderboard.name, raceColumns, fleet, b);
b.appendHtmlConstant("</div>");
}
b.appendHtmlConstant("</div>");
}
private void renderRacesToHTml(StrippedLeaderboardDTO leaderboard, List<RaceColumnDTO> raceColumns, FleetDTO fleet, SafeHtmlBuilder b) {
String debugParam = Window.Location.getParameter("gwt.codesvr");
private void renderRacesToHTml(String leaderboardName, List<RaceColumnDTO> raceColumns, FleetDTO fleet, SafeHtmlBuilder b) {
for (RaceColumnDTO raceColumn : raceColumns) {
String linkText = raceColumn.getRaceColumnName();
String raceColumnName = raceColumn.getRaceColumnName();
RaceDTO race = raceColumn.getRace(fleet);
if (race != null) {
RegattaAndRaceIdentifier raceIdentifier = race.getRaceIdentifier();
String link = URLFactory.INSTANCE.encode("/gwt/RaceBoard.html?leaderboardName=" + leaderboard.name
+ "&raceName=" + raceIdentifier.getRaceName() + "&root=" + root + raceIdentifier.getRaceName()
+ "&regattaName=" + raceIdentifier.getRegattaName() + "&leaderboardGroupName=" + leaderboardGroup.name);
if (debugParam != null && !debugParam.isEmpty()) {
link += "&gwt.codesvr=" + debugParam;
}
if (viewMode != null && !viewMode.isEmpty()) {
link += "&viewMode=" + viewMode;
}
if (race.trackedRace.hasGPSData && race.trackedRace.hasWindData) {
b.append(getAnchor(link, linkText, STYLE_ACTIVE_RACE));
} else {
b.append(TEXTTEMPLATE.textWithClass(linkText, STYLE_INACTIVE_RACE));
}
} else {
b.append(TEXTTEMPLATE.textWithClass(linkText, STYLE_INACTIVE_RACE));
}
renderRaceLink(leaderboardName, race, raceColumnName, b);
}
}
private void renderRaceLink(String leaderboardName, RaceDTO race, String raceColumnName, SafeHtmlBuilder b) {
String debugParam = Window.Location.getParameter("gwt.codesvr");
if (race != null) {
RegattaAndRaceIdentifier raceIdentifier = race.getRaceIdentifier();
String link = URLFactory.INSTANCE.encode("/gwt/RaceBoard.html?leaderboardName=" + leaderboardName
+ "&raceName=" + raceIdentifier.getRaceName() + "&root=" + root + raceIdentifier.getRaceName()
+ "&regattaName=" + raceIdentifier.getRegattaName() + "&leaderboardGroupName=" + leaderboardGroup.name);
if (debugParam != null && !debugParam.isEmpty()) {
link += "&gwt.codesvr=" + debugParam;
}
if (viewMode != null && !viewMode.isEmpty()) {
link += "&viewMode=" + viewMode;
}
if (race.trackedRace.hasGPSData && race.trackedRace.hasWindData) {
b.append(getAnchor(link, raceColumnName, STYLE_ACTIVE_RACE));
} else {
b.append(TEXTTEMPLATE.textWithClass(raceColumnName, STYLE_INACTIVE_RACE));
}
} else {
b.append(TEXTTEMPLATE.textWithClass(raceColumnName, STYLE_INACTIVE_RACE));
}
}
private Map<String, List<RaceColumnDTO>> getRacesOrderedByFleets(StrippedLeaderboardDTO leaderboard) {
Map<String, List<RaceColumnDTO>> racesOrderedByFleets = new LinkedHashMap<String, List<RaceColumnDTO>>();
@@ -12,7 +12,7 @@ import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Person;
@@ -162,22 +162,22 @@ public class RegattaAndRaceDataJsonExportServlet extends JsonExportServlet {
for (Waypoint waypoint : trackedRace.getRace().getCourse().getWaypoints()) {
JSONObject jsonWaypoint = new JSONObject();
jsonWaypoint.put("name", waypoint.getName());
JSONArray jsonBuoys = new JSONArray();
for (Buoy buoy : waypoint.getBuoys()) {
JSONObject jsonBuoy = new JSONObject();
jsonBuoy.put("name", buoy.getName());
GPSFixTrack<Buoy, GPSFix> buoyTrack = trackedRace.getOrCreateTrack(buoy);
GPSFix lastFixAtOrBefore = buoyTrack.getLastFixAtOrBefore(timePoint);
JSONArray jsonMarks = new JSONArray();
for (Mark mark : waypoint.getMarks()) {
JSONObject jsonMark = new JSONObject();
jsonMark.put("name", mark.getName());
GPSFixTrack<Mark, GPSFix> markTrack = trackedRace.getOrCreateTrack(mark);
GPSFix lastFixAtOrBefore = markTrack.getLastFixAtOrBefore(timePoint);
if (lastFixAtOrBefore != null) {
Position buoyPosition = lastFixAtOrBefore.getPosition();
if (buoyPosition != null) {
jsonBuoy.put("lat", buoyPosition.getLatDeg());
jsonBuoy.put("lng", buoyPosition.getLngDeg());
Position markPosition = lastFixAtOrBefore.getPosition();
if (markPosition != null) {
jsonMark.put("lat", markPosition.getLatDeg());
jsonMark.put("lng", markPosition.getLngDeg());
}
}
jsonBuoys.add(jsonBuoy);
jsonMarks.add(jsonMark);
}
jsonWaypoint.put("buoys", jsonBuoys);
jsonWaypoint.put("marks", jsonMarks);
jsonWaypoints.add(jsonWaypoint);
}
setJsonResponseHeader(resp);
@@ -219,7 +219,7 @@ public class RegattaAndRaceDataJsonExportServlet extends JsonExportServlet {
Position positionForWind = null;
TrackedLeg currentLeg = trackedRace.getCurrentLeg(timePoint);
if (currentLeg != null) {
positionForWind = trackedRace.getOrCreateTrack(currentLeg.getLeg().getFrom().getBuoys().iterator().next())
positionForWind = trackedRace.getOrCreateTrack(currentLeg.getLeg().getFrom().getMarks().iterator().next())
.getEstimatedPosition(timePoint, false);
}
Wind currentWind = trackedRace.getWind(positionForWind, timePoint);
@@ -87,9 +87,9 @@ public class ServerReplicationTest extends AbstractServerReplicationTest {
new ArrayList<Competitor>());
AddRaceDefinition addRaceOperation = new AddRaceDefinition(new RegattaName(regatta.getName()), race);
master.apply(addRaceOperation);
masterCourse.addWaypoint(0, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateBuoy("Buoy1")));
masterCourse.addWaypoint(1, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateBuoy("Buoy2")));
masterCourse.addWaypoint(2, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateBuoy("Buoy3")));
masterCourse.addWaypoint(0, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateMark("Mark1")));
masterCourse.addWaypoint(1, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateMark("Mark2")));
masterCourse.addWaypoint(2, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateMark("Mark3")));
masterCourse.removeWaypoint(1);
Thread.sleep(1000); // wait 1s for JMS to deliver the message and the message to be applied
Regatta replicaEvent = replica.getRegatta(new RegattaName(regatta.getName()));
@@ -98,7 +98,7 @@ public class ServerReplicationTest extends AbstractServerReplicationTest {
assertNotNull(replicaRace);
Course replicaCourse = replicaRace.getCourse();
assertEquals(2, Util.size(replicaCourse.getWaypoints()));
assertEquals("Buoy1", replicaCourse.getFirstWaypoint().getBuoys().iterator().next().getName());
assertEquals("Buoy3", replicaCourse.getLastWaypoint().getBuoys().iterator().next().getName());
assertEquals("Mark1", replicaCourse.getFirstWaypoint().getMarks().iterator().next().getName());
assertEquals("Mark3", replicaCourse.getLastWaypoint().getMarks().iterator().next().getName());
}
}
@@ -15,7 +15,7 @@ import org.junit.Test;
import com.mongodb.MongoException;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Regatta;
@@ -80,9 +80,9 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
RaceDefinition race = new RaceDefinitionImpl(raceName, masterCourse, boatClass, Collections.singletonList(competitor));
AddRaceDefinition addRaceOperation = new AddRaceDefinition(new RegattaName(regatta.getName()), race);
master.apply(addRaceOperation);
masterCourse.addWaypoint(0, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateBuoy("Buoy1")));
masterCourse.addWaypoint(1, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateBuoy("Buoy2")));
masterCourse.addWaypoint(2, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateBuoy("Buoy3")));
masterCourse.addWaypoint(0, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateMark("Mark1")));
masterCourse.addWaypoint(1, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateMark("Mark2")));
masterCourse.addWaypoint(2, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateMark("Mark3")));
masterCourse.removeWaypoint(1);
raceIdentifier = new RegattaNameAndRaceName(regatta.getName(), raceName);
trackedRegatta = master.apply(new TrackRegatta(raceIdentifier));
@@ -114,23 +114,23 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
}
@Test
public void testBuoyFixReplication() throws InterruptedException {
public void testMarkFixReplication() throws InterruptedException {
final GPSFixMovingImpl fix = new GPSFixMovingImpl(new DegreePosition(2, 3), new MillisecondsTimePoint(3456),
new KnotSpeedWithBearingImpl(13, new DegreeBearingImpl(234)));
final Buoy masterBuoy = trackedRace.getRace().getCourse().getFirstWaypoint().getBuoys().iterator().next();
trackedRace.recordFix(masterBuoy, fix);
final Mark masterMark = trackedRace.getRace().getCourse().getFirstWaypoint().getMarks().iterator().next();
trackedRace.recordFix(masterMark, fix);
Thread.sleep(1000);
TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
Buoy replicaBuoy = replicaTrackedRace.getRace().getCourse().getFirstWaypoint().getBuoys().iterator().next();
// assertNotSame(replicaBuoy, masterBuoy); // TODO this would require solving bug 592
GPSFixTrack<Buoy, GPSFix> replicaBuoyTrack = replicaTrackedRace.getOrCreateTrack(replicaBuoy);
replicaBuoyTrack.lockForRead();
Mark replicaMark = replicaTrackedRace.getRace().getCourse().getFirstWaypoint().getMarks().iterator().next();
// assertNotSame(replicaMark, masterMark); // TODO this would require solving bug 592
GPSFixTrack<Mark, GPSFix> replicaMarkTrack = replicaTrackedRace.getOrCreateTrack(replicaMark);
replicaMarkTrack.lockForRead();
try {
assertEquals(1, Util.size(replicaBuoyTrack.getRawFixes()));
assertEquals(replicaBuoyTrack.getRawFixes().iterator().next(), fix);
assertNotSame(fix, replicaBuoyTrack.getRawFixes().iterator().next());
assertEquals(1, Util.size(replicaMarkTrack.getRawFixes()));
assertEquals(replicaMarkTrack.getRawFixes().iterator().next(), fix);
assertNotSame(fix, replicaMarkTrack.getRawFixes().iterator().next());
} finally {
replicaBuoyTrack.unlockAfterRead();
replicaMarkTrack.unlockAfterRead();
}
}
@@ -27,7 +27,7 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Event;
@@ -106,7 +106,7 @@ import com.sap.sailing.server.operationaltransformation.AddRaceDefinition;
import com.sap.sailing.server.operationaltransformation.AddSpecificRegatta;
import com.sap.sailing.server.operationaltransformation.ConnectTrackedRaceToLeaderboardColumn;
import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
import com.sap.sailing.server.operationaltransformation.RecordBuoyGPSFix;
import com.sap.sailing.server.operationaltransformation.RecordMarkGPSFix;
import com.sap.sailing.server.operationaltransformation.RecordCompetitorGPSFix;
import com.sap.sailing.server.operationaltransformation.RecordWindFix;
import com.sap.sailing.server.operationaltransformation.RemoveWindFix;
@@ -894,8 +894,8 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
}
@Override
public void buoyPositionChanged(GPSFix fix, Buoy buoy) {
replicate(new RecordBuoyGPSFix(getRaceIdentifier(), buoy, fix));
public void markPositionChanged(GPSFix fix, Mark mark) {
replicate(new RecordMarkGPSFix(getRaceIdentifier(), mark, fix));
}
@Override
@@ -1,27 +1,27 @@
package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.RacingEventServiceOperation;
public class RecordBuoyGPSFix extends AbstractRaceOperation<Void> {
public class RecordMarkGPSFix extends AbstractRaceOperation<Void> {
private static final long serialVersionUID = -2149936580623244814L;
private final Buoy buoy;
private final Mark mark;
private final GPSFix fix;
public RecordBuoyGPSFix(RegattaAndRaceIdentifier raceIdentifier, Buoy buoy, GPSFix fix) {
public RecordMarkGPSFix(RegattaAndRaceIdentifier raceIdentifier, Mark mark, GPSFix fix) {
super(raceIdentifier);
this.buoy = buoy;
this.mark = mark;
this.fix = fix;
}
@Override
public Void internalApplyTo(RacingEventService toState) throws Exception {
DynamicTrackedRace trackedRace = (DynamicTrackedRace) toState.getTrackedRace(getRaceIdentifier());
trackedRace.recordFix(buoy, fix);
trackedRace.recordFix(mark, fix);
return null;
}
@@ -85,7 +85,7 @@ public class GPSPerRace extends Action {
addRow();
addColumn(legId);
addColumn(markName);
addColumn(leg.getTo().getBuoys().iterator().next().getName());
addColumn(leg.getTo().getMarks().iterator().next().getName());
addColumn(upOrDownwinLeg);
addColumn(competitorName);
addColumn(sailID == null ? "null" : sailID);
@@ -83,7 +83,7 @@ public class RankPerLeg extends Action {
addRow();
addColumn(legId);
addColumn(markName);
addColumn(leg.getTo().getBuoys().iterator().next().getName());
addColumn(leg.getTo().getMarks().iterator().next().getName());
addColumn(upOrDownwindLeg);
addColumn(competitorName);
addColumn(sailID == null ? "null" : sailID);
@@ -93,7 +93,7 @@ public class RankPerLeg2 extends Action {
} else {
addColumn(markName);
}
addColumn(leg == null ? "null" : leg.getTo().getBuoys().iterator().next().getName());
addColumn(leg == null ? "null" : leg.getTo().getMarks().iterator().next().getName());
addColumn(upOrDownwinLeg);
addColumn(competitorName);