diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java index ba165f37cc1..23b7ebb5e21 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java @@ -1128,6 +1128,11 @@ public class MockedTrackedRace implements DynamicTrackedRace { return Collections.emptySet(); } + @Override + public NavigableSet getMarkPassings(Competitor competitor, boolean waitForLatestUpdates) { + return null; + } + @Override public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) { return null; diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java index 30cdeb5e6ac..9f596ddc595 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java @@ -682,6 +682,11 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace { return Collections.emptySet(); } + @Override + public NavigableSet getMarkPassings(Competitor competitor, boolean waitForLatestUpdates) { + return null; + } + @Override public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) { return null; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/MarkPassingCalculator.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/MarkPassingCalculator.java index 32f29af56d5..8539ef86d47 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/MarkPassingCalculator.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/MarkPassingCalculator.java @@ -26,6 +26,8 @@ import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Triple; import com.sap.sse.common.util.IntHolder; +import com.sap.sse.concurrent.LockUtil; +import com.sap.sse.concurrent.NamedReentrantReadWriteLock; import com.sap.sse.util.ThreadPoolUtil; /** @@ -60,14 +62,16 @@ public class MarkPassingCalculator { * started and then terminated again. */ private final Thread listenerThread; + + private final Listen listen; /** * Synchronized using the {@link #listenerThread} as monitor object. */ private boolean listenerThreadStarted; - public MarkPassingCalculator(DynamicTrackedRace race, boolean listen, boolean waitForInitialMarkPassingCalculation) { - if (listen) { + public MarkPassingCalculator(DynamicTrackedRace race, boolean doListen, boolean waitForInitialMarkPassingCalculation) { + if (doListen) { listener = new MarkPassingUpdateListener(race); } else { listener = null; @@ -75,10 +79,12 @@ public class MarkPassingCalculator { this.race = race; finder = new CandidateFinderImpl(race, executor); chooser = new CandidateChooserImpl(race); - if (listen) { - listenerThread = new Thread(new Listen(race.getRace().getName()), "MarkPassingCalculator for race " + race.getRace().getName()); + if (doListen) { + listen = new Listen(race.getRace().getName()); + listenerThread = new Thread(listen, "MarkPassingCalculator for race " + race.getRace().getName()); } else { listenerThread = null; + listen = null; } Thread t = new Thread(() -> { final Set> tasks = new HashSet<>(); @@ -94,7 +100,7 @@ public class MarkPassingCalculator { } catch (Exception e) { logger.log(Level.SEVERE, "Error trying to compute initial set of mark passings for race "+race.getRace().getName(), e); } - if (listen) { + if (doListen) { listenerThread.setDaemon(true); listenerThread.start(); synchronized (listenerThread) { @@ -131,6 +137,28 @@ public class MarkPassingCalculator { } } + /** + * It's used for locking the calculation thread for read. You will be blocked if the calculation is in progress. + * Make sure that you unlock the thread with the method {@link MarkPassingCalculator#unlockForRead()} once you don't + * need it any more, using a {@code finally} clause to ensure unlocking even with abnormal termination. + */ + public void lockForRead() { + if (listen != null) { + listen.lockForRead(); + } + } + + /** + * Unlocks the calculation thread for read. + * + * @see #lockForRead + */ + public void unlockForRead() { + if (listen != null) { + listen.unlockAfterRead(); + } + } + /** * Waits until an object is in the queue, then drains it entirely. After that the information is sorted depending on * whether it is a fix, an updated waypoint or an updated fixed markpassing. Finally, if suspended is @@ -143,8 +171,25 @@ public class MarkPassingCalculator { private class Listen implements Runnable { private final String raceName; + /** + * The write lock is being held by the thread running this {@link Runnable} after successfully having + * waited for the next update to be pushed to the {@link MarkPassingUpdateListener#getQueue() queue}, + * before draining the queue starts and until the processing of all events from the queue has completed. + * This way, trying to obtain the read lock will block until all pending updates have been processed. + */ + private final NamedReentrantReadWriteLock lock; + public Listen(String raceName) { this.raceName = raceName; + lock = new NamedReentrantReadWriteLock("lock for calculation thread (" + Listen.class.getSimpleName() + ")", /* fair */ false); + } + + public void lockForRead() { + LockUtil.lockForRead(lock); + } + + public void unlockAfterRead() { + LockUtil.unlockAfterRead(lock); } @Override @@ -171,6 +216,7 @@ public class MarkPassingCalculator { logger.log(Level.SEVERE, "MarkPassingCalculator for "+raceName+" threw exception " + e.getMessage() + " while waiting for new GPSFixes"); } + LockUtil.lockForWrite(lock); listener.getQueue().drainTo(allNewFixInsertions); logger.fine("MPC for "+raceName+" received "+ allNewFixInsertions.size()+" new updates."); for (StorePositionUpdateStrategy fixInsertion : allNewFixInsertions) { @@ -225,6 +271,8 @@ public class MarkPassingCalculator { } } catch (Exception e) { logger.log(Level.SEVERE, "Error while calculating markpassings for race "+raceName+": " + e.getMessage(), e); + } finally { + LockUtil.unlockAfterWrite(lock); } } } finally { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java index d864ae66e80..c9f4e7ec66d 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java @@ -45,6 +45,7 @@ import com.sap.sailing.domain.common.racelog.RacingProcedureType; import com.sap.sailing.domain.common.tracking.GPSFix; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.common.tracking.SensorFix; +import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; @@ -435,6 +436,17 @@ public interface TrackedRace extends Serializable, IsManagedByCache getMarkPassings(Competitor competitor); + + /** + * Returns competitor's mark passings. + * + * @param waitForLatestUpdates + * if any mark passing updates are pending because some calculations are currently going on and updates + * haven't all been processed yet then the call will block until these updates have been processed in + * case this parameter is set to {@code true}. For this the method uses a lock on the + * {@link MarkPassingCalculator }to block the thread until all calculations will be finished. + */ + NavigableSet getMarkPassings(Competitor competitor, boolean waitForLatestUpdates); /** * This obtains the course's read lock before asking for the read lock for the markPassings structure. diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index bcb33ab5215..2d40b49208c 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -707,7 +707,21 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl @Override public NavigableSet getMarkPassings(Competitor competitor) { - return markPassingsForCompetitor.get(competitor); + return getMarkPassings(competitor, /* waitForLatestUpdates */ false); + } + + @Override + public NavigableSet getMarkPassings(Competitor competitor, boolean waitForLatestUpdates) { + if (waitForLatestUpdates && markPassingCalculator != null) { + markPassingCalculator.lockForRead(); + } + try { + return markPassingsForCompetitor.get(competitor); + } finally { + if (waitForLatestUpdates && markPassingCalculator != null) { + markPassingCalculator.unlockForRead(); + } + } } protected NavigableSet getMarkPassingsInOrderAsNavigableSet(Waypoint waypoint) { diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java index 00050caffca..c948deb2535 100644 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java @@ -861,6 +861,11 @@ public class MockedTrackedRace implements DynamicTrackedRace { return Collections.emptySet(); } + @Override + public NavigableSet getMarkPassings(Competitor competitor, boolean waitForLatestUpdates) { + return null; + } + @Override public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) { return null; diff --git a/java/com.sap.sailing.gwt.ui/Spectator.css b/java/com.sap.sailing.gwt.ui/Spectator.css index dc81d3c43ff..6f55fe4310c 100644 --- a/java/com.sap.sailing.gwt.ui/Spectator.css +++ b/java/com.sap.sailing.gwt.ui/Spectator.css @@ -23,6 +23,9 @@ top: -1000px; } +html { + font-size: 15px; +} body { background: url(images/spectatorview-bg.png) no-repeat left top #ebebeb; @@ -48,7 +51,7 @@ table td,select,button { .contentOuterPanel { background: #dddcdc; - margin: 0 12px 0 12px; + margin: 0 12px 120px; padding: 12px; } @@ -159,6 +162,7 @@ input.magnifier { .mainPanel { width: 100%; margin-left: 13px; + margin-bottom: 120px; } .leaderboardGroupPanel-GroupName { @@ -187,7 +191,8 @@ input.magnifier { margin: 5px 5px 5px 0; text-decoration: none; font-family: 'Open Sans', Arial, Verdana, sans-serif; - font-weight: 600 + font-weight: 600; + box-sizing: content-box; } .leaderboardGroupPanel-BoatClass { @@ -206,8 +211,8 @@ input.magnifier { padding: 5px; display: block; float: left; - width: 8px; - height: 8px; + width: 18px; + height: 18px; border-radius: 4px; -moz-border-radius: 4px; -webkit-border-radius: 4px; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index 2d11ab067f7..4b17e2bcd66 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -528,7 +528,11 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS PolarSheetsXYDiagramData createXYDiagramForBoatClass(String itemText); - Map getCompetitorMarkPassings(RegattaAndRaceIdentifier race, CompetitorDTO competitorDTO); + /** + * @see SailingServiceAsync#getCompetitorMarkPassings(RegattaAndRaceIdentifier, CompetitorDTO, boolean, com.google.gwt.user.client.rpc.AsyncCallback) + */ + Map getCompetitorMarkPassings(RegattaAndRaceIdentifier race, CompetitorDTO competitorDTO, + boolean waitForCalculations); /** * Obtains fixed mark passings and mark passing suppressions from the race log identified by diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index 66e3855174a..28533bf2032 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -695,9 +695,14 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan * the URL pointing to a Manage2Sail JSON document that contains the link to the XRR document */ void getRegattas(String manage2SailJsonUrl, AsyncCallback> asyncCallback); - + + /** + * Returns mark passings for the competitor. Using the {@code waitForCalculations} parameter callers can control + * whether to obtain a snapshot immediately of wait for pending updates. Waiting may be desirable, e.g., when having + * submitted a fixed mark passing into a race log which triggers the re-calculations asynchronously. + */ void getCompetitorMarkPassings(RegattaAndRaceIdentifier race, CompetitorDTO competitorDTO, - AsyncCallback> callback); + boolean waitForCalculations, AsyncCallback> callback); void getCompetitorRaceLogMarkPassingData(String leaderboardName, String raceColumnName, String fleetName, CompetitorDTO competitor, AsyncCallback> callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/AbstractCompetitorRaceChart.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/AbstractCompetitorRaceChart.java index 71a165375af..75efb151e86 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/AbstractCompetitorRaceChart.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/AbstractCompetitorRaceChart.java @@ -384,6 +384,8 @@ public abstract class AbstractCompetitorRaceChart() { @Override public void onFailure(Throwable caught) { @@ -314,11 +315,17 @@ public class EditMarkPassingsPanel extends AbsolutePanel implements Component>() { + sailingService.getCompetitorMarkPassings(raceIdentifier, competitor, true, new AsyncCallback>() { @Override public void onFailure(Throwable caught) { errorReporter.reportError(stringMessages.errorTryingToObtainMarkPassing(caught.getMessage())); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/WindChart.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/WindChart.java index 839ead23c27..2ab315d1fd4 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/WindChart.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/WindChart.java @@ -103,6 +103,7 @@ public class WindChart extends AbstractRaceChart implements R colorMap = new ColorMapImpl(); chart = new Chart() .setPersistent(true) + .setReflow(false) .setZoomType(BaseChart.ZoomType.X) .setMarginLeft(65) .setMarginRight(65) @@ -115,7 +116,7 @@ public class WindChart extends AbstractRaceChart implements R .setPlotBackgroundColor("#f8f8f8") .setPlotBorderWidth(0) .setCredits(new Credits().setEnabled(false)) - .setChartTitle(new ChartTitle().setText(stringMessages.wind())) + .setChartTitle(new ChartTitle().setText(stringMessages.wind()).setOption("floating",true)) .setChartSubtitle(new ChartSubtitle().setText(stringMessages.clickAndDragToZoomIn())) .setLinePlotOptions(new LinePlotOptions().setLineWidth(LINE_WIDTH).setMarker( new Marker().setEnabled(false).setHoverState( @@ -182,7 +183,7 @@ public class WindChart extends AbstractRaceChart implements R chart.getYAxis(1).setOpposite(true).setAxisTitleText(stringMessages.speed()+" ("+stringMessages.knotsUnit()+")").setMin(0) .setMaxPadding(0.05).setStartOnTick(false).setGridLineWidth(0).setMinorGridLineWidth(0); if (compactChart) { - chart.setSpacingBottom(10).setSpacingLeft(10).setSpacingRight(10).setSpacingTop(2) + chart.setSpacingBottom(10).setSpacingLeft(10).setSpacingRight(10).setSpacingTop(20) .setOption("legend/margin", 2) .setOption("title/margin", 5) .setChartSubtitle(null) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CourseMarkOverlay.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CourseMarkOverlay.java index a0a973708a5..8645ad390d9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CourseMarkOverlay.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CourseMarkOverlay.java @@ -9,13 +9,16 @@ import com.google.gwt.maps.client.MapWidget; import com.google.gwt.maps.client.base.LatLng; import com.google.gwt.maps.client.base.Point; import com.google.gwt.maps.client.base.Size; +import com.sap.sailing.domain.common.Bearing; import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.MarkType; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.impl.MeterDistance; +import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO; import com.sap.sailing.gwt.ui.shared.MarkDTO; import com.sap.sailing.gwt.ui.shared.racemap.CanvasOverlayV3; import com.sap.sailing.gwt.ui.shared.racemap.MarkVectorGraphics; +import com.sap.sailing.gwt.ui.shared.racemap.MarkVectorGraphicsFactory; import com.sap.sse.common.Util; /** @@ -26,6 +29,8 @@ public class CourseMarkOverlay extends CanvasOverlayV3 { * The course mark to draw */ private final MarkDTO mark; + + private CoursePositionsDTO coursePositionsDTO; private Position position; @@ -45,18 +50,22 @@ public class CourseMarkOverlay extends CanvasOverlayV3 { private Boolean lastShowBuoyZone; private Boolean lastIsSelected; private Distance lastBuoyZoneRadius; + + private MarkVectorGraphicsFactory markVectorGraphicsFactory; - public CourseMarkOverlay(MapWidget map, int zIndex, MarkDTO markDTO, CoordinateSystem coordinateSystem) { + public CourseMarkOverlay(MapWidget map, int zIndex, MarkDTO markDTO, CoordinateSystem coordinateSystem, CoursePositionsDTO coursePositionsDTO) { super(map, zIndex, coordinateSystem); this.mark = markDTO; + this.coursePositionsDTO = coursePositionsDTO; this.position = markDTO.position; this.buoyZoneRadius = new MeterDistance(0.0); this.showBuoyZone = false; - markVectorGraphics = new MarkVectorGraphics(markDTO.type, markDTO.color, markDTO.shape, markDTO.pattern); - markScaleAndSizePerZoomCache = new HashMap>(); + this.markScaleAndSizePerZoomCache = new HashMap>(); + this.markVectorGraphicsFactory = new MarkVectorGraphicsFactory(); + this.markVectorGraphics = markVectorGraphicsFactory.getMarkVectorGraphics(markDTO); setCanvasSize(50, 50); } - + @Override protected void draw() { if (mapProjection != null && mark != null && position != null) { @@ -104,6 +113,10 @@ public class CourseMarkOverlay extends CanvasOverlayV3 { lastWidth = canvasWidth; lastHeight = canvasHeight; } + final Bearing rotation = markVectorGraphics.getRotationInDegrees(coursePositionsDTO); + if (rotation != null) { + setCanvasRotation(rotation.getDegrees()); + } Point buoyPositionInPx = mapProjection.fromLatLngToDivPixel(coordinateSystem.toLatLng(position)); if (showBuoyZone && isMarkWithBuoyZone(mark) && buoyZoneRadiusInPixel > MIN_BUOYZONE_RADIUS_IN_PX) { setCanvasPosition(buoyPositionInPx.getX() - buoyZoneRadiusInPixel, buoyPositionInPx.getY() - buoyZoneRadiusInPixel); @@ -112,7 +125,7 @@ public class CourseMarkOverlay extends CanvasOverlayV3 { } } } - + private boolean isMarkWithBuoyZone(MarkDTO mark) { return mark.type == null || mark.type == MarkType.BUOY || mark.type == MarkType.STARTBOAT || mark.type == MarkType.FINISHBOAT || mark.type == MarkType.LANDMARK; @@ -159,6 +172,10 @@ public class CourseMarkOverlay extends CanvasOverlayV3 { public void setShowBuoyZone(boolean showBuoyZone) { this.showBuoyZone = showBuoyZone; } + + public void setCourse(CoursePositionsDTO coursePositionsDTO) { + this.coursePositionsDTO = coursePositionsDTO; + } public MarkDTO getMark() { return mark; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java index cf0841873e9..4b48619d7c3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java @@ -1125,7 +1125,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe } CourseMarkOverlay courseMarkOverlay = courseMarkOverlays.get(markDTO.getName()); if (courseMarkOverlay == null) { - courseMarkOverlay = new CourseMarkOverlay(map, RaceMapOverlaysZIndexes.COURSEMARK_ZINDEX, markDTO, coordinateSystem); + courseMarkOverlay = new CourseMarkOverlay(map, RaceMapOverlaysZIndexes.COURSEMARK_ZINDEX, markDTO, coordinateSystem, courseDTO); courseMarkOverlay.setShowBuoyZone(settings.getHelpLinesSettings().isVisible(HelpLineTypes.BUOYZONE)); courseMarkOverlay.setBuoyZoneRadius(settings.getBuoyZoneRadius()); courseMarkOverlay.setSelected(isSelected); @@ -1138,6 +1138,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe courseMarkOverlay.setShowBuoyZone(settings.getHelpLinesSettings().isVisible(HelpLineTypes.BUOYZONE)); courseMarkOverlay.setBuoyZoneRadius(settings.getBuoyZoneRadius()); courseMarkOverlay.setSelected(isSelected); + courseMarkOverlay.setCourse(courseDTO); courseMarkOverlay.draw(); toRemoveCourseMarks.remove(markDTO.getName()); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java index 3d4056386e1..e85b336979c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java @@ -1288,7 +1288,8 @@ public class LeaderboardPanel extends SimplePanel implements Component { @Override public Double get(LeaderboardRowDTO row) { - return row.getDistanceTraveledInMeters(getRaceColumnName()).getMeters(); + Distance distanceForRaceColumn = row.getDistanceTraveledInMeters(getRaceColumnName()); + return distanceForRaceColumn == null ? null : distanceForRaceColumn.getMeters(); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index ffcf6f905f3..c9af96ba985 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -5805,12 +5805,13 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public Map getCompetitorMarkPassings(RegattaAndRaceIdentifier race, CompetitorDTO competitorDTO) { + public Map getCompetitorMarkPassings(RegattaAndRaceIdentifier race, CompetitorDTO competitorDTO, boolean waitForCalculations) { Map result = new HashMap<>(); final TrackedRace trackedRace = getExistingTrackedRace(race); if (trackedRace != null) { Competitor competitor = getCompetitorByIdAsString(trackedRace.getRace().getCompetitors(), competitorDTO.getIdAsString()); - Set competitorMarkPassings = trackedRace.getMarkPassings(competitor); + Set competitorMarkPassings; + competitorMarkPassings = trackedRace.getMarkPassings(competitor, waitForCalculations); Iterable waypoints = trackedRace.getRace().getCourse().getWaypoints(); if (competitorMarkPassings != null) { for (MarkPassing markPassing : competitorMarkPassings) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/AbstractMarkVectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/AbstractMarkVectorGraphics.java new file mode 100644 index 00000000000..c2fb3578a39 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/AbstractMarkVectorGraphics.java @@ -0,0 +1,199 @@ +package com.sap.sailing.gwt.ui.shared.racemap; + +import com.google.gwt.canvas.dom.client.CanvasGradient; +import com.google.gwt.canvas.dom.client.Context2d; +import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.Distance; +import com.sap.sailing.domain.common.MarkType; +import com.sap.sailing.domain.common.impl.MeterDistance; +import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO; + +/** + * A class for course mark graphics based on SVG graphics drawn to a HTML5 canvas + * The SVG files for the drawing can be found in the package com.sap.sailing.gwt.ui.svg.buoys + * A general description how to convert SVG files to 'drawing commands' can be found at http://wiki.sapsailing.com/wiki/howto/development/boatgraphicssvg + * @author Frank + * + */ +public abstract class AbstractMarkVectorGraphics implements MarkVectorGraphics { + protected Distance markHeightInMeters; + protected Distance markWidthInMeters; + + protected final String color; + protected final String shape; + protected final String pattern; + protected final MarkType type; + + protected static final double doublePi = 2 * Math.PI; + + protected double anchorPointX = 0.44; + protected double anchorPointY = 1.67; + + protected final static String DEFAULT_MARK_COLOR = "#f9ac00"; + protected final static String DEFAULT_MARK_BG_COLOR = "#f0f0f0"; + + public AbstractMarkVectorGraphics(MarkType type, String color, String shape, String pattern) { + this.type = type; + this.color = color; + this.shape = shape; + this.pattern = pattern; + this.markHeightInMeters = new MeterDistance(2.1); + this.markWidthInMeters = new MeterDistance(1.5); + } + + public void drawMarkToCanvas(Context2d ctx, boolean isSelected, double width, double height, double scaleFactor) { + ctx.save(); + ctx.clearRect(0, 0, width, height); + ctx.translate(width / 2.0, height / 2.0); + ctx.scale(scaleFactor, scaleFactor); + ctx.translate(-anchorPointX * 100,- anchorPointY * 100); + String markColor = color != null ? color : DEFAULT_MARK_COLOR; + drawMark(ctx, isSelected, markColor); + ctx.restore(); + } + + public Distance getMarkHeight() { + return markHeightInMeters; + } + + public Distance getMarkWidth() { + return markWidthInMeters; + } + + protected void drawMark(Context2d ctx, boolean isSelected, String color) { + if (isSelected) { + drawMarkSelection(ctx); + } + this.drawMarkBody(ctx, isSelected, color); + } + + protected void drawMarkSelection(Context2d ctx) { + ctx.save(); + + this.setUpScaleAndTranslateForMarkSelection(ctx); + + CanvasGradient g1 = ctx.createLinearGradient(77.8, 188, 165, 219); + g1.addColorStop(0, "rgba(240, 240, 240, 1)"); + g1.addColorStop(1, "rgba(240, 240, 240, 0)"); + ctx.setFillStyle(g1); + ctx.beginPath(); + ctx.moveTo(170, 181); + ctx.translate(44.000168893718424, 180.79369636814624); + ctx.rotate(0); + ctx.scale(1, 1); + ctx.arc(0, 0, 126, 0.0016373311430805408, 0.5254904360229328, false); + ctx.scale(1, 1); + ctx.rotate(0); + ctx.translate(-44.000168893718424, -180.79369636814624); + ctx.lineTo(44.2, 181); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + + CanvasGradient g2 = ctx.createLinearGradient(51, 203, 77.3, 302); + g2.addColorStop(0, "rgba(255, 255, 255, 1)"); + g2.addColorStop(1, "rgba(255, 255, 255, 0)"); + ctx.setFillStyle(g2); + ctx.beginPath(); + ctx.moveTo(107, 290); + ctx.translate(43.79222318749837, 181.0010231680087); + ctx.rotate(0); + ctx.scale(1, 1); + ctx.arc(0, 0, 126, 1.0452923752792398, 1.5667663411841573, false); + ctx.scale(1, 1); + ctx.rotate(0); + ctx.translate(-43.79222318749837, -181.0010231680087); + ctx.lineTo(44.2, 181); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + + CanvasGradient g3 = ctx.createLinearGradient(26.8, 197, -46.5, 269); + g3.addColorStop(0, "rgba(255, 255, 255, 1)"); + g3.addColorStop(1, "rgba(255, 255, 255, 0)"); + ctx.setFillStyle(g3); + ctx.beginPath(); + ctx.moveTo(-18.3, 290); + ctx.translate(43.72636289026038, 180.32443158749652); + ctx.rotate(0); + ctx.scale(1, 1); + ctx.arc(0, 0, 126, 2.0854951576078884, 2.611791628699119, false); + ctx.scale(1, 1); + ctx.rotate(0); + ctx.translate(-43.72636289026038, -180.32443158749652); + ctx.lineTo(44.2, 181); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + + CanvasGradient g4 = ctx.createLinearGradient(18.7, 172, -76.3, 140); + g4.addColorStop(0, "rgba(255, 255, 255, 1)"); + g4.addColorStop(1, "rgba(255, 255, 255, 0)"); + ctx.setFillStyle(g4); + ctx.beginPath(); + ctx.moveTo(-81.8, 179); + ctx.translate(44.19920011832349, 178.55103503179944); + ctx.rotate(0); + ctx.scale(1, 1); + ctx.arc(0, 0, 126, 3.1380294320163484, 3.670248678643417, false); + ctx.scale(1, 1); + ctx.rotate(0); + ctx.translate(-44.19920011832349, -178.55103503179944); + ctx.lineTo(44.2, 179); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + + CanvasGradient g5 = ctx.createLinearGradient(37.9, 147, 13.6, 58.6); + g5.addColorStop(0, "rgba(255, 255, 255, 1)"); + g5.addColorStop(1, "rgba(255, 255, 255, 0)"); + ctx.setFillStyle(g5); + ctx.beginPath(); + ctx.moveTo(-18.7, 71.8); + ctx.translate(44.160311222571984, 180.99973110315514); + ctx.rotate(0); + ctx.scale(1, 1); + ctx.arc(0, 0, 126, -2.0931154263055687, -1.5728622903484606, false); + ctx.scale(1, 1); + ctx.rotate(0); + ctx.translate(-44.160311222571984, -180.99973110315514); + ctx.lineTo(44.199999999999996, 181); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + + CanvasGradient g6 = ctx.createLinearGradient(80.8, 139, 134, 91.9); + g6.addColorStop(0, "rgba(240, 240, 240, 1)"); + g6.addColorStop(1, "rgba(240, 240, 240, 0)"); + ctx.setFillStyle(g6); + ctx.beginPath(); + ctx.moveTo(108, 72.1); + ctx.translate(43.50304481630927, 180.3411325330301); + ctx.rotate(0); + ctx.scale(1, 1); + ctx.arc(0, 0, 126, -1.0334238189446499, -0.5175711746742696, false); + ctx.scale(1, 1); + ctx.rotate(0); + ctx.translate(-43.50304481630927, -180.3411325330301); + ctx.lineTo(44.2, 181); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + + ctx.translate(-49.5, 17.2); + ctx.restore(); + } + + protected void setUpScaleAndTranslateForMarkSelection(Context2d ctx) { + ctx.scale(1.2,1.2); + ctx.translate(-10,-30); + } + + protected abstract void drawMarkBody(Context2d ctx, boolean isSelected, String color); + + @Override + public Bearing getRotationInDegrees(CoursePositionsDTO coursePositionsDTO) { + // by default, no rotation for marks + return null; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/BoatMarkVectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/BoatMarkVectorGraphics.java new file mode 100644 index 00000000000..9668f195925 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/BoatMarkVectorGraphics.java @@ -0,0 +1,136 @@ +package com.sap.sailing.gwt.ui.shared.racemap; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.google.gwt.canvas.dom.client.Context2d; +import com.sap.sailing.domain.common.Bearing; +import com.sap.sailing.domain.common.Distance; +import com.sap.sailing.domain.common.MarkType; +import com.sap.sailing.domain.common.PassingInstruction; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.impl.MeterDistance; +import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO; +import com.sap.sailing.gwt.ui.shared.MarkDTO; +import com.sap.sailing.gwt.ui.shared.WaypointDTO; + +public class BoatMarkVectorGraphics extends AbstractMarkVectorGraphics { + + private final static Distance BOAT_MARK_HEIGHT_IN_METERS = new MeterDistance(6.2); + private final static Distance BOAT_MARK_WIDTH_IN_METERS = new MeterDistance(3.5); + private final static double BOAT_MARK_SELECTION_SCALE = 3.5; + private final static double BOAT_MARK_SELECTION_TRANSLATE_X = -10; + private final static double BOAT_MARK_SELECTION_TRANSLATE_Y = -30; + private final String markIdAsString; + + public BoatMarkVectorGraphics(MarkType type, String color, String shape, String pattern, String markIdAsString) { + super(type, color, shape, pattern); + this.anchorPointX = BOAT_MARK_HEIGHT_IN_METERS.getMeters() / 2; + this.anchorPointY = BOAT_MARK_WIDTH_IN_METERS.getMeters() / 2; + this.markHeightInMeters = BOAT_MARK_HEIGHT_IN_METERS; + this.markWidthInMeters = BOAT_MARK_WIDTH_IN_METERS; + this.markIdAsString = markIdAsString; + } + + protected void setUpScaleAndTranslateForMarkSelection(Context2d ctx) { + ctx.scale(BOAT_MARK_SELECTION_SCALE, BOAT_MARK_SELECTION_SCALE); + ctx.translate(BOAT_MARK_SELECTION_TRANSLATE_X, BOAT_MARK_SELECTION_TRANSLATE_Y); + } + + @Override + protected void drawMarkBody(Context2d ctx, boolean isSelected, String color) { + ctx.beginPath(); + ctx.setFillStyle("#000000"); + ctx.setStrokeStyle("#FFFFFF"); + ctx.setLineWidth(30.0); + ctx.setLineCap("butt"); + ctx.setLineJoin("miter"); + ctx.setMiterLimit(3.0); + ctx.moveTo(33, 30.36); + ctx.quadraticCurveTo(103.47, 18.96, 194.65, 18.55); + ctx.quadraticCurveTo(285.83, 18.13, 370.62, 34.74); + ctx.quadraticCurveTo(455.42, 51.34, 520.29, 87.99); + ctx.quadraticCurveTo(585.16, 124.64, 603, 187.36); + ctx.quadraticCurveTo(584.67, 244.84, 520.84, 277.54); + ctx.quadraticCurveTo(457, 310.24, 372.97, 324.79); + ctx.quadraticCurveTo(288.94, 339.34, 197.37, 339.08); + ctx.quadraticCurveTo(105.8, 338.81, 32, 330.36); + ctx.lineTo(33, 30.362205); + ctx.fill(); + ctx.stroke(); + + ctx.setFillStyle("#FFFFFF"); + ctx.beginPath(); + ctx.beginPath(); + ctx.setLineWidth(1.0); + ctx.setLineJoin("miter"); + ctx.setMiterLimit(4.0); + ctx.moveTo(81, 78); + ctx.lineTo(349, 78); + ctx.lineTo(349, 291); + ctx.lineTo(81, 291); + ctx.lineTo(81, 78); + ctx.fill(); + ctx.stroke(); + + ctx.setFillStyle("#000000"); + ctx.beginPath(); + ctx.moveTo(337, 186.36); + ctx.quadraticCurveTo(337, 180.56, 334.76, 175.46); + ctx.quadraticCurveTo(332.52, 170.36, 328.65, 166.56); + ctx.quadraticCurveTo(324.78, 162.76, 319.59, 160.56); + ctx.quadraticCurveTo(314.4, 158.36, 308.5, 158.36); + ctx.quadraticCurveTo(302.6, 158.36, 297.41, 160.56); + ctx.quadraticCurveTo(292.22, 162.76, 288.35, 166.56); + ctx.quadraticCurveTo(284.48, 170.36, 282.24, 175.46); + ctx.quadraticCurveTo(280, 180.56, 280, 186.36); + ctx.quadraticCurveTo(280, 192.16, 282.24, 197.26); + ctx.quadraticCurveTo(284.48, 202.36, 288.35, 206.16); + ctx.quadraticCurveTo(292.22, 209.96, 297.41, 212.16); + ctx.quadraticCurveTo(302.6, 214.36, 308.5, 214.36); + ctx.quadraticCurveTo(314.4, 214.36, 319.59, 212.16); + ctx.quadraticCurveTo(324.78, 209.96, 328.65, 206.16); + ctx.quadraticCurveTo(332.52, 202.36, 334.76, 197.26); + ctx.quadraticCurveTo(337, 192.16, 337, 186.36); + ctx.stroke(); + ctx.fill(); + ctx.beginPath(); + } + + @Override + public Bearing getRotationInDegrees(CoursePositionsDTO coursePositionsDTO) { + List lineMarkPositions = new ArrayList(); + MarkDTO firstMark = null; + MarkDTO secondMark = null; + for (WaypointDTO currentWaypoint : coursePositionsDTO.course.waypoints) { + if (currentWaypoint.passingInstructions == PassingInstruction.Line) { + Iterator marks = currentWaypoint.controlPoint.getMarks().iterator(); + firstMark = marks.next(); + if (marks.hasNext()) { + secondMark = marks.next(); + if (markIdAsString.equals(firstMark.getIdAsString()) + || markIdAsString.equals(secondMark.getIdAsString())) { + lineMarkPositions.add(firstMark.position); + lineMarkPositions.add(secondMark.position); + break; + } + } + } + } + return getLineBearing(lineMarkPositions); + } + + private Bearing getLineBearing(List markPositions) { + Bearing result = null; + if (markPositions.size() > 1) { + Position firstPosition = markPositions.get(0); + Position secondPosition = markPositions.get(1); + if (firstPosition != null) { + result = firstPosition.getBearingGreatCircle(secondPosition); + } + } + return result; + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/ConicalBuoyMarkVectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/ConicalBuoyMarkVectorGraphics.java new file mode 100644 index 00000000000..7f7ec139df5 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/ConicalBuoyMarkVectorGraphics.java @@ -0,0 +1,85 @@ +package com.sap.sailing.gwt.ui.shared.racemap; + +import com.google.gwt.canvas.dom.client.Context2d; +import com.sap.sailing.domain.common.MarkType; + +public class ConicalBuoyMarkVectorGraphics extends AbstractMarkVectorGraphics implements MarkVectorGraphics { + + public ConicalBuoyMarkVectorGraphics(MarkType type, String color, String shape, String pattern) { + super(type, color, shape, pattern); + } + + @Override + protected void drawMarkBody(Context2d ctx, boolean isSelected, String color) { + ctx.setStrokeStyle("rgba(0,0,0,0)"); + + ctx.save(); + ctx.setFillStyle(color); + ctx.transform(12.5, 0, 0, 12.5, -578, 22.2); + ctx.beginPath(); + ctx.arc(49.7, 12.8, 2.66, 0, doublePi, false); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.transform(12.5, 0, 0, 12.5, -578, 22.2); + ctx.beginPath(); + ctx.arc(49.7, 11.3, 3.37, 0, doublePi, false); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(color); + ctx.transform(12.5, 0, 0, 12.5, -578, 22.2); + ctx.beginPath(); + ctx.arc(49.6, 10.6, 2.66, 0, doublePi, false); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.beginPath(); + ctx.moveTo(36.9, 98); + ctx.lineTo(47.5, 98); + ctx.quadraticCurveTo(47.5, 98, 47.5, 98); + ctx.lineTo(47.5, 154.5); + ctx.quadraticCurveTo(47.5, 154.5, 47.5, 154.5); + ctx.lineTo(36.9, 154.5); + ctx.quadraticCurveTo(36.9, 154.5, 36.9, 154.5); + ctx.lineTo(36.9, 98); + ctx.quadraticCurveTo(36.9, 98, 36.9, 98); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.beginPath(); + ctx.moveTo(43.6, 0.372); + ctx.lineTo(87.3, 102); + ctx.lineTo(-0.714, 102); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(color); + ctx.beginPath(); + ctx.moveTo(43.6, 14.7); + ctx.lineTo(78.5, 96.6); + ctx.lineTo(8.07, 96.6); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/FinishFlagMarkVectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/FinishFlagMarkVectorGraphics.java new file mode 100644 index 00000000000..774167d58fc --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/FinishFlagMarkVectorGraphics.java @@ -0,0 +1,180 @@ +package com.sap.sailing.gwt.ui.shared.racemap; + +import com.google.gwt.canvas.dom.client.Context2d; +import com.sap.sailing.domain.common.MarkType; + +public class FinishFlagMarkVectorGraphics extends AbstractMarkVectorGraphics implements MarkVectorGraphics { + + public FinishFlagMarkVectorGraphics(MarkType type, String color, String shape, String pattern) { + super(type, color, shape, pattern); + } + + @Override + protected void drawMarkBody(Context2d ctx, boolean isSelected, String color) { + ctx.setStrokeStyle("rgba(0,0,0,0)"); + + ctx.save(); + ctx.setFillStyle(color); + ctx.transform(12.5, 0, 0, 12.5, -578, 22.2); + ctx.beginPath(); + ctx.arc(49.7, 12.8, 2.66, 0, doublePi, false); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.transform(12.5, 0, 0, 12.5, -578, 22.2); + ctx.beginPath(); + ctx.arc(49.7, 11.3, 3.37, 0, doublePi, false); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(color); + ctx.transform(12.5, 0, 0, 12.5, -578, 22.2); + ctx.beginPath(); + ctx.arc(49.6, 10.6, 2.66, 0, doublePi, false); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.transform(4.98, 0, 0, 10.8, -205, 50.4); + ctx.beginPath(); + ctx.moveTo(50.8, 9.84); + ctx.lineTo(48.5, 9.84); + ctx.lineTo(48.5, 1.44); + ctx.lineTo(50.8, 1.9); + ctx.lineTo(50.8, 9.84); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.beginPath(); + ctx.moveTo(36.9, -0.5); + ctx.lineTo(141.9, -0.5); + ctx.quadraticCurveTo(141.9, -0.5, 141.9, -0.5); + ctx.lineTo(141.9, 71.2); + ctx.quadraticCurveTo(141.9, 71.2, 141.9, 71.2); + ctx.lineTo(36.9, 71.2); + ctx.quadraticCurveTo(36.9, 71.2, 36.9, 71.2); + ctx.lineTo(36.9, -0.5); + ctx.quadraticCurveTo(36.9, -0.5, 36.9, -0.5); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(color); + ctx.beginPath(); + ctx.moveTo(46, 4.04); + ctx.lineTo(76.3, 4.04); + ctx.quadraticCurveTo(76.3, 4.04, 76.3, 4.04); + ctx.lineTo(76.3, 34.34); + ctx.quadraticCurveTo(76.3, 34.34, 76.3, 34.34); + ctx.lineTo(46, 34.34); + ctx.quadraticCurveTo(46, 34.34, 46, 34.34); + ctx.lineTo(46, 4.04); + ctx.quadraticCurveTo(46, 4.04, 46, 4.04); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.beginPath(); + ctx.moveTo(46.1, 34.3); + ctx.lineTo(76.4, 34.3); + ctx.quadraticCurveTo(76.4, 34.3, 76.4, 34.3); + ctx.lineTo(76.4, 64.6); + ctx.quadraticCurveTo(76.4, 64.6, 76.4, 64.6); + ctx.lineTo(46.1, 64.6); + ctx.quadraticCurveTo(46.1, 64.6, 46.1, 64.6); + ctx.lineTo(46.1, 34.3); + ctx.quadraticCurveTo(46.1, 34.3, 46.1, 34.3); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.beginPath(); + ctx.moveTo(76, 3.95); + ctx.lineTo(106.3, 3.95); + ctx.quadraticCurveTo(106.3, 3.95, 106.3, 3.95); + ctx.lineTo(106.3, 34.25); + ctx.quadraticCurveTo(106.3, 34.25, 106.3, 34.25); + ctx.lineTo(76, 34.25); + ctx.quadraticCurveTo(76, 34.25, 76, 34.25); + ctx.lineTo(76, 3.95); + ctx.quadraticCurveTo(76, 3.95, 76, 3.95); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(color); + ctx.beginPath(); + ctx.moveTo(76.1, 34.2); + ctx.lineTo(106.4, 34.2); + ctx.quadraticCurveTo(106.4, 34.2, 106.4, 34.2); + ctx.lineTo(106.4, 64.5); + ctx.quadraticCurveTo(106.4, 64.5, 106.4, 64.5); + ctx.lineTo(76.1, 64.5); + ctx.quadraticCurveTo(76.1, 64.5, 76.1, 64.5); + ctx.lineTo(76.1, 34.2); + ctx.quadraticCurveTo(76.1, 34.2, 76.1, 34.2); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(color); + ctx.beginPath(); + ctx.moveTo(106, 3.96); + ctx.lineTo(136.3, 3.96); + ctx.quadraticCurveTo(136.3, 3.96, 136.3, 3.96); + ctx.lineTo(136.3, 34.26); + ctx.quadraticCurveTo(136.3, 34.26, 136.3, 34.26); + ctx.lineTo(106, 34.26); + ctx.quadraticCurveTo(106, 34.26, 106, 34.26); + ctx.lineTo(106, 3.96); + ctx.quadraticCurveTo(106, 3.96, 106, 3.96); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.beginPath(); + ctx.moveTo(106, 34.3); + ctx.lineTo(136.3, 34.3); + ctx.quadraticCurveTo(136.3, 34.3, 136.3, 34.3); + ctx.lineTo(136.3, 64.6); + ctx.quadraticCurveTo(136.3, 64.6, 136.3, 64.6); + ctx.lineTo(106, 64.6); + ctx.quadraticCurveTo(106, 64.6, 106, 64.6); + ctx.lineTo(106, 34.3); + ctx.quadraticCurveTo(106, 34.3, 106, 34.3); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + ctx.restore(); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/LandMarkVectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/LandMarkVectorGraphics.java new file mode 100644 index 00000000000..dd604da5644 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/LandMarkVectorGraphics.java @@ -0,0 +1,77 @@ +package com.sap.sailing.gwt.ui.shared.racemap; + +import com.google.gwt.canvas.dom.client.Context2d; +import com.sap.sailing.domain.common.MarkType; + +public class LandMarkVectorGraphics extends AbstractMarkVectorGraphics implements MarkVectorGraphics { + + public LandMarkVectorGraphics(MarkType type, String color, String shape, String pattern) { + super(type, color, shape, pattern); + } + + @Override + protected void drawMarkBody(Context2d ctx, boolean isSelected, String color) { + ctx.setStrokeStyle("rgba(0,0,0,0)"); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.transform(4.98, 0, 0, 10.8, -205, 50.4); + ctx.beginPath(); + ctx.moveTo(50.8, 9.84); + ctx.lineTo(48.5, 9.84); + ctx.lineTo(48.5, 1.44); + ctx.lineTo(50.8, 1.9); + ctx.lineTo(50.8, 9.84); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.transform(12.5, 0, 0, 12.5, -570, 22.2); + ctx.save(); + ctx.setFillStyle(color); + ctx.beginPath(); + ctx.moveTo(48.8, 3.82); + ctx.lineTo(48.8, -1.32); + ctx.lineTo(57, 1.05); + ctx.lineTo(48.8, 3.82); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.beginPath(); + ctx.moveTo(48.5, 4.16); + ctx.lineTo(48.5, -1.65); + ctx.lineTo(57.8, 1.03); + ctx.lineTo(48.5, 4.16); + ctx.closePath(); + ctx.moveTo(49, -0.994); + ctx.lineTo(49, 3.47); + ctx.lineTo(56.2, 1.07); + ctx.lineTo(49, -0.994); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(color); + ctx.beginPath(); + ctx.moveTo(83.9, 209); + ctx.bezierCurveTo(83.9, 209, 68.6, 183, 43.0, 183); + ctx.bezierCurveTo(12.3, 183, 7.1, 209, 7.1, 209); + ctx.lineTo(7.1, 157); + ctx.lineTo(83.9, 157); + ctx.lineTo(83.9, 209); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + ctx.restore(); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/MarkVectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/MarkVectorGraphics.java index 5d61b9799f5..cdf8ad1366d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/MarkVectorGraphics.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/MarkVectorGraphics.java @@ -1,783 +1,24 @@ package com.sap.sailing.gwt.ui.shared.racemap; -import com.google.gwt.canvas.dom.client.CanvasGradient; import com.google.gwt.canvas.dom.client.Context2d; +import com.sap.sailing.domain.common.Bearing; import com.sap.sailing.domain.common.Distance; -import com.sap.sailing.domain.common.MarkType; -import com.sap.sailing.domain.common.impl.MeterDistance; +import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO; -/** - * A class for course mark graphics based on SVG graphics drawn to a HTML5 canvas - * The SVG files for the drawing can be found in the package com.sap.sailing.gwt.ui.svg.buoys - * A general description how to convert SVG files to 'drawing commands' can be found at http://wiki.sapsailing.com/wiki/howto/development/boatgraphicssvg - * @author Frank - * - */ -public class MarkVectorGraphics { - protected Distance markHeightInMeters; - protected Distance markWidthInMeters; - - private final String color; - private final String shape; - private final String pattern; - private final MarkType type; - - private static final double doublePi = 2 * Math.PI; +public interface MarkVectorGraphics { + void drawMarkToCanvas(Context2d ctx, boolean isSelected, double width, double height, double scaleFactor); - private double anchorPointX = 0.44; - private double anchorPointY = 1.67; - - private final static String DEFAULT_MARK_COLOR = "#f9ac00"; - private final static String DEFAULT_MARK_BG_COLOR = "#f0f0f0"; + Distance getMarkHeight(); - public MarkVectorGraphics(MarkType type, String color, String shape, String pattern) { - this.type = type; - this.color = color; - this.shape = shape; - this.pattern = pattern; - this.markHeightInMeters = new MeterDistance(2.1); - this.markWidthInMeters = new MeterDistance(1.5); - } - - public void drawMarkToCanvas(Context2d ctx, boolean isSelected, double width, double height, double scaleFactor) { - ctx.save(); - ctx.clearRect(0, 0, width, height); - ctx.translate(width / 2.0, height / 2.0); - ctx.scale(scaleFactor, scaleFactor); - ctx.translate(-anchorPointX * 100,- anchorPointY * 100); - String markColor = color != null ? color : DEFAULT_MARK_COLOR; - drawMark(ctx, isSelected, markColor); - ctx.restore(); - } + Distance getMarkWidth(); - protected void drawMark(Context2d ctx, boolean isSelected, String color) { - final MarkType markType = type==null ? MarkType.BUOY : type; - switch(markType) { - case BUOY: - if(isSelected) { - drawMarkSelection(ctx); - } - if(shape != null) { - if(Shape.CYLINDER.name().equalsIgnoreCase(shape) && pattern != null && Pattern.CHECKERED.name().equalsIgnoreCase(pattern)) { - drawBuoyWithFinishFlag(ctx, isSelected, color); - } else if (Shape.CONICAL.name().equalsIgnoreCase(shape)) { - drawConicalBuoy(ctx, isSelected, color); - } else { - drawSimpleBuoy(ctx, isSelected, color); - } - } else { - drawSimpleBuoy(ctx, isSelected, color); - } - break; - case FINISHBOAT: - drawFinishBoat(ctx, isSelected, color); - break; - case LANDMARK: - if(isSelected) { - drawMarkSelection(ctx); - } - drawLandmark(ctx, isSelected, color); - break; - case STARTBOAT: - drawStartBoat(ctx, isSelected, color); - break; - case UMPIREBOAT: - case CAMERABOAT: - // umpire and camera boats are not course marks -> see TrackedAssetVectorGraphics - break; - default: - break; - } - } - - private void drawMarkSelection(Context2d ctx) { - ctx.save(); - - ctx.scale(1.2,1.2); - ctx.translate(-10,-30); - - CanvasGradient g1=ctx.createLinearGradient(77.8,188,165,219); - g1.addColorStop(0,"rgba(240, 240, 240, 1)"); - g1.addColorStop(1,"rgba(240, 240, 240, 0)"); - ctx.setFillStyle(g1); - ctx.beginPath(); - ctx.moveTo(170,181); - ctx.translate(44.000168893718424,180.79369636814624); - ctx.rotate(0); - ctx.scale(1,1); - ctx.arc(0,0,126,0.0016373311430805408,0.5254904360229328,false); - ctx.scale(1,1); - ctx.rotate(0); - ctx.translate(-44.000168893718424,-180.79369636814624); - ctx.lineTo(44.2,181); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - - CanvasGradient g2=ctx.createLinearGradient(51,203,77.3,302); - g2.addColorStop(0,"rgba(255, 255, 255, 1)"); - g2.addColorStop(1,"rgba(255, 255, 255, 0)"); - ctx.setFillStyle(g2); - ctx.beginPath(); - ctx.moveTo(107,290); - ctx.translate(43.79222318749837,181.0010231680087); - ctx.rotate(0); - ctx.scale(1,1); - ctx.arc(0,0,126,1.0452923752792398,1.5667663411841573,false); - ctx.scale(1,1); - ctx.rotate(0); - ctx.translate(-43.79222318749837,-181.0010231680087); - ctx.lineTo(44.2,181); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - - CanvasGradient g3=ctx.createLinearGradient(26.8,197,-46.5,269); - g3.addColorStop(0,"rgba(255, 255, 255, 1)"); - g3.addColorStop(1,"rgba(255, 255, 255, 0)"); - ctx.setFillStyle(g3); - ctx.beginPath(); - ctx.moveTo(-18.3,290); - ctx.translate(43.72636289026038,180.32443158749652); - ctx.rotate(0); - ctx.scale(1,1); - ctx.arc(0,0,126,2.0854951576078884,2.611791628699119,false); - ctx.scale(1,1); - ctx.rotate(0); - ctx.translate(-43.72636289026038,-180.32443158749652); - ctx.lineTo(44.2,181); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - - CanvasGradient g4=ctx.createLinearGradient(18.7,172,-76.3,140); - g4.addColorStop(0,"rgba(255, 255, 255, 1)"); - g4.addColorStop(1,"rgba(255, 255, 255, 0)"); - ctx.setFillStyle(g4); - ctx.beginPath(); - ctx.moveTo(-81.8,179); - ctx.translate(44.19920011832349,178.55103503179944); - ctx.rotate(0); - ctx.scale(1,1); - ctx.arc(0,0,126,3.1380294320163484,3.670248678643417,false); - ctx.scale(1,1); - ctx.rotate(0); - ctx.translate(-44.19920011832349,-178.55103503179944); - ctx.lineTo(44.2,179); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - - CanvasGradient g5=ctx.createLinearGradient(37.9,147,13.6,58.6); - g5.addColorStop(0,"rgba(255, 255, 255, 1)"); - g5.addColorStop(1,"rgba(255, 255, 255, 0)"); - ctx.setFillStyle(g5); - ctx.beginPath(); - ctx.moveTo(-18.7,71.8); - ctx.translate(44.160311222571984,180.99973110315514); - ctx.rotate(0); - ctx.scale(1,1); - ctx.arc(0,0,126,-2.0931154263055687,-1.5728622903484606,false); - ctx.scale(1,1); - ctx.rotate(0); - ctx.translate(-44.160311222571984,-180.99973110315514); - ctx.lineTo(44.199999999999996,181); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - - CanvasGradient g6=ctx.createLinearGradient(80.8,139,134,91.9); - g6.addColorStop(0,"rgba(240, 240, 240, 1)"); - g6.addColorStop(1,"rgba(240, 240, 240, 0)"); - ctx.setFillStyle(g6); - ctx.beginPath(); - ctx.moveTo(108,72.1); - ctx.translate(43.50304481630927,180.3411325330301); - ctx.rotate(0); - ctx.scale(1,1); - ctx.arc(0,0,126,-1.0334238189446499,-0.5175711746742696,false); - ctx.scale(1,1); - ctx.rotate(0); - ctx.translate(-43.50304481630927,-180.3411325330301); - ctx.lineTo(44.2,181); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - - ctx.translate(-49.5,17.2); - ctx.restore(); - } - - void drawSimpleBuoy(Context2d ctx, boolean isSelected, String color) { - ctx.setStrokeStyle("rgba(0,0,0,0)"); - - ctx.save(); - ctx.setFillStyle(color); - ctx.transform(12.5,0,0,12.5,-578,22.2); - - ctx.beginPath(); - ctx.arc(49.7,12.8,2.66,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.transform(12.5,0,0,12.5,-578,22.2); - ctx.beginPath(); - ctx.arc(49.7,11.3,3.37,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(color); - ctx.transform(12.5,0,0,12.5,-578,22.2); - ctx.beginPath(); - ctx.arc(49.6,10.6,2.66,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.transform(4.98,0,0,10.8,-205,50.4); - ctx.beginPath(); - ctx.moveTo(50.8,9.84); - ctx.lineTo(48.5,9.84); - ctx.lineTo(48.5,1.44); - ctx.lineTo(50.8,1.9); - ctx.lineTo(50.8,9.84); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.transform(12.5,0,0,12.5,-570,22.2); - ctx.save(); - ctx.setFillStyle(color); - ctx.beginPath(); - ctx.moveTo(48.8,3.82); - ctx.lineTo(48.8,-1.32); - ctx.lineTo(57,1.05); - ctx.lineTo(48.8,3.82); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.beginPath(); - ctx.moveTo(48.5,4.16); - ctx.lineTo(48.5,-1.65); - ctx.lineTo(57.8,1.03); - ctx.lineTo(48.5,4.16); - ctx.closePath(); - ctx.moveTo(49,-0.994); - ctx.lineTo(49,3.47); - ctx.lineTo(56.2,1.07); - ctx.lineTo(49,-0.994); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - ctx.restore(); - } - - protected void drawBuoyWithFinishFlag(Context2d ctx, boolean isSelected, String color) { - ctx.setStrokeStyle("rgba(0,0,0,0)"); - - ctx.save(); - ctx.setFillStyle(color); - ctx.transform(12.5,0,0,12.5,-578,22.2); - ctx.beginPath(); - ctx.arc(49.7,12.8,2.66,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.transform(12.5,0,0,12.5,-578,22.2); - ctx.beginPath(); - ctx.arc(49.7,11.3,3.37,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(color); - ctx.transform(12.5,0,0,12.5,-578,22.2); - ctx.beginPath(); - ctx.arc(49.6,10.6,2.66,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.transform(4.98,0,0,10.8,-205,50.4); - ctx.beginPath(); - ctx.moveTo(50.8,9.84); - ctx.lineTo(48.5,9.84); - ctx.lineTo(48.5,1.44); - ctx.lineTo(50.8,1.9); - ctx.lineTo(50.8,9.84); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.beginPath(); - ctx.moveTo(36.9,-0.5); - ctx.lineTo(141.9,-0.5); - ctx.quadraticCurveTo(141.9,-0.5,141.9,-0.5); - ctx.lineTo(141.9,71.2); - ctx.quadraticCurveTo(141.9,71.2,141.9,71.2); - ctx.lineTo(36.9,71.2); - ctx.quadraticCurveTo(36.9,71.2,36.9,71.2); - ctx.lineTo(36.9,-0.5); - ctx.quadraticCurveTo(36.9,-0.5,36.9,-0.5); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(color); - ctx.beginPath(); - ctx.moveTo(46,4.04); - ctx.lineTo(76.3,4.04); - ctx.quadraticCurveTo(76.3,4.04,76.3,4.04); - ctx.lineTo(76.3,34.34); - ctx.quadraticCurveTo(76.3,34.34,76.3,34.34); - ctx.lineTo(46,34.34); - ctx.quadraticCurveTo(46,34.34,46,34.34); - ctx.lineTo(46,4.04); - ctx.quadraticCurveTo(46,4.04,46,4.04); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.beginPath(); - ctx.moveTo(46.1,34.3); - ctx.lineTo(76.4,34.3); - ctx.quadraticCurveTo(76.4,34.3,76.4,34.3); - ctx.lineTo(76.4,64.6); - ctx.quadraticCurveTo(76.4,64.6,76.4,64.6); - ctx.lineTo(46.1,64.6); - ctx.quadraticCurveTo(46.1,64.6,46.1,64.6); - ctx.lineTo(46.1,34.3); - ctx.quadraticCurveTo(46.1,34.3,46.1,34.3); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.beginPath(); - ctx.moveTo(76,3.95); - ctx.lineTo(106.3,3.95); - ctx.quadraticCurveTo(106.3,3.95,106.3,3.95); - ctx.lineTo(106.3,34.25); - ctx.quadraticCurveTo(106.3,34.25,106.3,34.25); - ctx.lineTo(76,34.25); - ctx.quadraticCurveTo(76,34.25,76,34.25); - ctx.lineTo(76,3.95); - ctx.quadraticCurveTo(76,3.95,76,3.95); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(color); - ctx.beginPath(); - ctx.moveTo(76.1,34.2); - ctx.lineTo(106.4,34.2); - ctx.quadraticCurveTo(106.4,34.2,106.4,34.2); - ctx.lineTo(106.4,64.5); - ctx.quadraticCurveTo(106.4,64.5,106.4,64.5); - ctx.lineTo(76.1,64.5); - ctx.quadraticCurveTo(76.1,64.5,76.1,64.5); - ctx.lineTo(76.1,34.2); - ctx.quadraticCurveTo(76.1,34.2,76.1,34.2); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(color); - ctx.beginPath(); - ctx.moveTo(106,3.96); - ctx.lineTo(136.3,3.96); - ctx.quadraticCurveTo(136.3,3.96,136.3,3.96); - ctx.lineTo(136.3,34.26); - ctx.quadraticCurveTo(136.3,34.26,136.3,34.26); - ctx.lineTo(106,34.26); - ctx.quadraticCurveTo(106,34.26,106,34.26); - ctx.lineTo(106,3.96); - ctx.quadraticCurveTo(106,3.96,106,3.96); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.beginPath(); - ctx.moveTo(106,34.3); - ctx.lineTo(136.3,34.3); - ctx.quadraticCurveTo(136.3,34.3,136.3,34.3); - ctx.lineTo(136.3,64.6); - ctx.quadraticCurveTo(136.3,64.6,136.3,64.6); - ctx.lineTo(106,64.6); - ctx.quadraticCurveTo(106,64.6,106,64.6); - ctx.lineTo(106,34.3); - ctx.quadraticCurveTo(106,34.3,106,34.3); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - ctx.restore(); - } - - protected void drawLandmark(Context2d ctx, boolean isSelected, String color) { - ctx.setStrokeStyle("rgba(0,0,0,0)"); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.transform(4.98,0,0,10.8,-205,50.4); - ctx.beginPath(); - ctx.moveTo(50.8,9.84); - ctx.lineTo(48.5,9.84); - ctx.lineTo(48.5,1.44); - ctx.lineTo(50.8,1.9); - ctx.lineTo(50.8,9.84); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.transform(12.5,0,0,12.5,-570,22.2); - ctx.save(); - ctx.setFillStyle(color); - ctx.beginPath(); - ctx.moveTo(48.8,3.82); - ctx.lineTo(48.8,-1.32); - ctx.lineTo(57,1.05); - ctx.lineTo(48.8,3.82); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.beginPath(); - ctx.moveTo(48.5,4.16); - ctx.lineTo(48.5,-1.65); - ctx.lineTo(57.8,1.03); - ctx.lineTo(48.5,4.16); - ctx.closePath(); - ctx.moveTo(49,-0.994); - ctx.lineTo(49,3.47); - ctx.lineTo(56.2,1.07); - ctx.lineTo(49,-0.994); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(color); - ctx.beginPath(); - ctx.moveTo(83.9,209); - ctx.bezierCurveTo(83.9,209,68.6,183,43.0,183); - ctx.bezierCurveTo(12.3,183,7.1,209,7.1,209); - ctx.lineTo(7.1,157); - ctx.lineTo(83.9,157); - ctx.lineTo(83.9,209); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - ctx.restore(); - } - - protected void drawConicalBuoy(Context2d ctx, boolean isSelected, String color) { - ctx.setStrokeStyle("rgba(0,0,0,0)"); - - ctx.save(); - ctx.setFillStyle(color); - ctx.transform(12.5,0,0,12.5,-578,22.2); - ctx.beginPath(); - ctx.arc(49.7,12.8,2.66,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.transform(12.5,0,0,12.5,-578,22.2); - ctx.beginPath(); - ctx.arc(49.7,11.3,3.37,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(color); - ctx.transform(12.5,0,0,12.5,-578,22.2); - ctx.beginPath(); - ctx.arc(49.6,10.6,2.66,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.beginPath(); - ctx.moveTo(36.9,98); - ctx.lineTo(47.5,98); - ctx.quadraticCurveTo(47.5,98,47.5,98); - ctx.lineTo(47.5,154.5); - ctx.quadraticCurveTo(47.5,154.5,47.5,154.5); - ctx.lineTo(36.9,154.5); - ctx.quadraticCurveTo(36.9,154.5,36.9,154.5); - ctx.lineTo(36.9,98); - ctx.quadraticCurveTo(36.9,98,36.9,98); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.beginPath(); - ctx.moveTo(43.6,0.372); - ctx.lineTo(87.3,102); - ctx.lineTo(-0.714,102); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(color); - ctx.beginPath(); - ctx.moveTo(43.6,14.7); - ctx.lineTo(78.5,96.6); - ctx.lineTo(8.07,96.6); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - } - - protected void drawStartBoat(Context2d ctx, boolean isSelected, String color2) { - ctx.setStrokeStyle("rgba(0,0,0,0)"); - - ctx.save(); - ctx.setFillStyle(color); - ctx.transform(12.5,0,0,12.5,-578,22.2); - - ctx.beginPath(); - ctx.arc(49.7,12.8,2.66,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.transform(12.5,0,0,12.5,-578,22.2); - ctx.beginPath(); - ctx.arc(49.7,11.3,3.37,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(color); - ctx.transform(12.5,0,0,12.5,-578,22.2); - ctx.beginPath(); - ctx.arc(49.6,10.6,2.66,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.transform(4.98,0,0,10.8,-205,50.4); - ctx.beginPath(); - ctx.moveTo(50.8,9.84); - ctx.lineTo(48.5,9.84); - ctx.lineTo(48.5,1.44); - ctx.lineTo(50.8,1.9); - ctx.lineTo(50.8,9.84); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.transform(12.5,0,0,12.5,-570,22.2); - ctx.save(); - ctx.setFillStyle(color); - ctx.beginPath(); - ctx.moveTo(48.8,3.82); - ctx.lineTo(48.8,-1.32); - ctx.lineTo(57,1.05); - ctx.lineTo(48.8,3.82); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.beginPath(); - ctx.moveTo(48.5,4.16); - ctx.lineTo(48.5,-1.65); - ctx.lineTo(57.8,1.03); - ctx.lineTo(48.5,4.16); - ctx.closePath(); - ctx.moveTo(49,-0.994); - ctx.lineTo(49,3.47); - ctx.lineTo(56.2,1.07); - ctx.lineTo(49,-0.994); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - ctx.restore(); - } - - protected void drawFinishBoat(Context2d ctx, boolean isSelected, String color2) { - ctx.setStrokeStyle("rgba(0,0,0,0)"); - - ctx.save(); - ctx.setFillStyle(color); - ctx.transform(12.5,0,0,12.5,-578,22.2); - - ctx.beginPath(); - ctx.arc(49.7,12.8,2.66,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.transform(12.5,0,0,12.5,-578,22.2); - ctx.beginPath(); - ctx.arc(49.7,11.3,3.37,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(color); - ctx.transform(12.5,0,0,12.5,-578,22.2); - ctx.beginPath(); - ctx.arc(49.6,10.6,2.66,0,doublePi,false); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.transform(4.98,0,0,10.8,-205,50.4); - ctx.beginPath(); - ctx.moveTo(50.8,9.84); - ctx.lineTo(48.5,9.84); - ctx.lineTo(48.5,1.44); - ctx.lineTo(50.8,1.9); - ctx.lineTo(50.8,9.84); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.transform(12.5,0,0,12.5,-570,22.2); - ctx.save(); - ctx.setFillStyle(color); - ctx.beginPath(); - ctx.moveTo(48.8,3.82); - ctx.lineTo(48.8,-1.32); - ctx.lineTo(57,1.05); - ctx.lineTo(48.8,3.82); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - - ctx.save(); - ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); - ctx.beginPath(); - ctx.moveTo(48.5,4.16); - ctx.lineTo(48.5,-1.65); - ctx.lineTo(57.8,1.03); - ctx.lineTo(48.5,4.16); - ctx.closePath(); - ctx.moveTo(49,-0.994); - ctx.lineTo(49,3.47); - ctx.lineTo(56.2,1.07); - ctx.lineTo(49,-0.994); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); - ctx.restore(); - } - - public Distance getMarkHeight() { - return markHeightInMeters; - } - - public Distance getMarkWidth() { - return markWidthInMeters; - } - - public String getColor() { - return color; - } - - public String getShape() { - return shape; - } - - public String getPattern() { - return pattern; - } - - public MarkType getType() { - return type; - } + /** + * If this graphical representation requires different rotations based on its state, this method can be implemented + * to compute the rotation desired. It is called after the drawing to the canvas, if it was necessary, has been + * updated. + * + * @return {@code null} if no rotation is desired; this will save the application of a CSS rotation; otherwise, a + * rotation as an angle + */ + Bearing getRotationInDegrees(CoursePositionsDTO coursePositionsDTO); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/MarkVectorGraphicsFactory.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/MarkVectorGraphicsFactory.java new file mode 100644 index 00000000000..cfb6aa0acce --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/MarkVectorGraphicsFactory.java @@ -0,0 +1,44 @@ +package com.sap.sailing.gwt.ui.shared.racemap; + +import com.sap.sailing.domain.common.MarkType; +import com.sap.sailing.gwt.ui.shared.MarkDTO; + +public class MarkVectorGraphicsFactory { + public MarkVectorGraphics getMarkVectorGraphics(MarkDTO markDTO) { + final MarkType markType = markDTO.type; + final MarkVectorGraphics result; + switch (markType) { + case BUOY: + result = createBuoyMarkVectorGraphics(markDTO); + break; + case STARTBOAT: + case FINISHBOAT: + result = new BoatMarkVectorGraphics(markDTO.type, markDTO.color, markDTO.shape, markDTO.pattern, markDTO.getIdAsString()); + break; + case LANDMARK: + result = new LandMarkVectorGraphics(markDTO.type, markDTO.color, markDTO.shape, markDTO.pattern); + break; + default: + result = createBuoyMarkVectorGraphics(markDTO); + break; + } + return result; + } + + private MarkVectorGraphics createBuoyMarkVectorGraphics(MarkDTO markDTO) { + final MarkVectorGraphics result; + if (markDTO.shape != null) { + if (Shape.CYLINDER.name().equalsIgnoreCase(markDTO.shape) && markDTO.pattern != null + && Pattern.CHECKERED.name().equalsIgnoreCase(markDTO.pattern)) { + result = new FinishFlagMarkVectorGraphics(markDTO.type, markDTO.color, markDTO.shape, markDTO.pattern); + } else if (Shape.CONICAL.name().equalsIgnoreCase(markDTO.shape)) { + result = new ConicalBuoyMarkVectorGraphics(markDTO.type, markDTO.color, markDTO.shape, markDTO.pattern); + } else { + result = new SimpleBuoyMarkVectorGraphics(markDTO.type, markDTO.color, markDTO.shape, markDTO.pattern); + } + } else { + result = new SimpleBuoyMarkVectorGraphics(markDTO.type, markDTO.color, markDTO.shape, markDTO.pattern); + } + return result; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/SimpleBuoyMarkVectorGraphics.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/SimpleBuoyMarkVectorGraphics.java new file mode 100644 index 00000000000..09c8be2a180 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/SimpleBuoyMarkVectorGraphics.java @@ -0,0 +1,93 @@ +package com.sap.sailing.gwt.ui.shared.racemap; + +import com.google.gwt.canvas.dom.client.Context2d; +import com.sap.sailing.domain.common.MarkType; + +public class SimpleBuoyMarkVectorGraphics extends AbstractMarkVectorGraphics implements MarkVectorGraphics { + + public SimpleBuoyMarkVectorGraphics(MarkType type, String color, String shape, String pattern) { + super(type, color, shape, pattern); + } + + @Override + protected void drawMarkBody(Context2d ctx, boolean isSelected, String color) { + ctx.setStrokeStyle("rgba(0,0,0,0)"); + + ctx.save(); + ctx.setFillStyle(color); + ctx.transform(12.5, 0, 0, 12.5, -578, 22.2); + + ctx.beginPath(); + ctx.arc(49.7, 12.8, 2.66, 0, doublePi, false); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.transform(12.5, 0, 0, 12.5, -578, 22.2); + ctx.beginPath(); + ctx.arc(49.7, 11.3, 3.37, 0, doublePi, false); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(color); + ctx.transform(12.5, 0, 0, 12.5, -578, 22.2); + ctx.beginPath(); + ctx.arc(49.6, 10.6, 2.66, 0, doublePi, false); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.transform(4.98, 0, 0, 10.8, -205, 50.4); + ctx.beginPath(); + ctx.moveTo(50.8, 9.84); + ctx.lineTo(48.5, 9.84); + ctx.lineTo(48.5, 1.44); + ctx.lineTo(50.8, 1.9); + ctx.lineTo(50.8, 9.84); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.transform(12.5, 0, 0, 12.5, -570, 22.2); + ctx.save(); + ctx.setFillStyle(color); + ctx.beginPath(); + ctx.moveTo(48.8, 3.82); + ctx.lineTo(48.8, -1.32); + ctx.lineTo(57, 1.05); + ctx.lineTo(48.8, 3.82); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + + ctx.save(); + ctx.setFillStyle(DEFAULT_MARK_BG_COLOR); + ctx.beginPath(); + ctx.moveTo(48.5, 4.16); + ctx.lineTo(48.5, -1.65); + ctx.lineTo(57.8, 1.03); + ctx.lineTo(48.5, 4.16); + ctx.closePath(); + ctx.moveTo(49, -0.994); + ctx.lineTo(49, 3.47); + ctx.lineTo(56.2, 1.07); + ctx.lineTo(49, -0.994); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + ctx.restore(); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/spectator/SpectatorEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/spectator/SpectatorEntryPoint.java index 99188283aae..bd9a41092ee 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/spectator/SpectatorEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/spectator/SpectatorEntryPoint.java @@ -1,5 +1,6 @@ package com.sap.sailing.gwt.ui.spectator; +import com.google.gwt.dom.client.Style.Position; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.user.client.Window; @@ -8,9 +9,9 @@ import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.SimplePanel; +import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication; +import com.sap.sailing.gwt.common.authentication.SAPSailingHeaderWithAuthentication; import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint; -import com.sap.sailing.gwt.ui.client.GlobalNavigationPanel; -import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel; import com.sap.sailing.gwt.ui.client.RegattaRefresher; import com.sap.sailing.gwt.ui.client.shared.panels.SimpleWelcomeWidget; import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapSettings; @@ -66,12 +67,8 @@ public class SpectatorEntryPoint extends AbstractSailingEntryPoint implements Re && Window.Location.getParameter("embedded").equalsIgnoreCase("true"); if (!embedded) { String title = groupName != null ? groupName : getStringMessages().overview(); - LogoAndTitlePanel logoAndTitlePanel = new LogoAndTitlePanel(title, getStringMessages(), this, getUserService()); - logoAndTitlePanel.addStyleName("LogoAndTitlePanel"); - FlowPanel globalNavigationPanel = new GlobalNavigationPanel(getStringMessages(), true, null, null, /* event */ null, null); - logoAndTitlePanel.add(globalNavigationPanel); - - rootPanel.add(logoAndTitlePanel); + SAPSailingHeaderWithAuthentication header = getHeader(title); + rootPanel.add(header); } else { RootPanel.getBodyElement().getStyle().setPadding(0, Unit.PX); RootPanel.getBodyElement().getStyle().setPaddingTop(20, Unit.PX); @@ -108,6 +105,16 @@ public class SpectatorEntryPoint extends AbstractSailingEntryPoint implements Re fillRegattas(); } + private SAPSailingHeaderWithAuthentication getHeader(String title){ + SAPSailingHeaderWithAuthentication header = new SAPSailingHeaderWithAuthentication(title); + new FixedSailingAuthentication(getUserService(), header.getAuthenticationMenuView()); + header.getElement().getStyle().setPosition(Position.FIXED); + header.getElement().getStyle().setTop(0, Unit.PX); + header.getElement().getStyle().setWidth(100, Unit.PCT); + header.getElement().getStyle().setZIndex(100); + return header; + } + @Override public void fillRegattas() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/boat_mark.svg b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/boat_mark.svg new file mode 100644 index 00000000000..ebd344fd9f1 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/client/svg/buoys/boat_mark.svg @@ -0,0 +1,77 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java index f7c5d1462db..4bed05fb47a 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java @@ -67,22 +67,26 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { private static final long serialVersionUID = -11522605089325440L; private Regatta regatta; - public DummyTrackedRace(final Serializable raceId, final Iterable competitors, final Regatta regatta, final TrackedRegatta trackedRegatta, final WindStore windStore) { - this(competitors, regatta, trackedRegatta, new RaceDefinitionImpl("DummyRace", new CourseImpl("Dummy Course", Collections.emptyList()), - regatta.getBoatClass(), competitors, raceId), windStore); + public DummyTrackedRace(final Serializable raceId, final Iterable competitors, + final Regatta regatta, final TrackedRegatta trackedRegatta, final WindStore windStore) { + this(competitors, regatta, trackedRegatta, + new RaceDefinitionImpl("DummyRace", new CourseImpl("Dummy Course", Collections. emptyList()), + regatta.getBoatClass(), competitors, raceId), + windStore); } - - public DummyTrackedRace(final Iterable competitors, final Regatta regatta, final TrackedRegatta trackedRegatta, - RaceDefinition race, WindStore windStore) { + + public DummyTrackedRace(final Iterable competitors, final Regatta regatta, + final TrackedRegatta trackedRegatta, RaceDefinition race, WindStore windStore) { super(race, trackedRegatta, windStore, -1); this.regatta = regatta; } - public DummyTrackedRace(final Iterable competitors, final Regatta regatta, final TrackedRegatta trackedRegatta, - RaceDefinition race) { - this(competitors, regatta, trackedRegatta, race, EmptyWindStore.INSTANCE); - + + public DummyTrackedRace(final Iterable competitors, final Regatta regatta, + final TrackedRegatta trackedRegatta, RaceDefinition race) { + this(competitors, regatta, trackedRegatta, race, EmptyWindStore.INSTANCE); + } - + public DummyTrackedRace(final String raceName, final Serializable raceId) { super(new RaceDefinitionImpl(raceName, new CourseImpl("Dummy Course", Collections. emptyList()), /* boatClass */ null, new HashSet(), raceId), null, EmptyWindStore.INSTANCE, -1); @@ -214,7 +218,8 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { } @Override - public Position getApproximatePosition(Waypoint waypoint, TimePoint timePoint, MarkPositionAtTimePointCache markPositionCache) { + public Position getApproximatePosition(Waypoint waypoint, TimePoint timePoint, + MarkPositionAtTimePointCache markPositionCache) { return null; } @@ -294,7 +299,7 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { public Tack getTack(Competitor competitor, TimePoint timePoint) throws NoWindException { return null; } - + @Override public Tack getTack(SpeedWithBearing speedWithBearing, Wind wind, TimePoint timePoint) { return null; @@ -346,7 +351,7 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { @Override public void removeListener(RaceChangeListener listener) { - + } @Override @@ -355,7 +360,8 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { } @Override - public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode) { + public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, + WindPositionMode windPositionMode) { return null; } @@ -382,12 +388,12 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { @Override public void setWindSourcesToExclude(Iterable windSourcesToExclude) { - + } @Override - public Distance getAverageAbsoluteCrossTrackError(Competitor competitor, TimePoint timePoint, boolean waitForLatestAnalysis) - throws NoWindException { + public Distance getAverageAbsoluteCrossTrackError(Competitor competitor, TimePoint timePoint, + boolean waitForLatestAnalysis) throws NoWindException { return null; } @@ -431,8 +437,8 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { } @Override - public Distance getAverageAbsoluteCrossTrackError(Competitor competitor, TimePoint from, TimePoint to, boolean upwindOnly, - boolean waitForLatestAnalyses) throws NoWindException { + public Distance getAverageAbsoluteCrossTrackError(Competitor competitor, TimePoint from, TimePoint to, + boolean upwindOnly, boolean waitForLatestAnalyses) throws NoWindException { return null; } @@ -465,7 +471,7 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { @Override public void addCourseDesignChangedListener(CourseDesignChangedListener listener) { - + } @Override @@ -596,13 +602,13 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { @Override public void setPolarDataService(PolarDataService polarDataService) { } - + @Override - public Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException, - NoWindException { + public Duration getEstimatedTimeToComplete(TimePoint timepoint) + throws NotEnoughDataHasBeenAddedException, NoWindException { return null; } - + @Override public Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache) { @@ -640,7 +646,7 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { @Override public void updateStartAndEndOfTracking(boolean waitForGPSFixesToLoad) { } - + @Override public > TrackT getSensorTrack( Competitor competitor, String trackName) { @@ -657,6 +663,11 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials { return Collections.emptySet(); } + @Override + public NavigableSet getMarkPassings(Competitor competitor, boolean waitForLatestUpdates) { + return null; + } + @Override public Distance getAverageRideHeight(Competitor competitor, TimePoint timePoint) { return null;