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

Conflicts:
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
This commit is contained in:
Steffen Schaefer committed 2015-04-29 17:00:53 +02:00
commit 89fd4e4471
171 files changed
+6008 -1229

No files matched your search

@@ -136,10 +136,10 @@ public class StartlineAnalysisCard extends Composite implements HasWidgets, Star
com.sap.sse.gwt.client.player.Timer timer = new com.sap.sse.gwt.client.player.Timer(PlayModes.Live, 1000l);
timer.pause();
ArrayList<ZoomTypes> zoomTypes = new ArrayList<ZoomTypes>();
if(startAnalysisDTO.racingProcedureType.equals(RacingProcedureType.GateStart)){
timer.setTime(startAnalysisDTO.timeOfStartInMilliSeconds+startAnalysisDTO.tailLenghtInMilliseconds);
if (startAnalysisDTO.racingProcedureType.equals(RacingProcedureType.GateStart)) {
timer.setTime(startAnalysisDTO.timeOfStartInMilliSeconds + startAnalysisDTO.tailLenghtInMilliseconds);
zoomTypes.add(ZoomTypes.BUOYS);
}else{
} else {
timer.setTime(startAnalysisDTO.timeOfStartInMilliSeconds);
zoomTypes.add(ZoomTypes.TAILS);
}
@@ -1,7 +1,7 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.domain.polars.PolarDataService;
public interface HasLeaderboardContext {
@@ -1,7 +1,7 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.domain.polars.PolarDataService;
public interface HasLeaderboardGroupContext {
@@ -5,7 +5,7 @@ import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
@@ -2,7 +2,7 @@ package com.sap.sailing.datamining.impl.data;
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.domain.polars.PolarDataService;
public class LeaderboardGroupWithContext implements HasLeaderboardGroupContext {
@@ -2,7 +2,7 @@ package com.sap.sailing.datamining.impl.data;
import com.sap.sailing.datamining.data.HasLeaderboardContext;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.domain.polars.PolarDataService;
public class LeaderboardWithContext implements HasLeaderboardContext {
@@ -20,11 +20,11 @@ import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableSpeed;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -0,0 +1,7 @@
package com.sap.sailing.domain.common;
public interface LegIdentifier extends RegattaAndRaceIdentifier {
RaceIdentifier getRaceIdentifier();
String getLegName();
int getLegNumber();
}
@@ -0,0 +1,62 @@
package com.sap.sailing.domain.common;
public class LegIdentifierImpl extends RegattaNameAndRaceName implements LegIdentifier {
private static final long serialVersionUID = 3599904513673776450L;
private RaceIdentifier raceIdentifier = null;
private String legName;
LegIdentifierImpl() {}
public LegIdentifierImpl(RegattaAndRaceIdentifier raceIdentifier, String legName) {
super(raceIdentifier.getRegattaName(), raceIdentifier.getRaceName());
this.raceIdentifier = raceIdentifier;
this.legName = legName;
}
@Override
public RaceIdentifier getRaceIdentifier() {
return this.raceIdentifier;
}
@Override
public String getLegName() {
return legName;
}
@Override
public int getLegNumber() {
return Integer.parseInt(legName)-1;
}
@Override
public String toString() {
return getRegattaName() + "/" + getRaceName() + "/" + getLegName();
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((legName == null) ? 0 : legName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
LegIdentifierImpl other = (LegIdentifierImpl) obj;
if (legName == null) {
if (other.legName != null)
return false;
} else if (!legName.equals(other.legName))
return false;
return true;
}
}
@@ -13,7 +13,8 @@ public enum RacingProcedureType {
RRS26("Fix Line Start (RRS26)"),
GateStart("Gate Start"),
ESS("\"Extreme Sailing Series\"-Start"),
BASIC("Basic Countdown Start");
BASIC("Basic Countdown Start"),
LEAGUE("League Start");
private String displayName;
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ReadonlyRac
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.basic.impl.BasicRacingProcedureImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ess.impl.ESSRacingProcedureImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.gate.impl.GateStartRacingProcedureImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league.impl.LeagueRacingProcedureImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.rrs26.impl.RRS26RacingProcedureImpl;
import com.sap.sailing.domain.base.configuration.ConfigurationLoader;
import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
@@ -48,6 +49,8 @@ public class ReadonlyRacingProcedureFactory implements RacingProcedureFactory {
return new RRS26RacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getRRS26Configuration());
case BASIC:
return new BasicRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getBasicConfiguration());
case LEAGUE:
return new LeagueRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getLeagueConfiguration());
default:
throw new UnsupportedOperationException("Unknown racing procedure " + type.toString());
}
@@ -0,0 +1,7 @@
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedure;
public interface LeagueRacingProcedure extends RacingProcedure {
}
@@ -0,0 +1,6 @@
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedureChangedListener;
public interface LeagueRacingProcedureChangedListener extends RacingProcedureChangedListener {
}
@@ -0,0 +1,22 @@
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league.impl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedurePrerequisite;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.impl.BaseRacingProcedurePrerequisite;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league.LeagueRacingProcedure;
import com.sap.sse.common.TimePoint;
/**
* Easy access to the {@link LeagueRacingProcedure}.
*/
public abstract class LeaguePrerequisite extends BaseRacingProcedurePrerequisite implements RacingProcedurePrerequisite {
public LeaguePrerequisite(FulfillmentFunction function, LeagueRacingProcedure procedure, TimePoint originalNow,
TimePoint originalStartTime) {
super(function, procedure, originalNow, originalStartTime);
}
protected LeagueRacingProcedure getProcedure() {
return (LeagueRacingProcedure) procedure;
}
}
@@ -0,0 +1,8 @@
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league.impl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.impl.RacingProcedureChangedListeners;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league.LeagueRacingProcedureChangedListener;
public class LeagueRacingProcedureChangedListeners extends RacingProcedureChangedListeners<LeagueRacingProcedureChangedListener> implements
LeagueRacingProcedureChangedListener {
}
@@ -0,0 +1,141 @@
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league.impl;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory;
import com.sap.sailing.domain.abstractlog.race.state.RaceStateEvent;
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl;
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEvents;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.FlagPoleState;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedureChangedListener;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedurePrerequisite;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedurePrerequisite.FulfillmentFunction;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.impl.BaseRacingProcedure;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.impl.NoMorePrerequisite;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.impl.RacingProcedureChangedListeners;
import com.sap.sailing.domain.base.configuration.procedures.LeagueConfiguration;
import com.sap.sailing.domain.common.racelog.FlagPole;
import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sse.common.TimePoint;
// TODO consider subclassing RRS26RacingProcedureImpl instead of this copy&paste orgy...
public class LeagueRacingProcedureImpl extends BaseRacingProcedure {
private final static long startPhaseClassUpInterval = 3 * 60 * 1000; // minutes * seconds * milliseconds
private final static long startPhaseStartModeUpInterval = 2 * 60 * 1000; // minutes * seconds * milliseconds
private final static long startPhaseStartModeDownInterval = 1 * 60 * 1000; // minutes * seconds * milliseconds
private final static Flags startmodeFlag = Flags.PAPA;
public LeagueRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author,
RaceLogEventFactory factory, LeagueConfiguration configuration) {
super(raceLog, author, factory, configuration);
update();
}
@Override
public RacingProcedureType getType() {
return RacingProcedureType.LEAGUE;
}
@Override
public boolean hasIndividualRecall() {
boolean hasRecall = super.hasIndividualRecall();
if (!hasRecall) {
return false;
} else {
return hasRecall;
}
}
@Override
protected boolean hasIndividualRecallByDefault() {
return true;
}
@Override
public RacingProcedurePrerequisite checkPrerequisitesForStart(TimePoint now, TimePoint startTime,
FulfillmentFunction function) {
return new NoMorePrerequisite(function);
}
@Override
public boolean isStartphaseActive(TimePoint startTime, TimePoint now) {
if (now.before(startTime)) {
long timeTillStart = startTime.minus(now.asMillis()).asMillis();
return timeTillStart < startPhaseClassUpInterval;
}
return false;
}
@Override
protected Collection<RaceStateEvent> createStartStateEvents(TimePoint startTime) {
// Remark: We are reusing here CLASS_UP, STARTMODE_UP and STARTMODE_DOWN from the RRS26 procedure
// The question is why there are no generic CLASS_UP, STARTMODE_UP and STARTMODE_DOWN events
return Arrays.<RaceStateEvent> asList(
new RaceStateEventImpl(startTime.minus(startPhaseClassUpInterval), RaceStateEvents.RRS26_CLASS_UP),
new RaceStateEventImpl(startTime.minus(startPhaseStartModeUpInterval), RaceStateEvents.RRS26_STARTMODE_UP),
new RaceStateEventImpl(startTime.minus(startPhaseStartModeDownInterval), RaceStateEvents.RRS26_STARTMODE_DOWN),
new RaceStateEventImpl(startTime, RaceStateEvents.START));
}
@Override
public FlagPoleState getActiveFlags(TimePoint startTime, TimePoint now) {
Flags classFlag = getConfiguration().getClassFlag() != null ?
getConfiguration().getClassFlag() : Flags.CLASS;
if (now.before(startTime.minus(startPhaseClassUpInterval))) {
return new FlagPoleState(
Arrays.asList(new FlagPole(classFlag, false), new FlagPole(startmodeFlag, false)),
null,
Arrays.asList(new FlagPole(classFlag, true), new FlagPole(startmodeFlag, false)),
startTime.minus(startPhaseClassUpInterval));
} else if (now.before(startTime.minus(startPhaseStartModeUpInterval))) {
return new FlagPoleState(
Arrays.asList(new FlagPole(classFlag, true), new FlagPole(startmodeFlag, false)),
startTime.minus(startPhaseClassUpInterval),
Arrays.asList(new FlagPole(classFlag, true), new FlagPole(startmodeFlag, true)),
startTime.minus(startPhaseStartModeUpInterval));
} else if (now.before(startTime.minus(startPhaseStartModeDownInterval))) {
return new FlagPoleState(
Arrays.asList(new FlagPole(classFlag, true), new FlagPole(startmodeFlag, true)),
startTime.minus(startPhaseStartModeUpInterval),
Arrays.asList(new FlagPole(classFlag, true), new FlagPole(startmodeFlag, false)),
startTime.minus(startPhaseStartModeDownInterval));
} else if (now.before(startTime)) {
return new FlagPoleState(
Arrays.asList(new FlagPole(classFlag, true), new FlagPole(startmodeFlag, false)),
startTime.minus(startPhaseStartModeDownInterval),
Arrays.asList(new FlagPole(classFlag, false), new FlagPole(startmodeFlag, false)),
startTime);
} else {
if (isIndividualRecallDisplayed(now)) {
return new FlagPoleState(
Arrays.asList(new FlagPole(Flags.XRAY, true)),
getIndividualRecallDisplayedTime(),
Arrays.asList(new FlagPole(Flags.XRAY, false)),
getIndividualRecallRemovalTime());
} else if (isFinished(now)) {
return new FlagPoleState(
Arrays.asList(new FlagPole(Flags.BLUE, false)), getFinishedTime());
} else if (isInFinishingPhase(now)) {
return new FlagPoleState(
Arrays.asList(new FlagPole(Flags.BLUE, true)),
getFinishingTime(),
Arrays.asList(new FlagPole(Flags.BLUE, false)),
null);
} else {
TimePoint recallRemoved = getIndividualRecallRemovalTime();
return new FlagPoleState(Collections.<FlagPole>emptyList(), recallRemoved == null ? startTime : recallRemoved);
}
}
}
@Override
protected RacingProcedureChangedListeners<? extends RacingProcedureChangedListener> createChangedListenerContainer() {
return new LeagueRacingProcedureChangedListeners();
}
}
@@ -5,6 +5,7 @@ import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedure;
import com.sap.sailing.domain.base.configuration.procedures.ESSConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.GateStartConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.LeagueConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.RRS26Configuration;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
@@ -43,6 +44,12 @@ public interface RegattaConfiguration extends Serializable, Cloneable {
*/
ESSConfiguration getESSConfiguration();
/**
* Gets the configuration for league races.
* @return <code>null</code> if there is no configuration.
*/
LeagueConfiguration getLeagueConfiguration();
/**
* Gets the configuration for Basic races.
* @return <code>null</code> if there is no configuration.
@@ -21,6 +21,7 @@ public class EmptyRegattaConfiguration extends RegattaConfigurationImpl implemen
setGateStartConfiguration(new GateStartConfigurationImpl());
setESSConfiguration(new ESSConfigurationImpl());
setBasicConfiguration(new RacingProcedureConfigurationImpl());
setLeagueConfiguration(new LeagueConfigurationImpl());
return clone();
}
@@ -0,0 +1,20 @@
package com.sap.sailing.domain.base.configuration.impl;
import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.LeagueConfiguration;
public class LeagueConfigurationImpl extends RacingProcedureConfigurationImpl implements LeagueConfiguration {
private static final long serialVersionUID = 3625803505541394766L;
protected LeagueConfigurationImpl copy() {
LeagueConfigurationImpl copy = (LeagueConfigurationImpl) super.copy(new LeagueConfigurationImpl());
return copy;
}
@Override
public RacingProcedureConfiguration merge(RacingProcedureConfiguration update) {
LeagueConfigurationImpl target = (LeagueConfigurationImpl) super.merge(update);
return target;
}
}
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration;
import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.ESSConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.GateStartConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.LeagueConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.RRS26Configuration;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
@@ -18,6 +19,7 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
private RRS26Configuration rrs26Configuration;
private GateStartConfiguration gateStartConfiguration;
private ESSConfiguration essConfiguration;
private LeagueConfiguration leagueConfiguration;
private RacingProcedureConfiguration basicConfiguration;
@Override
@@ -65,6 +67,15 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
this.essConfiguration = essConfiguration;
}
@Override
public LeagueConfiguration getLeagueConfiguration() {
return leagueConfiguration;
}
public void setLeagueConfiguration(LeagueConfiguration leagueConfiguration) {
this.leagueConfiguration = leagueConfiguration;
}
@Override
public RacingProcedureConfiguration getBasicConfiguration() {
return basicConfiguration;
@@ -83,6 +94,7 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
copy.setGateStartConfiguration(gateStartConfiguration);
copy.setESSConfiguration(essConfiguration);
copy.setBasicConfiguration(basicConfiguration);
copy.setLeagueConfiguration(leagueConfiguration);
return copy;
}
@@ -112,6 +124,10 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
target.setBasicConfiguration(
(RacingProcedureConfiguration) target.getBasicConfiguration().merge(update.getBasicConfiguration()));
}
if (update.getLeagueConfiguration() != null) {
target.setLeagueConfiguration(
(LeagueConfiguration) target.getLeagueConfiguration().merge(update.getLeagueConfiguration()));
}
return target;
}
@@ -0,0 +1,7 @@
package com.sap.sailing.domain.base.configuration.procedures;
import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration;
public interface LeagueConfiguration extends RacingProcedureConfiguration {
}
@@ -149,7 +149,9 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
Wind combinedWindDirection = combinedTrack.getAveragedWind(/* position */ null, now);
// The course layout makes a wind estimation around 7deg. The confidence of the cluster based wind estimation is a lot
// higher that that of the course layout wind (currently at approximately 10E-13), we will end up quite near 180 deg.
assertEquals(180.0, combinedWindDirection.getBearing().getDegrees(), 0.2);
// Update 04/24/15: Since polar data service is not available here, the confidence will not be as good as it once was.
// So we have quite a big delta in the assert
assertEquals(180.0, combinedWindDirection.getBearing().getDegrees(), 0.9);
}
/**
@@ -40,6 +40,7 @@ import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
import com.sap.sailing.domain.regattalike.RegattaLikeListener;
@@ -904,4 +905,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
// TODO Auto-generated method stub
return 0;
}
@Override
public void setPolarDataService(PolarDataService polarDataService) {
}
}
@@ -29,6 +29,7 @@ import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
@@ -609,4 +610,8 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
return 0;
}
@Override
public void setPolarDataService(PolarDataService polarDataService) {
}
}
@@ -17,6 +17,7 @@ Export-Package: com.sap.sailing.domain.base,
com.sap.sailing.domain.markpassingcalculation.impl,
com.sap.sailing.domain.markpassingcalculation.splining,
com.sap.sailing.domain.masterdataimport,
com.sap.sailing.domain.polars,
com.sap.sailing.domain.racelog,
com.sap.sailing.domain.racelog.impl,
com.sap.sailing.domain.racelog.tracking,
@@ -38,4 +39,5 @@ Require-Bundle: com.googlecode.java-diff-utils;bundle-version="1.3.0",
com.sap.sse.datamining.shared,
com.sap.sse.common,
com.sap.sse,
com.sap.sse.shared.android
com.sap.sse.shared.android,
org.apache.commons.math
@@ -1,4 +1,4 @@
package com.sap.sailing.polars;
package com.sap.sailing.domain.polars;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.common.Bearing;
@@ -1,4 +1,4 @@
package com.sap.sailing.polars.regression;
package com.sap.sailing.domain.polars;
public class NotEnoughDataHasBeenAddedException extends Exception {
@@ -1,4 +1,4 @@
package com.sap.sailing.polars;
package com.sap.sailing.domain.polars;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@@ -17,10 +17,9 @@ import com.sap.sailing.domain.common.PolarSheetGenerationSettings;
import com.sap.sailing.domain.common.PolarSheetsData;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.polars.mining.MovingAverageProcessor;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sse.common.Util.Pair;
/**
@@ -206,7 +205,28 @@ public interface PolarDataService {
*/
PolynomialFunction getSpeedRegressionFunction(BoatClass boatClass, double trueWindAngle) throws NotEnoughDataHasBeenAddedException;
/**
* For Upwind and Downwind returns the typical angle needed for a maneuver.
*
* @param boatClass
* @param maneuverType
* needs to be Tack or Jibe
* @param windSpeed
* Since the maneuver angle is windSpeed depended, supply it here
* @return angle with confidence as supplied by polars. Angle is always >= 0
* @throws NotEnoughDataHasBeenAddedException
*/
BearingWithConfidence<Void> getManeuverAngle(BoatClass boatClass, ManeuverType maneuverType, Speed windSpeed)
throws NotEnoughDataHasBeenAddedException;
void raceFinishedLoading(TrackedRace race);
/**
* See {@link #getAverageSpeedWithBearing(BoatClass, Speed, LegType, Tack, boolean)}
* Always use regression
*/
SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException;
}
@@ -35,6 +35,7 @@ import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.dto.TrackedRaceDTO;
import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
@@ -770,4 +771,6 @@ public interface TrackedRace extends Serializable {
boolean isUsingMarkPassingCalculator();
void setPolarDataService(PolarDataService polarDataService);
}
@@ -101,6 +101,8 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.confidence.ConfidenceBasedWindAverager;
import com.sap.sailing.domain.confidence.ConfidenceFactory;
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;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
@@ -317,6 +319,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
*/
private transient ShortTimeWindCache shortTimeWindCache;
private transient PolarDataService polarDataService;
public TrackedRaceImpl(final TrackedRegatta trackedRegatta, RaceDefinition race,
final Iterable<Sideline> sidelines, final WindStore windStore, final GPSFixStore gpsFixStore,
long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind,
@@ -407,7 +411,6 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
windTracks.putAll(loadedWindTracks);
updateEventTimePoints(loadedWindTracks.values());
logger.info("Finished loading wind tracks for " + getRace().getName() + ". Found " + windTracks.size() + " wind tracks for this race.");
} finally {
synchronized (TrackedRaceImpl.this) {
loadingFromWindStoreState = LoadingFromStoresState.FINISHED;
@@ -1861,41 +1864,67 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
BearingWithConfidence<TimePoint> resultBearing = null;
ScalablePosition scaledPosition = null;
int numberOfFixesConsideredForScaledPosition = 0;
Set<WindSource> estimationExcluded = new HashSet<>();
estimationExcluded.addAll(getWindSources(WindSourceType.TRACK_BASED_ESTIMATION));
estimationExcluded.addAll(getWindSources(WindSourceType.COURSE_BASED));
if (bearings != null) {
BearingWithConfidenceCluster<TimePoint>[] bearingClustersUpwind = bearings.get(LegType.UPWIND).getA().splitInTwo(
getMinimumAngleBetweenDifferentTacksUpwind(), timePoint);
int numberOfFixesUpwind = bearings.get(LegType.UPWIND).getA().size();
if (numberOfFixesUpwind > 0) {
ScalablePosition upwindPosition = bearings.get(LegType.UPWIND).getB();
Pair<Double, Double> minimumAngleBetweenDifferentTacksUpwindWithConfidence = getMinimumAngleBetweenDifferentTacksUpwind(getWind(
upwindPosition.divide(numberOfFixesUpwind), timePoint, estimationExcluded));
BearingWithConfidenceCluster<TimePoint>[] bearingClustersUpwind = bearings
.get(LegType.UPWIND)
.getA()
.splitInTwo(
minimumAngleBetweenDifferentTacksUpwindWithConfidence.getA(),
timePoint);
if (!bearingClustersUpwind[0].isEmpty() && !bearingClustersUpwind[1].isEmpty()) {
BearingWithConfidence<TimePoint> average0 = bearingClustersUpwind[0].getAverage(timePoint);
BearingWithConfidence<TimePoint> average1 = bearingClustersUpwind[1].getAverage(timePoint);
upwindNumberOfRelevantBoats = Math
.min(bearingClustersUpwind[0].size(), bearingClustersUpwind[1].size());
upwindNumberOfRelevantBoats = Math.min(bearingClustersUpwind[0].size(),
bearingClustersUpwind[1].size());
confidence = Math.min(average0.getConfidence(), average1.getConfidence())
* getRace().getBoatClass().getUpwindWindEstimationConfidence(upwindNumberOfRelevantBoats);
* getRace().getBoatClass().getUpwindWindEstimationConfidence(upwindNumberOfRelevantBoats)
* minimumAngleBetweenDifferentTacksUpwindWithConfidence.getB();
reversedUpwindAverage = new BearingWithConfidenceImpl<TimePoint>(average0.getObject()
.middle(average1.getObject()).reverse(), confidence, timePoint);
scaledPosition = bearings.get(LegType.UPWIND).getB();
scaledPosition = upwindPosition;
numberOfFixesConsideredForScaledPosition += bearings.get(LegType.UPWIND).getA().size();
}
}
BearingWithConfidenceImpl<TimePoint> downwindAverage = null;
int downwindNumberOfRelevantBoats = 0;
BearingWithConfidenceCluster<TimePoint>[] bearingClustersDownwind = bearings.get(LegType.DOWNWIND).getA()
.splitInTwo(getMinimumAngleBetweenDifferentTacksDownwind(), timePoint);
int numberOfFixesDownwind = bearings.get(LegType.DOWNWIND).getA().size();
if (numberOfFixesDownwind > 0) {
ScalablePosition downwindPosition = bearings.get(LegType.DOWNWIND).getB();
Pair<Double, Double> minimumAngleBetweenDifferentTacksDownwindWithConfidence = getMinimumAngleBetweenDifferentTacksDownwind(getWind(
downwindPosition.divide(numberOfFixesDownwind), timePoint, estimationExcluded));
BearingWithConfidenceCluster<TimePoint>[] bearingClustersDownwind = bearings
.get(LegType.DOWNWIND)
.getA()
.splitInTwo(
minimumAngleBetweenDifferentTacksDownwindWithConfidence.getA(),
timePoint);
if (!bearingClustersDownwind[0].isEmpty() && !bearingClustersDownwind[1].isEmpty()) {
BearingWithConfidence<TimePoint> average0 = bearingClustersDownwind[0].getAverage(timePoint);
BearingWithConfidence<TimePoint> average1 = bearingClustersDownwind[1].getAverage(timePoint);
downwindNumberOfRelevantBoats = Math.min(bearingClustersDownwind[0].size(),
bearingClustersDownwind[1].size());
confidence = Math.min(average0.getConfidence(), average1.getConfidence())
* getRace().getBoatClass().getDownwindWindEstimationConfidence(downwindNumberOfRelevantBoats);
* getRace().getBoatClass().getDownwindWindEstimationConfidence(
downwindNumberOfRelevantBoats)
* minimumAngleBetweenDifferentTacksDownwindWithConfidence.getB();
downwindAverage = new BearingWithConfidenceImpl<TimePoint>(average0.getObject().middle(
average1.getObject()), confidence, timePoint);
if (scaledPosition == null) {
scaledPosition = bearings.get(LegType.DOWNWIND).getB();
scaledPosition = downwindPosition;
} else {
scaledPosition.add(bearings.get(LegType.DOWNWIND).getB());
scaledPosition.add(downwindPosition);
}
numberOfFixesConsideredForScaledPosition += bearings.get(LegType.DOWNWIND).getA().size();
}
}
BearingWithConfidenceCluster<TimePoint> resultCluster = new BearingWithConfidenceCluster<TimePoint>(weigher);
assert upwindNumberOfRelevantBoats == 0 || reversedUpwindAverage != null;
if (upwindNumberOfRelevantBoats > 0) {
@@ -2716,12 +2745,41 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
return getRace().getBoatClass().getManeuverDegreeAngleThreshold();
}
private double getMinimumAngleBetweenDifferentTacksDownwind() {
return getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksDownwind();
private Pair<Double, Double> getMinimumAngleBetweenDifferentTacksDownwind(Wind wind) {
Pair<Double, Double> result;
double defaultAngle = getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksDownwind();
double threshold = 20;
result = usePolarsIfPossible(wind, defaultAngle, LegType.DOWNWIND, threshold);
return result;
}
private double getMinimumAngleBetweenDifferentTacksUpwind() {
return getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksUpwind();
private Pair<Double, Double> getMinimumAngleBetweenDifferentTacksUpwind(Wind wind) {
Pair<Double, Double> result;
double defaultAngle = getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksUpwind();
double threshold = 10;
result = usePolarsIfPossible(wind, defaultAngle, LegType.UPWIND, threshold);
return result;
}
private Pair<Double, Double> usePolarsIfPossible(Wind wind, double defaultAngle, LegType legType, double threshold) {
Pair<Double, Double> result;
if (polarDataService != null) {
try {
BearingWithConfidence<Void> average = polarDataService.getManeuverAngle(getRace().getBoatClass(),
legType == LegType.DOWNWIND ? ManeuverType.JIBE : ManeuverType.TACK, wind);
double averageAngleInDegMinusThreshold = average.getObject().getDegrees() - threshold;
if (averageAngleInDegMinusThreshold < defaultAngle) {
result = new Pair<Double, Double>(defaultAngle, 0.1);
} else {
result = new Pair<Double, Double>(averageAngleInDegMinusThreshold, average.getConfidence());
}
} catch (NotEnoughDataHasBeenAddedException e) {
result = new Pair<Double, Double>(defaultAngle, 0.1);
}
} else {
result = new Pair<Double, Double>(defaultAngle, 0.1);
}
return result;
}
private long getApproximateManeuverDurationInMilliseconds() {
@@ -2880,7 +2938,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
(DynamicGPSFixTrack<Competitor, GPSFixMoving>) tracks.get(competitor), log,
competitor);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not load track for " + competitor);
logger.log(Level.WARNING, "Could not load track for " + competitor, e);
}
}
logger.info("Finished loading competitor tracks for " + getRace().getName());
@@ -2890,7 +2948,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
gpsFixStore.loadMarkTrack((DynamicGPSFixTrack<Mark, GPSFix>) markTracks.get(mark), log,
mark);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not load track for " + mark);
logger.log(Level.WARNING, "Could not load track for " + mark, e);
}
}
logger.info("Finished loading mark tracks for " + getRace().getName());
@@ -3457,4 +3515,9 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
return result;
}
@Override
public void setPolarDataService(PolarDataService polarDataService) {
this.polarDataService = polarDataService;
}
}
+7
View File
@@ -444,4 +444,11 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al
version="0.0.0"
unpack="false"/>
<plugin
id="com.sap.sailing.polars"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
</feature>
@@ -38,6 +38,7 @@ import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
import com.sap.sailing.domain.regattalike.RegattaLikeListener;
@@ -902,4 +903,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
// TODO Auto-generated method stub
return 0;
}
@Override
public void setPolarDataService(PolarDataService polarDataService) {
}
}
@@ -50,10 +50,7 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sse.gwt.theme
Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator
Bundle-ActivationPolicy: lazy
Import-Package: com.sap.sailing.polars,
com.sap.sailing.polars.factory,
com.sap.sailing.polars.regression,
javax.jms;version="1.1.0",
Import-Package: javax.jms;version="1.1.0",
javax.servlet;version="3.1.0",
javax.servlet.descriptor;version="3.1.0",
javax.servlet.http;version="3.1.0",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 281 KiB

After

Width:  |  Height:  |  Size: 286 KiB

@@ -44,6 +44,7 @@ public interface TextMessages extends Messages {
String overview();
String sapSailing();
String search();
String startSimulator();
String countdownDays();
String countdownHours();
@@ -33,6 +33,7 @@ whatsNew=What''s new
overview=Overview
sapSailing=SAP Sailing
search=Search
startSimulator=Start Simulator
countdownDays=Days
countdownHours=Hrs
@@ -33,6 +33,7 @@ whatsNew=Neuigkeiten
overview=Übersicht
sapSailing=SAP Sailing
search=Suche
startSimulator=Simulator starten
countdownDays=Tage
countdownHours=Std.
@@ -1,5 +1,8 @@
package com.sap.sailing.gwt.home.client.app;
import java.util.HashMap;
import java.util.Map;
import com.google.gwt.place.shared.PlaceController;
import com.sap.sailing.gwt.home.client.place.aboutus.AboutUsPlace;
import com.sap.sailing.gwt.home.client.place.contact.ContactPlace;
@@ -19,6 +22,7 @@ import com.sap.sailing.gwt.home.client.place.sponsoring.SponsoringPlace;
import com.sap.sailing.gwt.home.client.place.start.StartPlace;
import com.sap.sailing.gwt.home.client.place.whatsnew.WhatsNewPlace;
import com.sap.sailing.gwt.home.client.place.whatsnew.WhatsNewPlace.WhatsNewNavigationTabs;
import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory;
public class HomePlacesNavigator extends AbstractPlaceNavigator {
@@ -42,6 +46,11 @@ public class HomePlacesNavigator extends AbstractPlaceNavigator {
return createLocalPlaceNavigation(new WhatsNewPlace(navigationTab));
}
public String getSimulatorURL() {
Map<String, String> parameters = new HashMap<String, String>();
return EntryPointLinkFactory.createSimulatorLink(parameters);
}
public PlaceNavigation<SponsoringPlace> getSponsoringNavigation() {
return createGlobalPlaceNavigation(new SponsoringPlace());
}
@@ -28,15 +28,15 @@ public class TabletAndDesktopWhatsNewView extends Composite implements WhatsNewV
private static final HyperlinkImpl HYPERLINK_IMPL = GWT.create(HyperlinkImpl.class);
@UiField HTML sailingAnalyticsNotes;
// @UiField HTML sailingSimulatorNotes;
@UiField HTML sailingSimulatorNotes;
@UiField HTML raceCommitteeAppNotes;
@UiField Anchor sailingAnalyticsNotesAnchor;
// @UiField Anchor sailingSimulatorNotesAnchor;
@UiField Anchor sailingSimulatorNotesAnchor;
@UiField Anchor raceCommitteeAppNotesAnchor;
private final PlaceNavigation<WhatsNewPlace> sailingAnalyticNotesNavigation;
// private final PlaceNavigation<WhatsNewPlace> sailingSimulatorNoteNavigation;
private final PlaceNavigation<WhatsNewPlace> sailingSimulatorNoteNavigation;
private final PlaceNavigation<WhatsNewPlace> raceCommitteeAppNotesNavigation;
private final List<Anchor> links;
@@ -49,19 +49,19 @@ public class TabletAndDesktopWhatsNewView extends Composite implements WhatsNewV
initWidget(uiBinder.createAndBindUi(this));
sailingAnalyticsNotes.setHTML(WhatsNewResources.INSTANCE.getSailingAnalyticsNotesHtml().getText());
// sailingSimulatorNotes.setHTML(WhatsNewResources.INSTANCE.getSailingSimulatorNotesHtml().getText());
sailingSimulatorNotes.setHTML(WhatsNewResources.INSTANCE.getSailingSimulatorNotesHtml().getText());
raceCommitteeAppNotes.setHTML(WhatsNewResources.INSTANCE.getRaceCommitteeAppNotesHtml().getText());
sailingAnalyticNotesNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingAnalytics);
// sailingSimulatorNoteNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingSimulator);
sailingSimulatorNoteNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingSimulator);
raceCommitteeAppNotesNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.RaceCommiteeApp);
sailingAnalyticsNotesAnchor.setHref(sailingAnalyticNotesNavigation.getTargetUrl());
// sailingSimulatorNotesAnchor.setHref(sailingSimulatorNoteNavigation.getTargetUrl());
sailingSimulatorNotesAnchor.setHref(sailingSimulatorNoteNavigation.getTargetUrl());
raceCommitteeAppNotesAnchor.setHref(raceCommitteeAppNotesNavigation.getTargetUrl());
links = Arrays.asList(new Anchor[] { sailingAnalyticsNotesAnchor, /*sailingSimulatorNotesAnchor,*/ raceCommitteeAppNotesAnchor });
contentWidgets = Arrays.asList(new HTML[] { sailingAnalyticsNotes, /*sailingSimulatorNotes,*/ raceCommitteeAppNotes });
links = Arrays.asList(new Anchor[] { sailingAnalyticsNotesAnchor, sailingSimulatorNotesAnchor, raceCommitteeAppNotesAnchor });
contentWidgets = Arrays.asList(new HTML[] { sailingAnalyticsNotes, sailingSimulatorNotes, raceCommitteeAppNotes });
switch(navigationTab) {
case PostRaceAnalytics:
@@ -73,7 +73,7 @@ public class TabletAndDesktopWhatsNewView extends Composite implements WhatsNewV
setActiveContent(sailingAnalyticsNotes, sailingAnalyticsNotesAnchor);
break;
case SailingSimulator:
// setActiveContent(sailingSimulatorNotes, sailingSimulatorNotesAnchor);
setActiveContent(sailingSimulatorNotes, sailingSimulatorNotesAnchor);
break;
case TrainingDiary:
break;
@@ -85,13 +85,13 @@ public class TabletAndDesktopWhatsNewView extends Composite implements WhatsNewV
setActiveContent(sailingAnalyticsNotes, sailingAnalyticsNotesAnchor);
handleClickEventWithLocalNavigation(event, sailingAnalyticNotesNavigation);
}
/*
@UiHandler("sailingSimulatorNotesAnchor")
void featuresClicked(ClickEvent event) {
setActiveContent(sailingSimulatorNotes, sailingSimulatorNotesAnchor);
handleClickEventWithLocalNavigation(event, sailingSimulatorNoteNavigation);
}
*/
@UiHandler("raceCommitteeAppNotesAnchor")
void releaseNotesClicked(ClickEvent event) {
setActiveContent(raceCommitteeAppNotes, raceCommitteeAppNotesAnchor);
@@ -10,9 +10,7 @@
<div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.columns}">
<g:Anchor ui:field="sailingAnalyticsNotesAnchor" href="javascript:;" styleName="{local_res.css.whatsnew_nav_link}"><ui:text from='{i18n.solutionsSAPHeadline}'/></g:Anchor>
<!--
<g:Anchor ui:field="sailingSimulatorNotesAnchor" href="javascript:;" styleName="{local_res.css.whatsnew_nav_link}"><ui:text from='{i18n.solutionsSimulatorHeadline}'/></g:Anchor>
-->
<g:Anchor ui:field="raceCommitteeAppNotesAnchor" href="javascript:;" styleName="{local_res.css.whatsnew_nav_link}"><ui:text from='{i18n.solutionsRaceHeadline}'/></g:Anchor>
</div>
</div>
@@ -20,9 +18,7 @@
<div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.columns}">
<g:HTML ui:field="sailingAnalyticsNotes" />
<!--
<g:HTML ui:field="sailingSimulatorNotes" />
-->
<g:HTML ui:field="raceCommitteeAppNotes" />
</div>
</div>
@@ -44,6 +44,8 @@ public class Solutions extends Composite {
@UiField Anchor sailingAnalyticsDetailsAnchor;
@UiField Anchor raceCommitteeAppDetailsAnchor;
@UiField Anchor simulatorStartAnchor;
@UiField Anchor simulatorAppDetailsAnchor;
private final PlaceNavigation<SolutionsPlace> sailingAnalyticsNavigation;
private final PlaceNavigation<SolutionsPlace> raceCommitteeAppNavigation;
@@ -55,6 +57,7 @@ public class Solutions extends Composite {
private final PlaceNavigation<WhatsNewPlace> sailingAnalyticsDetailsNavigation;
private final PlaceNavigation<WhatsNewPlace> raceCommitteeAppDetailsNavigation;
private final PlaceNavigation<WhatsNewPlace> simulatorAppDetailsNavigation;
private final HomePlacesNavigator placesNavigator;
public Solutions(SolutionsNavigationTabs navigationTab, HomePlacesNavigator placesNavigator) {
@@ -67,9 +70,12 @@ public class Solutions extends Composite {
sailingAnalyticsDetailsNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingAnalytics);
raceCommitteeAppDetailsNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.RaceCommiteeApp);
simulatorAppDetailsNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingSimulator);
sailingAnalyticsDetailsAnchor.setHref(sailingAnalyticsDetailsNavigation.getTargetUrl());
raceCommitteeAppDetailsAnchor.setHref(raceCommitteeAppDetailsNavigation.getTargetUrl());
simulatorAppDetailsAnchor.setHref(simulatorAppDetailsNavigation.getTargetUrl());
simulatorStartAnchor.setHref(placesNavigator.getSimulatorURL());
sailingAnalyticsNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.SailingAnalytics);
raceCommitteeAppNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.RaceCommiteeApp);
@@ -128,6 +134,11 @@ public class Solutions extends Composite {
handleClickEventWithPlaceController(e, sailingAnalyticsDetailsNavigation);
}
@UiHandler("simulatorAppDetailsAnchor")
public void simulatorAppDetailsAnchorClicked(ClickEvent e) {
handleClickEventWithPlaceController(e, simulatorAppDetailsNavigation);
}
private void scrollToView(SolutionsNavigationTabs navigationTab) {
switch (navigationTab) {
case SailingAnalytics:
@@ -67,7 +67,9 @@
<div class="{res.mediaCss.small5} {res.mediaCss.smalloffset7} {res.mediaCss.columns}">
<h2><ui:text from='{i18n.solutionsSimulatorHeadline}'/></h2>
<p><ui:text from='{i18n.solutionsSimulatorText}'/></p>
<!-- <a href="#" class="{res.mainCss.button}">Learn More</a> -->
<g:Anchor ui:field="simulatorAppDetailsAnchor" styleName="{res.mainCss.button}"><ui:text from='{i18n.whatsNew}'/></g:Anchor>
<span>&nbsp;&nbsp;</span>
<g:Anchor ui:field="simulatorStartAnchor" target="_blank" styleName="{res.mainCss.button}"><ui:text from='{i18n.startSimulator}'/></g:Anchor>
</div>
</div>
</div>
@@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.Map;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.LegIdentifier;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
@@ -20,10 +21,11 @@ public class GetRaceMapDataAction implements AsyncAction<RaceMapDataDTO> {
private final Map<CompetitorDTO, Date> to;
private final boolean extrapolate;
private final Date date;
private final LegIdentifier simulationLegIdentifier;
public GetRaceMapDataAction(SailingServiceAsync sailingService, Iterable<CompetitorDTO> allCompetitors,
RegattaAndRaceIdentifier raceIdentifier, Date date, Map<CompetitorDTO, Date> from,
Map<CompetitorDTO, Date> to, boolean extrapolate) {
Map<CompetitorDTO, Date> to, boolean extrapolate, LegIdentifier simulationLegIdentifier) {
this.allCompetitors = allCompetitors;
this.sailingService = sailingService;
this.raceIdentifier = raceIdentifier;
@@ -31,6 +33,7 @@ public class GetRaceMapDataAction implements AsyncAction<RaceMapDataDTO> {
this.from = from;
this.to = to;
this.extrapolate = extrapolate;
this.simulationLegIdentifier = simulationLegIdentifier;
}
@Override
@@ -46,7 +49,7 @@ public class GetRaceMapDataAction implements AsyncAction<RaceMapDataDTO> {
}
sailingService.getRaceMapData(raceIdentifier, date, fromByCompetitorIdAsString, toByCompetitorIdAsString,
extrapolate, new AsyncCallback<CompactRaceMapDataDTO>() {
extrapolate, simulationLegIdentifier, new AsyncCallback<CompactRaceMapDataDTO>() {
@Override
public void onFailure(Throwable caught) {
callback.onFailure(caught);
@@ -1,12 +1,11 @@
package com.sap.sailing.gwt.ui.actions;
import java.util.Date;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.LegIdentifier;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMap;
import com.sap.sailing.gwt.ui.shared.SimulatorResultsDTO;
import com.sap.sailing.gwt.ui.shared.racemap.RaceSimulationOverlay;
import com.sap.sse.gwt.client.async.AsyncAction;
/**
@@ -18,19 +17,15 @@ import com.sap.sse.gwt.client.async.AsyncAction;
*/
public class GetSimulationAction implements AsyncAction<SimulatorResultsDTO> {
private final SailingServiceAsync sailingService;
private final RegattaAndRaceIdentifier raceIdentifier;
private final Date from;
private final Date prevStartTime;
private final LegIdentifier legIdentifier;
public GetSimulationAction(SailingServiceAsync sailingService, RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime) {
public GetSimulationAction(SailingServiceAsync sailingService, LegIdentifier legIdentifier) {
this.sailingService = sailingService;
this.raceIdentifier = raceIdentifier;
this.from = from;
this.prevStartTime = prevStartTime;
this.legIdentifier = legIdentifier;
}
@Override
public void execute(AsyncCallback<SimulatorResultsDTO> callback) {
sailingService.getSimulatorResults(raceIdentifier, from, prevStartTime, callback);
sailingService.getSimulatorResults(legIdentifier, callback);
}
}
@@ -41,7 +41,7 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> {
private final TextBox sailId;
private final TextBox email;
private final StringMessages stringMessages;
private final TextBox flagImageURL;
private final URLFieldWithFileUpload flagImageURL;
private final URLFieldWithFileUpload imageUrlAndUploadComposite;
public CompetitorEditDialog(final StringMessages stringMessages, CompetitorDTO competitorToEdit,
@@ -123,12 +123,12 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> {
}
}
this.sailId = createTextBox(competitorToEdit.getSailID());
this.flagImageURL = createTextBox(competitorToEdit.getFlagImageURL(), 100);
imageUrlAndUploadComposite = new URLFieldWithFileUpload(stringMessages);
imageUrlAndUploadComposite.setURL(competitorToEdit.getImageURL());
this.flagImageURL = new URLFieldWithFileUpload(stringMessages);
this.flagImageURL.setURL(competitorToEdit.getFlagImageURL());
this.imageUrlAndUploadComposite = new URLFieldWithFileUpload(stringMessages);
this.imageUrlAndUploadComposite.setURL(competitorToEdit.getImageURL());
}
@Override
public void show() {
super.show();
@@ -182,7 +182,7 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> {
/* twoLetterIsoCountryCode */ null,
threeLetterIocCountryCode.getValue(threeLetterIocCountryCode.getSelectedIndex()),
/* countryName */ null, sailId.getText(), competitorToEdit.getIdAsString(),
imageUrlAndUploadComposite.getURL(), flagImageURL.getText(), boatClass);
imageUrlAndUploadComposite.getURL(), flagImageURL.getURL(), boatClass);
return result;
}
@@ -60,6 +60,11 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
private ListBox basicClassFlagListBox;
private CheckBox basicRecallBox;
private DisclosurePanel leagueDisclosurePanel;
private CheckBox leagueEnabledBox;
private ListBox leagueClassFlagListBox;
private CheckBox leagueRecallBox;
public RegattaConfigurationDialog(DeviceConfigurationDTO.RegattaConfigurationDTO regattaConfiguration,
StringMessages messages, DataEntryDialog.DialogCallback<RegattaConfigurationDTO> callback) {
super(messages.racingProcedureConfiguration(), "", messages.save(), messages.cancel(), /* validator */ null, callback);
@@ -75,6 +80,7 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
setupGateStart();
setupESS();
setupBasic();
setupLeague();
if (rrs26EnabledBox.getValue()) {
rrs26DisclosurePanel.setOpen(true);
@@ -88,6 +94,9 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
if (basicEnabledBox.getValue()) {
basicDisclosurePanel.setOpen(true);
}
if (leagueEnabledBox.getValue()) {
leagueDisclosurePanel.setOpen(true);
}
return contentPanel;
}
@@ -109,7 +118,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
racingProcedureListBox.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
markAsDrity(true);
}
});
grid.setWidget(gridRow, 0, new Label(stringMessages.racingProcedure()));
@@ -126,7 +134,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
designerModeEntryListBox.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
markAsDrity(true);
}
});
grid.setWidget(gridRow, 0, new Label(stringMessages.courseDesignerMode()));
@@ -143,7 +150,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
box.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
markAsDrity(true);
}
});
return box;
@@ -155,7 +161,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
}
});
return box;
@@ -170,7 +175,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
rrs26EnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
boolean isActive = event.getValue();
rrs26ClassFlagListBox.setEnabled(isActive);
rrs26RecallBox.setEnabled(isActive);
@@ -215,7 +219,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
rrs26StartModeFlagsBox.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
markAsDrity(true);
}
});
}
@@ -229,7 +232,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
gateStartEnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
gateStartClassFlagListBox.setEnabled(event.getValue());
gateStartRecallBox.setEnabled(event.getValue());
gateStartPathfinderBox.setEnabled(event.getValue());
@@ -244,14 +246,12 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
gateStartPathfinderBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
}
});
gateStartGolfDownBox = createCheckbox(stringMessages.hasAdditionalGolfDownTime());
gateStartGolfDownBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
}
});
@@ -284,7 +284,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
essEnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
essClassFlagListBox.setEnabled(event.getValue());
essRecallBox.setEnabled(event.getValue());
}
@@ -318,7 +317,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
basicEnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
basicClassFlagListBox.setEnabled(event.getValue());
basicRecallBox.setEnabled(event.getValue());
}
@@ -343,8 +341,37 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
contentPanel.add(basicDisclosurePanel);
}
private void markAsDrity(boolean b) {
// hmnn do we need to this?
private void setupLeague() {
leagueDisclosurePanel = new DisclosurePanel(stringMessages.leagueStart());
VerticalPanel panel = new VerticalPanel();
Grid grid = new Grid(2, 3);
leagueEnabledBox = new CheckBox(stringMessages.setConfiguration());
leagueEnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
leagueClassFlagListBox.setEnabled(event.getValue());
leagueRecallBox.setEnabled(event.getValue());
}
});
leagueClassFlagListBox = setupClassFlagListBox(originalConfiguration == null ? null
: originalConfiguration.leagueConfiguration);
leagueClassFlagListBox.setWidth("100%");
leagueRecallBox = setupRecallBox();
grid.setWidget(0, 0, new Label(stringMessages.classFlag() + ":"));
grid.setWidget(0, 1, leagueClassFlagListBox);
grid.setWidget(0, 2, createHelpImage(stringMessages.classFlagHelpText("league start")));
grid.setWidget(1, 0, leagueRecallBox);
grid.setWidget(1, 2, createHelpImage(stringMessages.individualRecallHelpText()));
leagueEnabledBox.setValue(originalConfiguration != null && originalConfiguration.leagueConfiguration != null);
ValueChangeEvent.fire(leagueEnabledBox, leagueEnabledBox.getValue());
panel.add(leagueEnabledBox);
panel.add(grid);
leagueDisclosurePanel.add(panel);
contentPanel.add(leagueDisclosurePanel);
}
private Widget createHelpImage(String tooltip) {
@@ -399,6 +426,10 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
result.basicConfiguration = new DeviceConfigurationDTO.RegattaConfigurationDTO.RacingProcedureConfigurationDTO();
getRacingProcedureConfigurationResults(result.basicConfiguration, basicClassFlagListBox, basicRecallBox);
}
if (leagueEnabledBox.getValue()) {
result.leagueConfiguration = new DeviceConfigurationDTO.RegattaConfigurationDTO.LeagueConfigurationDTO();
getRacingProcedureConfigurationResults(result.leagueConfiguration, leagueClassFlagListBox, leagueRecallBox);
}
return result;
}
@@ -9,6 +9,10 @@ public class EntryPointLinkFactory extends AbstractEntryPointLinkFactory {
return createEntryPointLink("/gwt/RaceBoard.html", parameters);
}
public static String createSimulatorLink(Map<String, String> parameters) {
return createEntryPointLink("/gwt/Simulator.html", parameters);
}
public static String createLeaderboardLink(Map<String, String> parameters) {
return createEntryPointLink("/gwt/Leaderboard.html", parameters);
}
@@ -17,6 +17,7 @@ import com.sap.sailing.domain.base.RemoteSailingServerReference;
import com.sap.sailing.domain.common.DataImportProgress;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.LeaderboardType;
import com.sap.sailing.domain.common.LegIdentifier;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.PassingInstruction;
@@ -144,10 +145,10 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
boolean getPolarResults(RegattaAndRaceIdentifier raceIdentifier);
SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime);
SimulatorResultsDTO getSimulatorResults(LegIdentifier legIdentifier);
CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map<String, Date> fromPerCompetitorIdAsString,
Map<String, Date> toPerCompetitorIdAsString, boolean extrapolate) throws NoWindException;
Map<String, Date> toPerCompetitorIdAsString, boolean extrapolate, LegIdentifier simulationLegIdentifier) throws NoWindException;
RaceTimesInfoDTO getRaceTimesInfo(RegattaAndRaceIdentifier raceIdentifier);
@@ -13,6 +13,7 @@ import com.sap.sailing.domain.base.RemoteSailingServerReference;
import com.sap.sailing.domain.common.DataImportProgress;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.LeaderboardType;
import com.sap.sailing.domain.common.LegIdentifier;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.common.PolarSheetGenerationResponse;
@@ -191,7 +192,7 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM
void getPolarResults(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<Boolean> callback);
void getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime, AsyncCallback<SimulatorResultsDTO> callback);
void getSimulatorResults(LegIdentifier legIdentifier, AsyncCallback<SimulatorResultsDTO> callback);
void setWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO wind, AsyncCallback<Void> callback);
@@ -336,7 +337,7 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM
* identified by <code>raceIdentifier</code> will be used, considering that race's delay.
*/
void getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map<String, Date> fromPerCompetitorIdAsString,
Map<String, Date> toPerCompetitorIdAsString, boolean extrapolate, AsyncCallback<CompactRaceMapDataDTO> callback);
Map<String, Date> toPerCompetitorIdAsString, boolean extrapolate, LegIdentifier simulationLegIdentifier, AsyncCallback<CompactRaceMapDataDTO> callback);
void getReplicaInfo(AsyncCallback<ReplicationStateDTO> callback);
@@ -19,6 +19,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String wind();
String windPanelLabel();
String refresh();
@Override
String remove();
String windSource();
String dampeningInterval();
@@ -53,6 +54,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String linkToColumn();
String unlink();
String leaderboardName();
@Override
String cancel();
String pleaseEnterAName();
String pleaseEnterABoatClass();
@@ -65,6 +67,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String renameLeaderboard();
String addColumnToLeaderboard();
String pleaseEnterNameForNewRaceColumn();
@Override
String ok();
String medalRace();
String renameRace();
@@ -81,6 +84,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String leaderboard();
String leaderboards();
String leaderboardSettings();
@Override
String settings();
String linkedRaces();
String selectAtLeastOneLegDetail();
@@ -154,6 +158,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String penaltyCircles();
String medalRaceIsNull();
String maneuverTypes();
@Override
String configuration();
String chooseChart();
String distanceTraveled();
@@ -166,12 +171,14 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String in();
String secondsUnit();
String metersUnit();
@Override
String close();
String compareCompetitors();
String description();
String sailNumber();
String country();
String no3LetterCodes();
@Override
String add();
String delete();
String showCharts();
@@ -944,6 +951,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String pathfinderHelpText();
String essStart();
String basicStart();
String leagueStart();
String configured();
String overwriteRacingProceduresConfiguration();
String overwriteRacingProceduresConfigurationHelpText();
@@ -1141,9 +1149,13 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String enterRaceName();
String enterCourseName();
String scoringSchemeHighPointFirstGetsTenOrEightDescription();
@Override
String serverError();
@Override
String remoteProcedureCall();
@Override
String serverReplies();
@Override
String errorCommunicatingWithServer();
String userManagement();
String structureImportUrls();
@@ -1191,10 +1203,15 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String sendingMailsSuccessful();
String selectEventForInvitation();
String imageURL();
@Override
String upload();
String removeResult(JSONValue status, JSONValue message);
@Override
String uploadSuccessful();
String fileUploadResult(JSONValue status, JSONValue message);
@Override
String fileUploadResult(String status, String message);
@Override
String removeUploadedImage();
String showCompetitorSailIdColumn();
String showCompetitorFullNameColumn();
String loadingDimensionValues();
@@ -924,6 +924,7 @@ activatePathfinder=Activate Pathfinder
pathfinderHelpText=When activated the Race Officer is able to set the Pathfinder boat.
essStart=ESS Start
basicStart=Basic Start
leagueStart=League Start
configured=Configured
overwriteRacingProceduresConfiguration=Activate regatta configuration
overwriteRacingProceduresConfigurationHelpText=Enabling this option will provide a base regatta configuration for all options unconfigured in the regatta-specific configuration.
@@ -1176,6 +1177,7 @@ upload=Upload
removeResult=Remove operation: {0} {1}
uploadSuccessful=Upload successful
fileUploadResult=File upload: {0} {1}.\nIn case of error please check that your File Storage service is properly configured.
removeUploadedImage=Remove uploaded image
showCompetitorSailIdColumn=Show Competitor Sail Id
showCompetitorFullNameColumn=Show Competitor Full Name
loadingDimensionValues=Loading dimension values
@@ -920,6 +920,7 @@ activatePathfinder=Aktiviere Pathfinder
pathfinderHelpText=Wenn aktiviert, ermöglicht dem Race Officer einen Pathfinder auszuwählen.
essStart=ESS Start
basicStart=Basic Start
leagueStart=Liga Start
configured=Konfiguriert
overwriteRacingProceduresConfiguration=Aktivere Regattakonfiguration
overwriteRacingProceduresConfigurationHelpText=Wenn aktiviert überschreibt jegliche Konfiguration der Rennarten durch eine Regatta.
@@ -1166,6 +1167,7 @@ upload=Hochladen
removeResult=Löschergebnis: {0} {1}
uploadSuccessful=Hochladen erfolgreich
fileUploadResult=Ergebnis des Hochladens: {0} {1}\nIm Fehlerfall bitte die Konfiguration für "Datei Speicherung" prüfen.
removeUploadedImage=Hochgeladenes Bild löschen
showCompetitorSailIdColumn=Sail Id anzeigen
showCompetitorFullNameColumn=Vollen Namen anzeigen
loadingDimensionValues=Lade Dimensionswerte
@@ -914,6 +914,7 @@ activatePathfinder=Активировать «Следопыт»
pathfinderHelpText=После активации официальное лицо гонки может настроить судно «Следопыт».
essStart=Старт ESS
basicStart=Основной старт
leagueStart=League Start
configured=Настроенный
overwriteRacingProceduresConfiguration=Активировать конфигурацию регаты
overwriteRacingProceduresConfigurationHelpText=Включение этой опции предоставляет базовую конфигурацию регаты для всех опций, не настроенных в специальной конфигурации регаты.
@@ -1115,6 +1116,7 @@ upload=Upload
removeResult=Remove operation: {0} {1}
uploadSuccessful=Upload successful
fileUploadResult=File upload: {0} {1}.\nIn case of error please check that your File Storage service is properly configured.
removeUploadedImage=Remove uploaded image
showCompetitorSailIdColumn=Show Competitor Sail Id
showCompetitorFullNameColumn=Show Competitor Full Name
loadingDimensionValues=Loading dimension values
@@ -308,6 +308,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
private Date lastTimeChangeBeforeInitialization;
private int lastLegNumber;
/**
* The last quick ranks received from a call to {@link SailingServiceAsync#getQuickRanks(RaceIdentifier, Date, AsyncCallback)} upon
* the last {@link #timeChanged(Date, Date)} event. Therefore, the ranks listed here correspond to the {@link #timer}'s time.
@@ -739,7 +741,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
// next, do the full thing; being the later call, if request throttling kicks in, the later call
// supersedes the earlier call which may get dropped then
GetRaceMapDataAction getRaceMapDataAction = new GetRaceMapDataAction(sailingService, competitorSelection.getAllCompetitors(), race,
useNullAsTimePoint() ? null : newTime, fromAndToAndOverlap.getA(), fromAndToAndOverlap.getB(), /* extrapolate */ true);
useNullAsTimePoint() ? null : newTime, fromAndToAndOverlap.getA(), fromAndToAndOverlap.getB(), /* extrapolate */ true, (settings.isShowSimulationOverlay() ? simulationOverlay.getLegIdentifier() : null));
asyncActionsExecutor.execute(getRaceMapDataAction, GET_RACE_MAP_DATA_CATEGORY,
getRaceMapDataCallback(oldTime, newTime, fromAndToAndOverlap.getC(), competitorsToShow, requestID));
@@ -820,7 +822,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
final GetRaceMapDataAction result;
if (!fromTimes.isEmpty()) {
result = new GetRaceMapDataAction(sailingService, competitorSelection.getAllCompetitors(),
race, useNullAsTimePoint() ? null : newTime, fromTimes, toTimes, /* extrapolate */true);
race, useNullAsTimePoint() ? null : newTime, fromTimes, toTimes, /* extrapolate */true, (settings.isShowSimulationOverlay() ? simulationOverlay.getLegIdentifier() : null));
} else {
result = null;
}
@@ -843,7 +845,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
if (map != null && raceMapDataDTO != null) {
quickRanks = raceMapDataDTO.quickRanks;
if (showViewSimulation && settings.isShowSimulationOverlay()) {
simulationOverlay.updateLeg(getCurrentLeg(), newTime, /* clearCanvas */ false);
lastLegNumber = raceMapDataDTO.coursePositions.currentLegNumber;
simulationOverlay.updateLeg(Math.max(lastLegNumber,1), /* clearCanvas */ false, raceMapDataDTO.simulationResultVersion);
}
// process response only if not received out of order
if (startedProcessingRequestID < requestID) {
@@ -2228,7 +2231,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
if (newSettings.isShowSimulationOverlay() != settings.isShowSimulationOverlay()) {
settings.setShowSimulationOverlay(newSettings.isShowSimulationOverlay());
simulationOverlay.setVisible(newSettings.isShowSimulationOverlay());
simulationOverlay.updateLeg(getCurrentLeg(), timer.getTime(), true);
if (newSettings.isShowSimulationOverlay()) {
simulationOverlay.updateLeg(Math.max(lastLegNumber,1), true, -1 /* ensure ui-update */);
}
}
if (newSettings.isWindUp() != settings.isWindUp()) {
settings.setWindUp(newSettings.isWindUp());
@@ -2437,16 +2442,6 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
return result;
}
public int getCurrentLeg() {
com.sap.sse.common.Util.Pair<Integer, CompetitorDTO> leaderWithLeg = this
.getLeadingVisibleCompetitorWithOneBasedLegNumber(getCompetitorsToShow());
if (leaderWithLeg == null) {
return 0;
} else {
return leaderWithLeg.getA();
}
}
private Image createSAPLogo() {
ImageResource sapLogoResource = resources.sapLogoOverlay();
Image sapLogo = new Image(sapLogoResource);
@@ -117,6 +117,7 @@ import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcher
import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherSingle;
import com.sap.sailing.domain.base.configuration.impl.ESSConfigurationImpl;
import com.sap.sailing.domain.base.configuration.impl.GateStartConfigurationImpl;
import com.sap.sailing.domain.base.configuration.impl.LeagueConfigurationImpl;
import com.sap.sailing.domain.base.configuration.impl.RRS26ConfigurationImpl;
import com.sap.sailing.domain.base.configuration.impl.RacingProcedureConfigurationImpl;
import com.sap.sailing.domain.base.configuration.impl.RegattaConfigurationImpl;
@@ -137,6 +138,7 @@ import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.LeaderboardNameConstants;
import com.sap.sailing.domain.common.LeaderboardType;
import com.sap.sailing.domain.common.LegIdentifier;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.MaxPointsReason;
@@ -221,6 +223,8 @@ import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
import com.sap.sailing.domain.persistence.MongoRegattaLogStoreFactory;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.racelog.RaceStateOfSameDayHelper;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
@@ -340,8 +344,6 @@ import com.sap.sailing.manage2sail.EventResultDescriptor;
import com.sap.sailing.manage2sail.Manage2SailEventResultsParserImpl;
import com.sap.sailing.manage2sail.RaceResultDescriptor;
import com.sap.sailing.manage2sail.RegattaResultDescriptor;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.resultimport.ResultUrlProvider;
import com.sap.sailing.resultimport.ResultUrlRegistry;
import com.sap.sailing.server.RacingEventService;
@@ -395,24 +397,20 @@ import com.sap.sailing.server.operationaltransformation.UpdateLeaderboardScoreCo
import com.sap.sailing.server.operationaltransformation.UpdateRaceDelayToLive;
import com.sap.sailing.server.operationaltransformation.UpdateSeries;
import com.sap.sailing.server.operationaltransformation.UpdateSpecificRegatta;
import com.sap.sailing.server.simulation.SimulationService;
import com.sap.sailing.simulator.Path;
import com.sap.sailing.simulator.PathType;
import com.sap.sailing.simulator.PolarDiagram;
import com.sap.sailing.simulator.SailingSimulator;
import com.sap.sailing.simulator.SimulationParameters;
import com.sap.sailing.simulator.SimulationResults;
import com.sap.sailing.simulator.TimedPositionWithSpeed;
import com.sap.sailing.simulator.impl.PolarDiagramGPS;
import com.sap.sailing.simulator.impl.SailingSimulatorImpl;
import com.sap.sailing.simulator.impl.SimulationParametersImpl;
import com.sap.sailing.simulator.util.SailingSimulatorConstants;
import com.sap.sailing.simulator.windfield.WindFieldGenerator;
import com.sap.sailing.simulator.windfield.impl.WindFieldTrackedRaceImpl;
import com.sap.sailing.simulator.impl.SparseSimulationDataException;
import com.sap.sailing.xrr.schema.RegattaResults;
import com.sap.sailing.xrr.structureimport.SeriesParameters;
import com.sap.sailing.xrr.structureimport.StructureImporter;
import com.sap.sailing.xrr.structureimport.buildstructure.SetRacenumberFromSeries;
import com.sap.sse.BuildVersion;
import com.sap.sse.common.CountryCode;
import com.sap.sse.common.Duration;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TimeRange;
@@ -421,7 +419,6 @@ import com.sap.sse.common.TypeBasedServiceFinderFactory;
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.impl.MillisecondsDurationImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.impl.TimeRangeImpl;
import com.sap.sse.common.mail.MailException;
@@ -1436,107 +1433,55 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
} else {
BoatClass boatClass = trackedRace.getRace().getBoatClass();
PolarDataService polarData = getService().getPolarDataService();
PolarDiagram polarDiagram = new PolarDiagramGPS(boatClass, polarData);
PolarDiagram polarDiagram;
try {
polarDiagram = new PolarDiagramGPS(boatClass, polarData);
} catch (SparseSimulationDataException e) {
polarDiagram = null;
// TODO: raise a UI message, to inform user about missing polar data resulting in unability to simulate
}
result = polarDiagram != null;
}
return result;
}
@Override
public SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime) {
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
public SimulatorResultsDTO getSimulatorResults(LegIdentifier legIdentifier) {
// get simulation-results from smart-future-cached simulation-service
SimulatorResultsDTO result = null;
if (trackedRace != null) {
TimePoint fromTimePoint = from == null ? new MillisecondsTimePoint(trackedRace.getStartOfRace().asMillis() + 10000) : new MillisecondsTimePoint(from);
// get previous mark or start line as start-position
TrackedLeg trackedLeg = trackedRace.getCurrentLeg(fromTimePoint);
if (trackedLeg == null) {
SimulationService simulationService = getService().getSimulationService();
if (simulationService == null)
return result;
SimulationResults simulationResults = simulationService.getSimulationResults(legIdentifier);
if (simulationResults == null)
return result;
}
Waypoint fromWaypoint = trackedLeg.getLeg().getFrom();
// get next mark as end-position
Waypoint toWaypoint = trackedLeg.getLeg().getTo();
TimePoint startTimePoint = null;
TimePoint endTimePoint = null;
Iterable<Util.Pair<Waypoint, Util.Pair<TimePoint, TimePoint>>> markPassings = trackedRace.getMarkPassingsTimes();
long legDuration = 0;
synchronized(markPassings) {
for(Pair<Waypoint, Pair<TimePoint, TimePoint>> markPassing : markPassings) {
if (markPassing.getA().equals(fromWaypoint)) {
startTimePoint = markPassing.getB().getA();
}
if (markPassing.getA().equals(toWaypoint)) {
endTimePoint = markPassing.getB().getA();
}
}
}
legDuration = endTimePoint.asMillis() - startTimePoint.asMillis();
Position startPosition = trackedRace.getApproximatePosition(fromWaypoint, startTimePoint);
Position endPosition = trackedRace.getApproximatePosition(toWaypoint, endTimePoint);
if (startTimePoint.asDate().equals(prevStartTime)) {
return new SimulatorResultsDTO(startTimePoint.asDate(), 0, 0, null, null, null, null);
}
// determine legtype upwind/downwind/reaching
LegType legType = null;
try {
legType = trackedLeg.getLegType(fromTimePoint);
} catch (NoWindException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// get windfield
WindFieldGenerator windField = new WindFieldTrackedRaceImpl(trackedRace);
Duration timeStep = new MillisecondsDurationImpl(15 * 1000);
windField.generate(startTimePoint, null, timeStep);
// prepare simulation-parameters
List<Position> course = new ArrayList<>();
course.add(startPosition);
course.add(endPosition);
BoatClass boatClass = trackedRace.getRace().getBoatClass();
PolarDataService polarData = getService().getPolarDataService();
PolarDiagram polarDiagram = new PolarDiagramGPS(boatClass, polarData);
SimulationParameters simulationPars = new SimulationParametersImpl(course, polarDiagram, windField, SailingSimulatorConstants.ModeEvent, true, true);
// for upwind/downwind, run simulation with start-time, start-position, end-position and windfield
SailingSimulator simulator = new SailingSimulatorImpl(simulationPars);
Map<String, Path> pathsAndNames = null;
if (legType != LegType.REACHING) {
pathsAndNames = simulator.getAllPathsEvenTimed(timeStep.asMillis(), null);
}
// prepare simulator-results-dto
if (pathsAndNames != null) {
int noOfPaths = pathsAndNames.size();
Map<PathType, Path> paths = simulationResults.getPaths();
if (paths != null) {
int noOfPaths = paths.size();
PathDTO[] pathDTOs = new PathDTO[noOfPaths];
int index = noOfPaths - 1;
for (Entry<String, Path> entry : pathsAndNames.entrySet()) {
pathDTOs[index] = new PathDTO(entry.getKey());
for (Entry<PathType, Path> entry : paths.entrySet()) {
pathDTOs[index] = new PathDTO(entry.getKey().getTxtId());
// fill pathDTO with path points where speed is true wind speed
List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>();
for (TimedPositionWithSpeed p : entry.getValue().getPathPoints()) {
wList.add(createSimulatorWindDTO(p));
}
pathDTOs[index].setPoints(wList);
pathDTOs[index].setAlgorithmTimedOut(entry.getValue().getAlgorithmTimedOut());
pathDTOs[index].setMixedLeg(entry.getValue().getMixedLeg());
index--;
}
RaceMapDataDTO rcDTO;
rcDTO = new RaceMapDataDTO();
rcDTO.coursePositions = new CoursePositionsDTO();
rcDTO.coursePositions.waypointPositions = new ArrayList<>();
rcDTO.coursePositions.waypointPositions.add(startPosition);
rcDTO.coursePositions.waypointPositions.add(endPosition);
result = new SimulatorResultsDTO(startTimePoint.asDate(), timeStep.asMillis(), legDuration, rcDTO, pathDTOs, null, null);
rcDTO.coursePositions.waypointPositions = new ArrayList<Position>();
rcDTO.coursePositions.waypointPositions.add(simulationResults.getStartPosition());
rcDTO.coursePositions.waypointPositions.add(simulationResults.getEndPosition());
result = new SimulatorResultsDTO(simulationResults.hashCode(), simulationResults.getStartTime(), simulationResults.getTimeStep(),
simulationResults.getLegDuration(), rcDTO, pathDTOs, null, null);
}
}
return result;
}
@@ -1612,13 +1557,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
@Override
public CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date,
Map<String, Date> fromPerCompetitorIdAsString, Map<String, Date> toPerCompetitorIdAsString,
boolean extrapolate) throws NoWindException {
boolean extrapolate, LegIdentifier simulationLegIdentifier) throws NoWindException {
final Map<CompetitorDTO, List<GPSFixDTO>> boatPositions = getBoatPositions(raceIdentifier,
fromPerCompetitorIdAsString, toPerCompetitorIdAsString, extrapolate);
final CoursePositionsDTO coursePositions = getCoursePositions(raceIdentifier, date);
final List<SidelineDTO> courseSidelines = getCourseSidelines(raceIdentifier, date);
final List<QuickRankDTO> quickRanks = getQuickRanks(raceIdentifier, date);
return new CompactRaceMapDataDTO(boatPositions, coursePositions, courseSidelines, quickRanks);
int simulationResultVersion = 0;
if (simulationLegIdentifier != null) {
SimulationService simulationService = getService().getSimulationService();
simulationResultVersion = simulationService.getSimulationResultsVersion(simulationLegIdentifier);
}
return new CompactRaceMapDataDTO(boatPositions, coursePositions, courseSidelines, quickRanks, simulationResultVersion);
}
/**
@@ -1897,6 +1847,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
} else {
dateAsTimePoint = new MillisecondsTimePoint(date);
}
result.totalLegsCount = trackedRace.getRace().getCourse().getLegs().size();
result.currentLegNumber = trackedRace.getLastLegStarted(dateAsTimePoint);
result.marks = new HashSet<MarkDTO>();
result.waypointPositions = new ArrayList<>();
Set<Mark> marks = new HashSet<Mark>();
@@ -4527,8 +4479,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
getService().apply(
new UpdateCompetitor(competitor.getIdAsString(), competitor.getName(), competitor
.getColor(), competitor.getEmail(), competitor.getSailID(), nationality,
competitor.getFlagImageURL() == null ? null : new URI(competitor.getFlagImageURL()),
competitor.getImageURL() == null ? null : new URI(competitor.getImageURL()))));
competitor.getImageURL() == null ? null : new URI(competitor.getImageURL()),
competitor.getFlagImageURL() == null ? null : new URI(competitor.getFlagImageURL()))));
}
return result;
}
@@ -4643,6 +4595,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
dto.basicConfiguration.classFlag = configuration.getBasicConfiguration().getClassFlag();
dto.basicConfiguration.hasInidividualRecall = configuration.getBasicConfiguration().hasInidividualRecall();
}
if (configuration.getLeagueConfiguration() != null) {
dto.leagueConfiguration = new DeviceConfigurationDTO.RegattaConfigurationDTO.LeagueConfigurationDTO();
dto.leagueConfiguration.classFlag = configuration.getLeagueConfiguration().getClassFlag();
dto.leagueConfiguration.hasInidividualRecall = configuration.getLeagueConfiguration().hasInidividualRecall();
}
return dto;
}
@@ -4688,6 +4645,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
config.setHasInidividualRecall(dto.basicConfiguration.hasInidividualRecall);
configuration.setBasicConfiguration(config);
}
if (dto.leagueConfiguration != null) {
LeagueConfigurationImpl config = new LeagueConfigurationImpl();
config.setClassFlag(dto.leagueConfiguration.classFlag);
config.setHasInidividualRecall(dto.leagueConfiguration.hasInidividualRecall);
configuration.setLeagueConfiguration(config);
}
return configuration;
}
@@ -9,6 +9,11 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
@@ -21,6 +26,7 @@ import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.dto.BoatClassDTO;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.impl.NauticalMileDistance;
import com.sap.sailing.gwt.ui.client.SimulatorService;
import com.sap.sailing.gwt.ui.shared.BoatClassDTOsAndNotificationMessage;
@@ -50,11 +56,14 @@ import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternDisplay;
import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternDisplayManager;
import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternNotFoundException;
import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternSetting;
import com.sap.sailing.server.simulation.SimulationService;
import com.sap.sailing.server.simulation.SimulationServiceFactory;
import com.sap.sailing.simulator.BoatClassProperties;
import com.sap.sailing.simulator.Grid;
import com.sap.sailing.simulator.Path;
import com.sap.sailing.simulator.PathType;
import com.sap.sailing.simulator.PolarDiagram;
import com.sap.sailing.simulator.SailingSimulator;
import com.sap.sailing.simulator.Simulator;
import com.sap.sailing.simulator.SimulationParameters;
import com.sap.sailing.simulator.TimedPosition;
import com.sap.sailing.simulator.TimedPositionWithSpeed;
@@ -64,7 +73,7 @@ import com.sap.sailing.simulator.impl.PathGenerator1Turner;
import com.sap.sailing.simulator.impl.PathImpl;
import com.sap.sailing.simulator.impl.PolarDiagramCSV;
import com.sap.sailing.simulator.impl.ReadingConfigurationFileStatus;
import com.sap.sailing.simulator.impl.SailingSimulatorImpl;
import com.sap.sailing.simulator.impl.SimulatorImpl;
import com.sap.sailing.simulator.impl.SimulationParametersImpl;
import com.sap.sailing.simulator.impl.TimedPositionImpl;
import com.sap.sailing.simulator.impl.TimedPositionWithSpeedImpl;
@@ -77,6 +86,7 @@ import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class SimulatorServiceImpl extends RemoteServiceServlet implements SimulatorService {
private static final long serialVersionUID = 4445427185387524086L;
@@ -89,11 +99,23 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
// private static final double TOTAL_TIME_SCALE_FACTOR = 0.9;
private static final int DEFAULT_STEP_MAX = 800;
private static final long DEFAULT_TIMESTEP = 6666;
private final SimulationService simulationService;
private double stepSizeMeters = 0.0;
private WindControlParameters controlParameters = new WindControlParameters(0, 0);
private SpeedWithBearing averageWind = null;
public SimulatorServiceImpl() {
final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3);
Executor simulatorExecutor = new ThreadPoolExecutor(/* corePoolSize */THREAD_POOL_SIZE,
/* maximumPoolSize */THREAD_POOL_SIZE,
/* keepAliveTime */60, TimeUnit.SECONDS,
/* workQueue */new LinkedBlockingQueue<Runnable>());
// TODO: initialize smart-future-cache for simulation-results and add to simulation-service
simulationService = SimulationServiceFactory.INSTANCE.getService(simulatorExecutor, null);
}
@Override
public Position[] getRaceLocations() {
Position lakeGarda = new DegreePosition(45.57055337226086, 10.693345069885254);
@@ -185,7 +207,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
throw new WindPatternNotFoundException("Please select a valid wind pattern.");
}
Position[][] grid = bd.generatePositions(params.getxRes(), params.getyRes(), params.getBorderY(), params.getBorderX());
Position[][] grid = bd.generatePositions(params.getxRes(), params.getyRes(), params.getBorderY(),
params.getBorderX());
wf.setPositionGrid(grid);
TimePoint startTime = new MillisecondsTimePoint(params.getStartTime().getTime());
@@ -224,9 +247,9 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
}
@Override
public SimulatorResultsDTO getSimulatorResults(char mode, char rcDirection, WindFieldGenParamsDTO params, WindPatternDisplay pattern, boolean withWindField,
SimulatorUISelectionDTO selection) throws WindPatternNotFoundException,
ConfigurationException {
public SimulatorResultsDTO getSimulatorResults(char mode, char rcDirection, WindFieldGenParamsDTO params,
WindPatternDisplay pattern, boolean withWindField, SimulatorUISelectionDTO selection)
throws WindPatternNotFoundException, ConfigurationException {
WindFieldGenerator wf = null;
List<Position> course = null;
TimePoint startTime = new MillisecondsTimePoint(params.getStartTime().getTime());
@@ -265,7 +288,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
wf.generate(startTime, null, timeStep);
Long longestPathTime = 0L;
SimulatedPathsEvenTimedResultDTO simulatedPaths = this.getSimulatedPathsEvenTimed(course, wf, mode, selection, params.showOmniscient, params.showOpportunist);
SimulatedPathsEvenTimedResultDTO simulatedPaths = this.getSimulatedPathsEvenTimed(course, wf, mode, selection,
params.showOmniscient, params.showOpportunist);
PathDTO[] pathDTOs = simulatedPaths.pathDTOs;
RaceMapDataDTO rcDTO = simulatedPaths.raceMapDataDTO;
@@ -283,10 +307,13 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
WindFieldDTO windFieldDTO = null;
if (pattern != null) {
windFieldDTO = this.createWindFieldDTO(wf, startTime, endTime, timeStep, params); // params.isShowStreamlets2(), params.isShowLines(), params.getSeedLines());
windFieldDTO = this.createWindFieldDTO(wf, startTime, endTime, timeStep, params); // params.isShowStreamlets2(),
// params.isShowLines(),
// params.getSeedLines());
}
return new SimulatorResultsDTO(null, timeStep.asMillis(), 0, rcDTO, pathDTOs, windFieldDTO, simulatedPaths.notificationMessage);
return new SimulatorResultsDTO(0, null, timeStep.asMillis(), 0, rcDTO, pathDTOs, windFieldDTO,
simulatedPaths.notificationMessage);
}
@Override
@@ -349,20 +376,23 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
@Override
public ResponseTotalTimeDTO getTotalTime(RequestTotalTimeDTO requestData) throws ConfigurationException {
this.averageWind = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils.getAverage(requestData.allPoints)
: SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
this.averageWind = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils
.getAverage(requestData.allPoints) : SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
this.stepSizeMeters = SimulatorServiceUtils.knotsToMetersPerSecond(this.averageWind.getKnots()) * (requestData.stepDurationMilliseconds / 1000.);
this.stepSizeMeters = SimulatorServiceUtils.knotsToMetersPerSecond(this.averageWind.getKnots())
* (requestData.stepDurationMilliseconds / 1000.);
// List<Position> points = SimulatorServiceUtils.getIntermediatePoints2(requestData.turnPoints,
// this.stepSizeMeters);
// int noOfPointsMinus1 = points.size() - 1;
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this.getPolarDiagram(requestData.selection.boatClassIndex);
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this
.getPolarDiagram(requestData.selection.boatClassIndex);
PolarDiagram polarDiagram = polarDiagramAndNotificationMessage.getA();
String notificationMessage = polarDiagramAndNotificationMessage.getB();
SailingSimulator simulator = new SailingSimulatorImpl(new SimulationParametersImpl(null, polarDiagram, null, SailingSimulatorConstants.ModeMeasured, true, true));
Simulator simulator = new SimulatorImpl(new SimulationParametersImpl(null, polarDiagram, null,
null, SailingSimulatorConstants.ModeMeasured, true, true));
Path gpsTrack = simulator.getLegGPSTrack(SimulatorServiceUtils.toSimulatorUISelection(requestData.selection));
// Position startPoint = null;
@@ -405,14 +435,12 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
//
// double totalTimeSeconds = (timepointAsMillis - courseStartPoint.timepoint) / 1000;
//
double totalTimeGPSTrackSeconds = (gpsTrack.getPathPoints().get(gpsTrack.getPathPoints().size() - 1).getTimePoint().asMillis() - gpsTrack
.getPathPoints().get(0).getTimePoint().asMillis()) / 1000;
double totalTimeGPSTrackSeconds = (gpsTrack.getPathPoints().get(gpsTrack.getPathPoints().size() - 1)
.getTimePoint().asMillis() - gpsTrack.getPathPoints().get(0).getTimePoint().asMillis()) / 1000;
//while (totalTimeSeconds > totalTimeGPSTrackSeconds) {
// while (totalTimeSeconds > totalTimeGPSTrackSeconds) {
// totalTimeSeconds *= TOTAL_TIME_SCALE_FACTOR;
//}
// }
long startTimePoint = requestData.allPoints.get(0).timepoint;
long segmentTime = 0;
@@ -425,8 +453,9 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
totalTime += segmentTime;
segmentTime = getTimeMillisecondsBetween(requestData.turnPoints.get(index), requestData.turnPoints.get(index + 1), this.stepSizeMeters,
requestData.useRealAverageWindSpeed, gpsTrack, polarDiagram, startTimePoint + totalTime);
segmentTime = getTimeMillisecondsBetween(requestData.turnPoints.get(index),
requestData.turnPoints.get(index + 1), this.stepSizeMeters, requestData.useRealAverageWindSpeed,
gpsTrack, polarDiagram, startTimePoint + totalTime);
System.out.println("Total time of segment " + segmentIndex + " = " + segmentTime + " milliseconds");
}
@@ -437,25 +466,30 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
System.out.println("TotalTimeGPS: " + totalTimeGPSTrackSeconds + " TotalTimePoly: " + totalTimeSeconds);
return new ResponseTotalTimeDTO(totalTimeSeconds, totalTimeSeconds/totalTimeGPSTrackSeconds, notificationMessage);
return new ResponseTotalTimeDTO(totalTimeSeconds, totalTimeSeconds / totalTimeGPSTrackSeconds,
notificationMessage);
}
//@Override
// @Override
public ResponseTotalTimeDTO getTotalTimeOld(RequestTotalTimeDTO requestData) throws ConfigurationException {
this.averageWind = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils.getAverage(requestData.allPoints)
: SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
this.averageWind = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils
.getAverage(requestData.allPoints) : SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
this.stepSizeMeters = SimulatorServiceUtils.knotsToMetersPerSecond(this.averageWind.getKnots()) * (requestData.stepDurationMilliseconds / 1000.);
this.stepSizeMeters = SimulatorServiceUtils.knotsToMetersPerSecond(this.averageWind.getKnots())
* (requestData.stepDurationMilliseconds / 1000.);
List<Position> points = SimulatorServiceUtils.getIntermediatePoints2(requestData.turnPoints, this.stepSizeMeters);
List<Position> points = SimulatorServiceUtils.getIntermediatePoints2(requestData.turnPoints,
this.stepSizeMeters);
int noOfPointsMinus1 = points.size() - 1;
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this.getPolarDiagram(requestData.selection.boatClassIndex);
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this
.getPolarDiagram(requestData.selection.boatClassIndex);
PolarDiagram polarDiagram = polarDiagramAndNotificationMessage.getA();
String notificationMessage = polarDiagramAndNotificationMessage.getB();
SailingSimulator simulator = new SailingSimulatorImpl(new SimulationParametersImpl(null, polarDiagram, null, SailingSimulatorConstants.ModeMeasured, true, true));
Simulator simulator = new SimulatorImpl(new SimulationParametersImpl(null, polarDiagram, null,
null, SailingSimulatorConstants.ModeMeasured, true, true));
Path gpsTrack = simulator.getLegGPSTrack(SimulatorServiceUtils.toSimulatorUISelection(requestData.selection));
Position startPoint = null;
@@ -476,17 +510,18 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
endPoint = points.get(index + 1);
distanceMeters = startPoint.getDistance(endPoint).getMeters();
windAtTimePoint = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils.getWindAtTimepoint(timepointAsMillis, gpsTrack)
: SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
windAtTimePoint = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils.getWindAtTimepoint(
timepointAsMillis, gpsTrack) : SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
boatBearingDeg = SimulatorServiceUtils.getInitialBearing(startPoint, endPoint);
polarDiagram.setWind(windAtTimePoint);
boatSpeedMetersPerSecond = polarDiagram.getSpeedAtBearing(new DegreeBearingImpl(boatBearingDeg)).getMetersPerSecond();
boatSpeedMetersPerSecond = polarDiagram.getSpeedAtBearing(new DegreeBearingImpl(boatBearingDeg))
.getMetersPerSecond();
stepTimeMilliseconds = (long) ((distanceMeters / boatSpeedMetersPerSecond) * 1000);
//problem right here
//boatSpeed might be 0 for very small distances
//this is a rough fix
if(boatSpeedMetersPerSecond == 0.0) {
// problem right here
// boatSpeed might be 0 for very small distances
// this is a rough fix
if (boatSpeedMetersPerSecond == 0.0) {
stepTimeMilliseconds = 1000;
}
@@ -496,23 +531,23 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
double totalTimeSeconds = (timepointAsMillis - requestData.allPoints.get(0).timepoint) / 1000;
double totalTimeGPSTrackSeconds = (gpsTrack.getPathPoints().get(gpsTrack.getPathPoints().size() - 1).getTimePoint().asMillis() - gpsTrack
.getPathPoints().get(0).getTimePoint().asMillis()) / 1000;
double totalTimeGPSTrackSeconds = (gpsTrack.getPathPoints().get(gpsTrack.getPathPoints().size() - 1)
.getTimePoint().asMillis() - gpsTrack.getPathPoints().get(0).getTimePoint().asMillis()) / 1000;
//while (totalTimeSeconds > totalTimeGPSTrackSeconds) {
// while (totalTimeSeconds > totalTimeGPSTrackSeconds) {
// totalTimeSeconds *= TOTAL_TIME_SCALE_FACTOR;
//}
System.out.println("TotalTimeGPS: "+totalTimeGPSTrackSeconds+" TotalTimePoly: "+totalTimeSeconds);
// }
System.out.println("TotalTimeGPS: " + totalTimeGPSTrackSeconds + " TotalTimePoly: " + totalTimeSeconds);
return new ResponseTotalTimeDTO((long) totalTimeSeconds, (double)totalTimeSeconds/(double)totalTimeGPSTrackSeconds, notificationMessage);
return new ResponseTotalTimeDTO((long) totalTimeSeconds, (double) totalTimeSeconds
/ (double) totalTimeGPSTrackSeconds, notificationMessage);
}
@Override
public Response1TurnerDTO get1Turner(Request1TurnerDTO requestData) throws ConfigurationException {
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this.getPolarDiagram(requestData.selection.boatClassIndex);
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this
.getPolarDiagram(requestData.selection.boatClassIndex);
PolarDiagram polarDiagram = polarDiagramAndNotificationMessage.getA();
String notificationMessage = polarDiagramAndNotificationMessage.getB();
@@ -522,16 +557,19 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
Position oldMovedPosition = requestData.oldMovedPoint;
Position newMovedPosition = requestData.newMovedPoint;
Bearing oldMovedToNewMovedBearing = oldMovedPosition.getBearingGreatCircle(newMovedPosition);
boolean areTowardsSameDirection = SimulatorServiceUtils.areTowardsSameDirection(oldMovedToNewMovedBearing, new DegreeBearingImpl(
requestData.startToEndBearingDegrees));
boolean areTowardsSameDirection = SimulatorServiceUtils.areTowardsSameDirection(oldMovedToNewMovedBearing,
new DegreeBearingImpl(requestData.startToEndBearingDegrees));
System.out.println("oldMovedToNewMovedBearing = " + oldMovedToNewMovedBearing.getDegrees() + " degrees");
System.out.println("requestData.startToEndBearingDegrees = " + requestData.startToEndBearingDegrees + " degrees");
System.out.println("requestData.startToEndBearingDegrees = " + requestData.startToEndBearingDegrees
+ " degrees");
System.out.println("areTowardsSameDirection = " + areTowardsSameDirection);
SimulationParameters simulationParameters = new SimulationParametersImpl(null, polarDiagram, null, SailingSimulatorConstants.ModeMeasured, true, true);
SailingSimulator sailingSimulator = new SailingSimulatorImpl(simulationParameters);
Path gpsWind = sailingSimulator.getLegGPSTrack(SimulatorServiceUtils.toSimulatorUISelection(requestData.selection));
SimulationParameters simulationParameters = new SimulationParametersImpl(null, polarDiagram, null, null,
SailingSimulatorConstants.ModeMeasured, true, true);
Simulator sailingSimulator = new SimulatorImpl(simulationParameters);
Path gpsWind = sailingSimulator.getLegGPSTrack(SimulatorServiceUtils
.toSimulatorUISelection(requestData.selection));
Grid grid = new CurvedGrid(oldMovedPosition, newMovedPosition);
this.controlParameters.baseWindBearing += grid.getSouth().getDegrees();
@@ -548,8 +586,10 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
Position realStart = areTowardsSameDirection ? oldMovedPosition : newMovedPosition;
Position realEnd = areTowardsSameDirection ? newMovedPosition : oldMovedPosition;
leftSide1Turner = pathGenerator.get1Turner(windFieldGenerator, polarDiagram, realStart, realEnd, startTime, true, DEFAULT_STEP_MAX, DEFAULT_TIMESTEP);
rightSide1Turner = pathGenerator.get1Turner(windFieldGenerator, polarDiagram, realStart, realEnd, startTime, false, DEFAULT_STEP_MAX, DEFAULT_TIMESTEP);
leftSide1Turner = pathGenerator.get1Turner(windFieldGenerator, polarDiagram, realStart, realEnd, startTime,
true, DEFAULT_STEP_MAX, DEFAULT_TIMESTEP);
rightSide1Turner = pathGenerator.get1Turner(windFieldGenerator, polarDiagram, realStart, realEnd, startTime,
false, DEFAULT_STEP_MAX, DEFAULT_TIMESTEP);
boolean isLeftSide1TurnerOnTheInside = SimulatorServiceUtils.isPointInsideTriangle(leftSide1Turner.getPosition(),
requestData.beforeMovedPoint,
@@ -579,8 +619,7 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
} else if (SimulatorServiceUtils.equals(rightSide1Turner.getPosition(), newMovedPosition, 0.0001)) {
System.out.println("voi folosi endPosition = rightSide1Turner!");
correct1Turner = rightSide1Turner;
}
else {
} else {
System.out.println("nu ar trebui sa ajunga aici NICIODATA!");
}
}
@@ -588,11 +627,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
long timeStepMilliseconds = 2000;
double minimumDistanceMeters = 4.0;
List<TimedPositionWithSpeed> path = pathGenerator.getIntersectionOptimalTowardWind(windFieldGenerator, polarDiagram, edgeStart, edgeEnd,
correct1Turner,
true,
timeStepMilliseconds, minimumDistanceMeters);
List<TimedPositionWithSpeed> path = pathGenerator.getIntersectionOptimalTowardWind(windFieldGenerator,
polarDiagram, edgeStart, edgeEnd, correct1Turner, true, timeStepMilliseconds, minimumDistanceMeters);
return new Response1TurnerDTO(SimulatorServiceUtils.toSimulatorWindDTOList(path), SimulatorServiceUtils.toSimulatorWindDTO(leftSide1Turner),
SimulatorServiceUtils.toSimulatorWindDTO(rightSide1Turner), oldMovedPosition,
@@ -607,7 +643,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
selectedRaceIndex = 0;
}
SailingSimulator simulator = new SailingSimulatorImpl(new SimulationParametersImpl(null, null, null, SailingSimulatorConstants.ModeMeasured, true, true));
Simulator simulator = new SimulatorImpl(new SimulationParametersImpl(null, null, null, null,
SailingSimulatorConstants.ModeMeasured, true, true));
return simulator.getLegsNames(selectedRaceIndex);
}
@@ -615,7 +652,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
@Override
public List<String> getRacesNames() {
SailingSimulator simulator = new SailingSimulatorImpl(new SimulationParametersImpl(null, null, null, SailingSimulatorConstants.ModeMeasured, true, true));
Simulator simulator = new SimulatorImpl(new SimulationParametersImpl(null, null, null, null,
SailingSimulatorConstants.ModeMeasured, true, true));
return simulator.getRacesNames();
}
@@ -627,9 +665,10 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
selectedRaceIndex = 0;
}
SailingSimulator simulator = new SailingSimulatorImpl(new SimulationParametersImpl(null, null, null, SailingSimulatorConstants.ModeMeasured,true, true));
Simulator simulator = new SimulatorImpl(new SimulationParametersImpl(null, null, null, null,
SailingSimulatorConstants.ModeMeasured, true, true));
return simulator.getComeptitorsNames(selectedRaceIndex);
return simulator.getCompetitorsNames(selectedRaceIndex);
}
private void retreiveWindControlParameters(WindPatternDisplay pattern) {
@@ -779,9 +818,9 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
}
}
}
//TODO: throws null pointer exception for when reading serialized paths.
//TODO: should windlines also be serialized?
//logger.info("Added : " + windFieldDTO.getWindLinesDTO().getWindLinesMap().size() + " wind lines");
// TODO: throws null pointer exception for when reading serialized paths.
// TODO: should windlines also be serialized?
// logger.info("Added : " + windFieldDTO.getWindLinesDTO().getWindLinesMap().size() + " wind lines");
}
private void getWindLinesFromEndLine(WindFieldGenerator wf, WindFieldDTO windFieldDTO, TimePoint startTime,
@@ -850,22 +889,49 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
}
}
private SimulatedPathsEvenTimedResultDTO getSimulatedPathsEvenTimed(List<Position> course, WindFieldGenerator wf, char mode,
SimulatorUISelectionDTO selection, boolean showOmniscient, boolean showOpportunist) throws ConfigurationException {
private SimulatedPathsEvenTimedResultDTO getSimulatedPathsEvenTimed(List<Position> course, WindFieldGenerator wf,
char mode, SimulatorUISelectionDTO selection, boolean showOmniscient, boolean showOpportunist)
throws ConfigurationException {
LOGGER.info("Retrieving simulated paths");
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this.getPolarDiagram(selection.boatClassIndex);
PolarDiagram pd = polarDiagramAndNotificationMessage.getA();
SimulationParameters sp = new SimulationParametersImpl(course, pd, wf, mode, showOmniscient, showOpportunist);
SailingSimulator simulator = new SailingSimulatorImpl(sp);
Map<String, Path> pathsAndNames = null;
pathsAndNames = simulator.getAllPathsEvenTimed(wf.getTimeStep().asMillis(),
(mode == SailingSimulatorConstants.ModeMeasured) ? SimulatorServiceUtils.toSimulatorUISelection(selection) : null);
int[] gridRes = wf.getGridResolution();
Position[] gridArea = wf.getGridAreaGps();
LOGGER.info("showOmniscient : "+showOmniscient);
LOGGER.info("showOpportunist: "+showOpportunist);
if (gridArea != null) {
// initialize grid of supporting location for windfield
Grid bd = new CurvedGrid(gridArea[0], gridArea[1]);
// set base wind bearing
wf.getWindParameters().baseWindBearing += bd.getSouth().getDegrees();
LOGGER.info("base wind: " + pd.getWind().getKnots() + " kn, "
+ ((wf.getWindParameters().baseWindBearing) % 360.0) + "\u00B0");
// set water current
SpeedWithBearing current = new KnotSpeedWithBearingImpl(wf.getWindParameters().curSpeed, new DegreeBearingImpl(wf.getWindParameters().curBearing));
if (wf.getWindParameters().curSpeed > 0) {
pd.initializeSOGwithCurrent(); // polar-diagram is extended with data to support water currents
}
pd.setCurrent(current);
if (pd.getCurrent() != null) {
LOGGER.info("water current: " + pd.getCurrent().getKnots() + " kn, "
+ pd.getCurrent().getBearing().getDegrees() + "\u00B0");
}
wf.setBoundary(bd);
Position[][] positionGrid = bd.generatePositions(gridRes[0], gridRes[1], gridRes[2], gridRes[3]);
wf.setPositionGrid(positionGrid);
wf.generate(wf.getStartTime(), wf.getEndTime(), wf.getTimeStep());
}
SimulationParameters sp = new SimulationParametersImpl(course, pd, wf, null, mode, showOmniscient, showOpportunist);
Map<PathType, Path> pathsAndNames = null;
try {
pathsAndNames = simulationService.getAllPathsEvenTimed(sp, wf.getTimeStep().asMillis());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int noOfPaths = pathsAndNames.size();
if (mode == SailingSimulatorConstants.ModeMeasured) {
noOfPaths++; // the last path is the polyline
@@ -878,20 +944,21 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
pathDTOs[0] = this.getPolylinePathDTO(pathsAndNames.get("6#GPS Poly"), pathsAndNames.get("7#GPS Track"));
}
for (Entry<String, Path> entry : pathsAndNames.entrySet()) {
LOGGER.info("Path " + entry.getKey());
for (Entry<PathType, Path> entry : pathsAndNames.entrySet()) {
LOGGER.info("Path " + entry.getKey().getTxtId());
// NOTE: pathName convention is: sort-digit + "#" + path-name
// pathsAndNames is TreeMap which ensures sorting
pathDTOs[index] = new PathDTO(entry.getKey());
pathDTOs[index] = new PathDTO(entry.getKey().getTxtId());
// fill pathDTO with path points where speed is true wind speed
List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>();
for (TimedPositionWithSpeed p : entry.getValue().getPathPoints()) {
wList.add(createSimulatorWindDTO(p));
}
pathDTOs[index].setPoints(wList);
pathDTOs[index].setAlgorithmTimedOut(entry.getValue().getAlgorithmTimedOut());
pathDTOs[index].setMixedLeg(entry.getValue().getMixedLeg());
index--;
}
@@ -901,9 +968,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
rcDTO = new RaceMapDataDTO();
rcDTO.coursePositions = new CoursePositionsDTO();
rcDTO.coursePositions.waypointPositions = new ArrayList<>();
Path rc = simulator.getRaceCourse();
rcDTO.coursePositions.waypointPositions.add(rc.getPathPoints().get(0).getPosition());
rcDTO.coursePositions.waypointPositions.add(rc.getPathPoints().get(1).getPosition());
rcDTO.coursePositions.waypointPositions.add(course.get(0));
rcDTO.coursePositions.waypointPositions.add(course.get(1));
} else {
rcDTO = null;
}
@@ -963,7 +1029,7 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
List<TimedPositionWithSpeed> polylinePoints = gpsTrackPoints.subList(startPointIndex, endPointIndex + 1);
List<TimedPositionWithSpeed> turns = (new PathImpl(polylinePoints, null)).getTurns();
List<TimedPositionWithSpeed> turns = (new PathImpl(polylinePoints, null, false /* algorithmTimedOut */, false /* mixedLeg */)).getTurns();
// PathImpl.saveToGpxFile(new PathImpl(turns, null), "C:\\gps_path_turns_20deg_not_even_timed.gpx");
List<SimulatorWindDTO> points = new ArrayList<SimulatorWindDTO>();
@@ -977,8 +1043,10 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
isTurn = false;
for (TimedPositionWithSpeed turn : turns) {
if (turn.getPosition().getLatDeg() == point.getPosition().getLatDeg() && turn.getPosition().getLngDeg() == point.getPosition().getLngDeg()
&& turn.getTimePoint().asMillis() == point.getTimePoint().asMillis() && turn.getSpeed().getKnots() == point.getSpeed().getKnots()
if (turn.getPosition().getLatDeg() == point.getPosition().getLatDeg()
&& turn.getPosition().getLngDeg() == point.getPosition().getLngDeg()
&& turn.getTimePoint().asMillis() == point.getTimePoint().asMillis()
&& turn.getSpeed().getKnots() == point.getSpeed().getKnots()
&& turn.getSpeed().getBearing().getDegrees() == point.getSpeed().getBearing().getDegrees()) {
isTurn = true;
break;
@@ -989,12 +1057,12 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
position = point.getPosition();
points.add(new SimulatorWindDTO(position.getLatDeg(), position.getLngDeg(), speedWithBearing.getKnots(),
speedWithBearing.getBearing()
.getDegrees(), point.getTimePoint().asMillis(), isTurn));
speedWithBearing.getBearing().getDegrees(), point.getTimePoint().asMillis(), isTurn));
}
PathDTO result = new PathDTO(POLYLINE_PATH_NAME);
result.setPoints(points);
result.setAlgorithmTimedOut(false);
return result;
}
@@ -1081,17 +1149,18 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
endPoint = points.get(index + 1);
distanceMeters = startPoint.getDistance(endPoint).getMeters();
windAtTimePoint = useRealAverageWindSpeed ? SimulatorServiceUtils.getWindAtTimepoint(timepointAsMillis, gpsTrack)
: SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
windAtTimePoint = useRealAverageWindSpeed ? SimulatorServiceUtils.getWindAtTimepoint(timepointAsMillis,
gpsTrack) : SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
boatBearingDeg = SimulatorServiceUtils.getInitialBearing(startPoint, endPoint);
polarDiagram.setWind(windAtTimePoint);
boatSpeedMetersPerSecond = polarDiagram.getSpeedAtBearing(new DegreeBearingImpl(boatBearingDeg)).getMetersPerSecond();
boatSpeedMetersPerSecond = polarDiagram.getSpeedAtBearing(new DegreeBearingImpl(boatBearingDeg))
.getMetersPerSecond();
stepTimeMilliseconds = (long) ((distanceMeters / boatSpeedMetersPerSecond) * 1000);
// problem right here: boatSpeed might be 0 for very small distances
// this is a rough fix
if(boatSpeedMetersPerSecond == 0.0) {
if (boatSpeedMetersPerSecond == 0.0) {
stepTimeMilliseconds = 1000;
}
@@ -25,11 +25,12 @@ public class CompactRaceMapDataDTO implements IsSerializable {
private CoursePositionsDTO coursePositions;
private List<SidelineDTO> courseSidelines;
private List<CompactQuickRankDTO> quickRanks;
private int simulationResultVersion;
CompactRaceMapDataDTO() {}
public CompactRaceMapDataDTO(Map<CompetitorDTO, List<GPSFixDTO>> boatPositions, CoursePositionsDTO coursePositions,
List<SidelineDTO> courseSidelines, List<QuickRankDTO> quickRanks) {
List<SidelineDTO> courseSidelines, List<QuickRankDTO> quickRanks, int simulationResultVersion) {
this.boatPositionsByCompetitorIdAsString = new HashMap<String, List<GPSFixDTO>>();
for (Map.Entry<CompetitorDTO, List<GPSFixDTO>> e : boatPositions.entrySet()) {
this.boatPositionsByCompetitorIdAsString.put(e.getKey().getIdAsString(), e.getValue());
@@ -43,6 +44,7 @@ public class CompactRaceMapDataDTO implements IsSerializable {
}
this.courseSidelines = courseSidelines;
this.coursePositions = coursePositions;
this.simulationResultVersion = simulationResultVersion;
}
public RaceMapDataDTO getRaceMapDataDTO(Iterable<CompetitorDTO> competitors) {
@@ -68,6 +70,7 @@ public class CompactRaceMapDataDTO implements IsSerializable {
result.boatPositions.put(competitor, e.getValue());
}
}
result.simulationResultVersion = simulationResultVersion;
return result;
}
}
@@ -13,6 +13,9 @@ public class CoursePositionsDTO implements IsSerializable {
public List<Position> finishMarkPositions;
public Set<MarkDTO> marks;
public int totalLegsCount;
public int currentLegNumber;
/**
* <code>null</code> if the start waypoint does not have exactly two marks with valid positions; in this case,
* {@link #startLineAdvantageousSide}, {@link #startLineAdvantageInMeters} and {@link #startLineLengthInMeters} are
@@ -23,6 +23,10 @@ public class DeviceConfigurationDTO implements IsSerializable {
}
public static class LeagueConfigurationDTO extends RacingProcedureConfigurationDTO {
}
public static class RacingProcedureConfigurationDTO implements IsSerializable {
public Flags classFlag;
public Boolean hasInidividualRecall;
@@ -34,6 +38,7 @@ public class DeviceConfigurationDTO implements IsSerializable {
public GateStartConfigurationDTO gateStartConfiguration;
public ESSConfigurationDTO essConfiguration;
public RacingProcedureConfigurationDTO basicConfiguration;
public LeagueConfigurationDTO leagueConfiguration;
}
public List<String> allowedCourseAreaNames;
@@ -7,9 +7,10 @@ import com.sap.sailing.domain.common.dto.NamedDTO;
public class PathDTO extends NamedDTO {
private static final long serialVersionUID = 2381814072763342186L;
private List<SimulatorWindDTO> points;
private boolean algorithmTimedOut;
private boolean mixedLeg;
public PathDTO() {
}
public PathDTO(final String name) {
@@ -32,4 +33,20 @@ public class PathDTO extends NamedDTO {
return points.get(points.size() - 1).timepoint - points.get(0).timepoint;
}
public boolean getAlgorithmTimedOut() {
return this.algorithmTimedOut;
}
public void setAlgorithmTimedOut(boolean algorithmTimedOut) {
this.algorithmTimedOut = algorithmTimedOut;
}
public boolean getMixedLeg() {
return this.mixedLeg;
}
public void setMixedLeg(boolean mixedLeg) {
this.mixedLeg = mixedLeg;
}
}
@@ -12,4 +12,5 @@ public class RaceMapDataDTO implements IsSerializable {
public CoursePositionsDTO coursePositions;
public List<SidelineDTO> courseSidelines;
public LinkedHashMap<CompetitorDTO, QuickRankDTO> quickRanks;
public int simulationResultVersion;
}
@@ -6,6 +6,7 @@ import com.google.gwt.user.client.rpc.IsSerializable;
public class SimulatorResultsDTO implements IsSerializable {
private int version;
private Date startTime;
private long timeStep;
private long legDuration;
@@ -15,6 +16,7 @@ public class SimulatorResultsDTO implements IsSerializable {
private String notificationMessage;
public SimulatorResultsDTO(){
this.version = 0;
this.startTime = null;
this.timeStep = 0;
this.legDuration = 0;
@@ -24,7 +26,8 @@ public class SimulatorResultsDTO implements IsSerializable {
this.notificationMessage = "";
}
public SimulatorResultsDTO(final Date startTime, final long timeStep, final long legDuration, final RaceMapDataDTO raceCourse, final PathDTO[] paths, final WindFieldDTO windField, final String notificationMessage) {
public SimulatorResultsDTO(final int version, final Date startTime, final long timeStep, final long legDuration, final RaceMapDataDTO raceCourse, final PathDTO[] paths, final WindFieldDTO windField, final String notificationMessage) {
this.version = version;
this.startTime = startTime;
this.timeStep = timeStep;
this.legDuration = legDuration;
@@ -34,6 +37,14 @@ public class SimulatorResultsDTO implements IsSerializable {
this.notificationMessage = notificationMessage;
}
public int getVersion() {
return this.version;
}
public void setVersion(int version) {
this.version = version;
}
public Date getStartTime() {
return this.startTime;
}
@@ -14,6 +14,8 @@ import com.google.gwt.maps.client.base.Point;
import com.google.gwt.maps.client.controls.ControlPosition;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.LegIdentifier;
import com.sap.sailing.domain.common.LegIdentifierImpl;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.gwt.ui.actions.GetSimulationAction;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
@@ -40,6 +42,8 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
public static final String GET_SIMULATION_CATEGORY = "getSimulation";
private final String textColor = "Black";
private final String textFont = "10pt OpenSansRegular";
private String algorithmTimedOutText = "out-of-bounds";
private String mixedLegText = "ambiguous wind";
private int xOffset = 0;
private int yOffset = 0; //150;
private double rectWidth = 20;
@@ -52,7 +56,6 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
private SimulatorResultsDTO simulationResult;
private PathDTO racePath;
private int raceLeg = 0;
private Date prevStartTime;
private Canvas simulationLegend;
public RaceSimulationOverlay(MapWidget map, int zIndex, RegattaAndRaceIdentifier raceIdentifier, SailingServiceAsync sailingService, StringMessages stringMessages, AsyncActionsExecutor asyncActionsExecutor, CoordinateSystem coordinateSystem) {
@@ -64,13 +67,25 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
this.colors = new ColorPaletteGenerator();
}
public void updateLeg(int newLeg, Date newTime, boolean clearCanvas) {
if ((newLeg != raceLeg) && (this.isVisible())) {
public void updateLeg(int newLeg, boolean clearCanvas, int newVersion) {
if (((newLeg != raceLeg)||((newLeg == raceLeg)&&(newVersion != (simulationResult==null ? 0 : simulationResult.getVersion())))) && (this.isVisible())) {
raceLeg = newLeg;
if (clearCanvas) {
this.clearCanvas();
}
this.simulate(newTime);
this.simulate(newLeg);
}
}
public LegIdentifier getLegIdentifier() {
return new LegIdentifierImpl(raceIdentifier, String.valueOf(raceLeg));
}
public int getVersion() {
if (this.simulationResult == null) {
return 0;
} else {
return this.simulationResult.getVersion();
}
}
@@ -146,8 +161,12 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
Context2d ctxt = canvas.getContext2d();
PathDTO[] paths = simulationResult.getPaths();
boolean first = true;
int colorIdx = paths.length - 1;
int colorIdx = paths.length;
for (PathDTO path : paths) {
colorIdx--;
if (path.getMixedLeg()) {
continue;
}
List<SimulatorWindDTO> points = path.getPoints();
ctxt.setLineWidth(3.0);
ctxt.setGlobalAlpha(0.7);
@@ -175,7 +194,6 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
ctxt.closePath();
ctxt.stroke();
}
colorIdx--;
}
}
@@ -190,22 +208,57 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
txtmet = context2d.measureText("00:00:00");
double timewidth = txtmet.getWidth();
double txtmaxwidth = 0.0;
if (racePath != null) {
txtmet = context2d.measureText(racePath.getName().split("#")[1]);
txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth());
}
boolean containsTimeOut = false;
boolean containsMixedLeg = false;
PathDTO[] paths = this.simulationResult.getPaths();
for (PathDTO path : paths) {
txtmet = context2d.measureText(path.getName());
if (path.getAlgorithmTimedOut()) {
containsTimeOut = true;
}
if (path.getMixedLeg()) {
containsMixedLeg = true;
}
txtmet = context2d.measureText(path.getName().split("#")[1]);
txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth());
}
double newwidth = 0;
double deltaTime = 0;
double deltaMixedLeg = 0;
double deltaTimeOut = 0;
double mixedLegWidth = 0;
if (containsMixedLeg) {
txtmet = context2d.measureText(mixedLegText);
mixedLegWidth = txtmet.getWidth();
newwidth = Math.max(timewidth, mixedLegWidth);
}
double timeOutWidth = 0;
if (containsTimeOut) {
txtmet = context2d.measureText(algorithmTimedOutText);
timeOutWidth = txtmet.getWidth();
newwidth = Math.max(newwidth, timeOutWidth);
}
if (containsMixedLeg||containsTimeOut) {
deltaTime = newwidth - timewidth;
deltaMixedLeg = newwidth - mixedLegWidth;
deltaTimeOut = newwidth - timeOutWidth;
timewidth = newwidth;
}
//canvas.setSize(xOffset + rectWidth + txtmaxwidth + timewidth + 10.0+"px", rectHeight*(paths.length+1)+"px");
int canvasWidth = (int)Math.ceil(xOffset + rectWidth + txtmaxwidth + timewidth + 10.0 + 5.0);
int canvasHeight = (int)Math.ceil(yOffset + rectHeight*(paths.length+1));
int canvasWidth = (int)Math.ceil(xOffset + rectWidth + txtmaxwidth + timewidth + 10.0 + 10.0);
int canvasHeight = (int)Math.ceil(yOffset + rectHeight*(paths.length + (racePath == null? 0 : 1)));
setCanvasSize(canvas, canvasWidth, canvasHeight);
drawRectangleWithText(context2d, xOffset, yOffset, "rgba(255,255,255,0.8);",
racePath.getName().split("#")[1], getFormattedTime(racePath.getPathTime()), txtmaxwidth, timewidth);
if (racePath != null) {
drawRectangleWithText(context2d, xOffset, yOffset, null,
racePath.getName().split("#")[1], getFormattedTime(racePath.getPathTime()), txtmaxwidth, timewidth, deltaTime);
}
for (PathDTO path : paths) {
drawRectangleWithText(context2d, xOffset, yOffset + (paths.length-index) * rectHeight, this.colors.getColor(paths.length-1-index),
path.getName().split("#")[1], getFormattedTime(path.getPathTime()), txtmaxwidth, timewidth);
String timeText = (path.getMixedLeg() ? mixedLegText : (path.getAlgorithmTimedOut() ? algorithmTimedOutText : getFormattedTime(path.getPathTime())));
drawRectangleWithText(context2d, xOffset, yOffset + (paths.length-index-(racePath==null?1:0)) * rectHeight, this.colors.getColor(paths.length-1-index),
path.getName().split("#")[1], timeText, txtmaxwidth, timewidth, (path.getMixedLeg()?deltaMixedLeg:(path.getAlgorithmTimedOut()?deltaTimeOut:deltaTime)));
index++;
}
}
@@ -223,17 +276,19 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
context2d.fillRect(x, y, rectWidth, rectHeight);
}
protected void drawRectangleWithText(Context2d context2d, double x, double y, String color, String text, String time, double textmaxwidth, double timewidth) {
protected void drawRectangleWithText(Context2d context2d, double x, double y, String color, String text, String time, double textmaxwidth, double timewidth, double xdelta) {
double offset = 3.0;
context2d.setFont(textFont);
if (color != null) {
drawRectangle(context2d, x, y, color);
}
context2d.setGlobalAlpha(0.80);
context2d.setFillStyle("white");
context2d.fillRect(x + rectWidth, y, 15.0 + textmaxwidth + timewidth, rectHeight);
context2d.fillRect(x + (color==null?0:rectWidth), y, 20.0 + textmaxwidth + timewidth + (color==null?rectWidth:0), rectHeight);
context2d.setGlobalAlpha(1.0);
context2d.setFillStyle(textColor);
context2d.fillText(text, x + rectWidth + 5.0, y + 12.0 + offset);
context2d.fillText(time, x + rectWidth + textmaxwidth + 10.0, y + 12.0 + offset);
context2d.fillText(time, x + rectWidth + textmaxwidth + xdelta + 15.0, y + 12.0 + offset);
}
protected String getFormattedTime(long pathTime) {
@@ -244,8 +299,9 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
return pathTimeStr;
}
public void simulate(Date from) {
GetSimulationAction getSimulation = new GetSimulationAction(sailingService, raceIdentifier, from, prevStartTime);
public void simulate(int leg) {
LegIdentifier legIdentifier = new LegIdentifierImpl(raceIdentifier, String.valueOf(leg));
GetSimulationAction getSimulation = new GetSimulationAction(sailingService, legIdentifier);
asyncActionsExecutor.execute(getSimulation, GET_SIMULATION_CATEGORY,
new MarkedAsyncCallback<>(new AsyncCallback<SimulatorResultsDTO>() {
@Override
@@ -259,19 +315,26 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
public void onSuccess(SimulatorResultsDTO result) {
// store results
if (result != null) {
prevStartTime = result.getStartTime();
if (result.getPaths() != null) {
simulationResult = result;
PathDTO[] paths = result.getPaths();
if (result.getLegDuration() > 0) {
racePath = new PathDTO();
List<SimulatorWindDTO> racePathPoints = new ArrayList<SimulatorWindDTO>();
racePathPoints.add(new SimulatorWindDTO(null, 0, 0, paths[0].getPoints().get(0).timepoint));
racePathPoints.add(new SimulatorWindDTO(null, 0, 0, paths[0].getPoints().get(0).timepoint + result.getLegDuration()));
racePath.setPoints(racePathPoints);
racePath.setName("0#Race");
} else {
racePath = null;
}
clearCanvas();
drawPaths();
}
} else {
raceLeg = 0;
simulationResult = null;
clearCanvas();
}
}
}));
@@ -43,6 +43,8 @@ public class PathCanvasOverlay extends WindFieldCanvasOverlay implements Named {
private long totalTimeMilliseconds = 0;
private String name;
private boolean algorithmTimedOut;
private boolean mixedLeg;
private String pathColor = "Green";
@@ -56,9 +58,11 @@ public class PathCanvasOverlay extends WindFieldCanvasOverlay implements Named {
this.name = name;
}
public PathCanvasOverlay(MapWidget map, int zIndex, String name, Timer timer, WindFieldGenParamsDTO windParams, CoordinateSystem coordinateSystem) {
public PathCanvasOverlay(MapWidget map, int zIndex, String name, Timer timer, WindFieldGenParamsDTO windParams, boolean algorithmTimedOut, boolean mixedLeg, CoordinateSystem coordinateSystem) {
super(map, zIndex, timer, windParams, coordinateSystem);
this.name = name;
this.algorithmTimedOut = algorithmTimedOut;
this.mixedLeg = mixedLeg;
}
public PathCanvasOverlay(MapWidget map, int zIndex, String name, long totalTimeMilliseconds, CoordinateSystem coordinateSystem) {
@@ -250,6 +254,14 @@ public class PathCanvasOverlay extends WindFieldCanvasOverlay implements Named {
return name;
}
public boolean getAlgorithmTimedOut() {
return algorithmTimedOut;
}
public boolean getMixedLeg() {
return mixedLeg;
}
public long getPathTime() {
if (totalTimeIsGiven) {
return totalTimeMilliseconds;
@@ -40,6 +40,8 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
private String textColor = "Black";
private String textFont = "10pt OpenSansRegular";
private String algorithmTimedOutText = "out-of-bounds";
private String mixedLegText = "ambiguous wind";
public PathLegendCanvasOverlay(MapWidget map, int zIndex, char mode, CoordinateSystem coordinateSystem) {
super(map, zIndex, coordinateSystem);
@@ -82,13 +84,44 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
txtmet = context2d.measureText("00:00:00");
double timewidth = txtmet.getWidth();
double txtmaxwidth = 0.0;
boolean containsTimeOut = false;
boolean containsMixedLeg = false;
for (PathCanvasOverlay path : pathOverlays) {
if (path.getAlgorithmTimedOut()) {
containsTimeOut = true;
}
if (path.getMixedLeg()) {
containsMixedLeg = true;
}
txtmet = context2d.measureText(path.getName());
txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth());
}
double newwidth = 0;
double deltaTime = 0;
double deltaMixedLeg = 0;
double deltaTimeOut = 0;
double mixedLegWidth = 0;
if (containsMixedLeg) {
txtmet = context2d.measureText(mixedLegText);
mixedLegWidth = txtmet.getWidth();
newwidth = Math.max(timewidth, mixedLegWidth);
}
double timeOutWidth = 0;
if (containsTimeOut) {
txtmet = context2d.measureText(algorithmTimedOutText);
timeOutWidth = txtmet.getWidth();
newwidth = Math.max(newwidth, timeOutWidth);
}
if (containsMixedLeg||containsTimeOut) {
deltaTime = newwidth - timewidth;
deltaMixedLeg = newwidth - mixedLegWidth;
deltaTimeOut = newwidth - timeOutWidth;
timewidth = newwidth;
}
for (PathCanvasOverlay path : pathOverlays) {
String timeText = (path.getMixedLeg() ? mixedLegText : (path.getAlgorithmTimedOut() ? algorithmTimedOutText : getFormattedTime(path.getPathTime())));
drawRectangleWithText(xOffset, yOffset + (pathOverlays.size()-1-index) * rectHeight, path.getPathColor(),
path.getName(), getFormattedTime(path.getPathTime()),txtmaxwidth,timewidth);
path.getName(), timeText, txtmaxwidth, timewidth, (path.getMixedLeg()?deltaMixedLeg:(path.getAlgorithmTimedOut()?deltaTimeOut:deltaTime)));
index++;
}
//
@@ -170,7 +203,7 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
context2d.fillRect(x, y, rectWidth, rectHeight);
}
protected void drawRectangleWithText(double x, double y, String color, String text, String time, double textmaxwidth, double timewidth) {
protected void drawRectangleWithText(double x, double y, String color, String text, String time, double textmaxwidth, double timewidth, double xdelta) {
double offset = 3.0;
@@ -179,11 +212,11 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
drawRectangle(x, y, color);
context2d.setGlobalAlpha(0.80);
context2d.setFillStyle("white");
context2d.fillRect(x + rectWidth, y, 15.0 + textmaxwidth + timewidth, rectHeight);
context2d.fillRect(x + rectWidth, y, 20.0 + textmaxwidth + timewidth, rectHeight);
context2d.setGlobalAlpha(1.0);
context2d.setFillStyle(textColor);
context2d.fillText(text, x + rectWidth + 5.0, y + 12.0 + offset);
context2d.fillText(time, x + rectWidth + textmaxwidth + 10.0, y + 12.0 + offset);
context2d.fillText(time, x + rectWidth + textmaxwidth + xdelta + 15.0, y + 12.0 + offset);
}
protected String getFormattedTime(long pathTime) {
@@ -18,8 +18,8 @@ public class ReplayPathCanvasOverlay extends PathCanvasOverlay {
private List<SimulatorWindDTO> windDTOToDraw;
public ReplayPathCanvasOverlay(MapWidget map, int zIndex, final String name, final Timer timer,
WindFieldGenParamsDTO windParams, CoordinateSystem coordinateSystem) {
super(map, zIndex, name, timer, windParams, coordinateSystem);
WindFieldGenParamsDTO windParams, boolean algorithmTimedOut, boolean mixedLeg, CoordinateSystem coordinateSystem) {
super(map, zIndex, name, timer, windParams, algorithmTimedOut, mixedLeg, coordinateSystem);
this.displayWindAlongPath = false;
windDTOToDraw = null;
canvas.setStyleName("replayPanel");
@@ -34,6 +34,10 @@ public class ReplayPathCanvasOverlay extends PathCanvasOverlay {
@Override
public void timeChanged(final Date newTime, Date oldTime) {
if (windFieldDTO == null) {
return;
}
canvas.getContext2d().clearRect(0/* canvas.getAbsoluteLeft() */, 0/* canvas.getAbsoluteTop() */,
canvas.getCoordinateSpaceWidth(), canvas.getCoordinateSpaceHeight());
@@ -50,7 +54,10 @@ public class ReplayPathCanvasOverlay extends PathCanvasOverlay {
@Override
public boolean shallStop() {
if (!isVisible() || windDTOToDraw == null || windFieldDTO == null) {
if (windDTOToDraw == null || windFieldDTO == null) {
return false;
}
if (!isVisible()) {
return true;
}
if (windDTOToDraw.size() >= (windFieldDTO.getMatrix().size()-1)) {
@@ -158,27 +158,31 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
PathDTO currentPath = null;
//String color = null;
String pathName = null;
boolean algorithmTimedOut = false;
int noOfPaths = paths.length;
for (int index = 0; index < noOfPaths; ++index) {
currentPath = paths[index];
pathName = currentPath.getName();
algorithmTimedOut = currentPath.getAlgorithmTimedOut();
//color = colorPalette.getColor(noOfPaths - 1 - index);
if (pathName.equals("Polyline")) {
pathPolyline = createPathPolyline(currentPath);
} else if (pathName.equals("GPS Poly")) {
continue;
}
else {
} else {
/* TODO Revisit for now creating a WindFieldDTO from the path */
WindFieldDTO pathWindDTO = new WindFieldDTO();
WindFieldDTO pathWindDTO = null;
if (!currentPath.getMixedLeg()) {
pathWindDTO = new WindFieldDTO();
pathWindDTO.setMatrix(currentPath.getPoints());
}
ReplayPathCanvasOverlay replayPathCanvasOverlay = new ReplayPathCanvasOverlay(map, SimulatorMapOverlaysZIndexes.PATH_ZINDEX,
pathName.split("#")[1], timer, windParams, coordinateSystem);
pathName.split("#")[1], timer, windParams, algorithmTimedOut, currentPath.getMixedLeg(), coordinateSystem);
replayPathCanvasOverlays.add(replayPathCanvasOverlay);
replayPathCanvasOverlay.setPathColor(colorPalette.getColor(Integer.parseInt(pathName.split("#")[0])-1));
@@ -205,7 +209,7 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
legendCanvasOverlay.setPathOverlays(replayPathCanvasOverlays);
long tmpDurationTime = currentPath.getPathTime();
if (tmpDurationTime > maxDurationTime) {
if ((!currentPath.getMixedLeg())&&(!currentPath.getAlgorithmTimedOut())&&(tmpDurationTime > maxDurationTime)) {
maxDurationTime = tmpDurationTime;
}
}
@@ -4,12 +4,64 @@
<div id="mainContent">
<h4 class="articleHeadline">What's New - Strategy Simulator</h4>
<div class="innerContent">
<h5 class="articleSubheadline">September 2014</h5>
<h5 class="articleSubheadline">October 2014</h5>
<ul class="bulletList">
<li>Point 1...
</li>
<li>Simulation is being integrated into the race board (see What's New in Sailing Analytics)</li>
</ul>
<h5 class="articleSubheadline">August 2014</h5>
<ul class="bulletList">
<li>Accuracy of optimal course calculation has been improved</li>
<li>Streamlet motion is now calibrated to physical reality on large zoom levels of the map</li>
</ul>
<h5 class="articleSubheadline">April 2014</h5>
<ul class="bulletList">
<li>Wind is visualized using animated streamlets based on a swarm of particles which locally follow the wind</li>
</ul>
<h5 class="articleSubheadline">September 2013</h5>
<ul class="bulletList">
<li>Windbot based on RaspberryPi to construct real, spatially resolved wind vector fields from wind measurements</li>
</ul>
<h5 class="articleSubheadline">June 2013</h5>
<ul class="bulletList">
<li>Optimal courses shown as "Omniscient" are determined by an heuristic search algorithm greatly improving accuracy and runtime performance</li>
<li>Sailing angles are represented with full numeric accuracy</li>
<li>Water current is taken into account</li>
<li>Support up- and downwind legs</li>
<li>1-Click Simulation simplifies the user interaction</li>
<li>Race course map for Kieler Woche and Travemuender Woche</li>
</ul>
<h5 class="articleSubheadline">March 2013</h5>
<ul class="bulletList">
<li>What-if simulation comparing sailed GPS-track and simulated course with changed locations of turns for
answering questions like: would it have been advantageous to do the second turn a bit later?</li>
</ul>
<h5 class="articleSubheadline">February 2013</h5>
<ul class="bulletList">
<li>Strategy Simulator becomes a part of SAP's Sailing Analytics suite</li>
</ul>
<h5 class="articleSubheadline">December 2012</h5>
<ul class="bulletList">
<li>Polar diagram chart is available</li>
<li>Multiple boat classes are supported based on polar diagrams in tabular format provided as CSV-files</li>
<li>Several wind visualization approaches are supported: arrows on a grid, as well as, heatmap combined with bearing lines (either grid or integrated across race course)</li>
</ul>
<h5 class="articleSubheadline">June 2012</h5>
<ul class="bulletList">
<li>First upwind-only prototype of sailing simulation is available</li>
<li>Optimal courses shown as "Omniscient" are calculated with an implementation of Dijkstra's algorithm on a rectangular spatial grid</li>
<li>Wind is visualized by arrows which scale with wind speed</li>
<li>Race course definition with 2 mouse clicks for start and end</li>
</ul>
</div>
</div>
</body>
@@ -13,4 +13,5 @@ Require-Bundle: org.hamcrest;bundle-version="1.1.0",
com.sap.sailing.domain.test,
com.sap.sse.common,
com.sap.sailing.domain.tractracadapter,
com.tractrac.clientmodule;bundle-version="3.0.7"
com.tractrac.clientmodule;bundle-version="3.0.7",
com.sap.sailing.domain
@@ -42,6 +42,7 @@ import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl;
import com.sap.sailing.domain.common.impl.WindImpl;
import com.sap.sailing.domain.common.impl.WindSpeedSteppingWithMaxDistance;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace;
@@ -49,7 +50,6 @@ import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
import com.sap.sailing.domain.tracking.impl.WindWithConfidenceImpl;
import com.sap.sailing.polars.mining.PolarDataMiner;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -12,8 +12,8 @@ import java.util.Random;
import org.junit.Test;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.regression.IncrementalLeastSquares;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
public class IncrementalLeastSquaresTest {
@@ -7,8 +7,8 @@ import static org.junit.Assert.assertTrue;
import org.hamcrest.number.IsCloseTo;
import org.junit.Test;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.regression.IncrementalLeastSquares;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
public class IncrementalLinearRegressionOrderOneTest {
@@ -12,7 +12,6 @@ import java.text.ParseException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@@ -27,11 +26,11 @@ import com.sap.sailing.domain.common.confidence.impl.ScalableDouble;
import com.sap.sailing.domain.common.confidence.impl.ScalableWind;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.test.OnlineTracTracBasedTest;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tractracadapter.ReceiverType;
import com.sap.sailing.polars.impl.PolarDataServiceImpl;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl.ManeuverClassification;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.util.kmeans.Cluster;
@@ -117,7 +116,7 @@ public class TestWindEstimationFromManeuversOnAFew505Races extends OnlineTracTra
IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException,
CreateModelException {
setUp("event_20110609_KielerWoch-505_Race_3");
ManeuverBasedWindEstimationTrackImpl windTrack = new ManeuverBasedWindEstimationTrackImpl(new PolarDataServiceImpl(Executors.newFixedThreadPool(4)),
ManeuverBasedWindEstimationTrackImpl windTrack = new ManeuverBasedWindEstimationTrackImpl(new PolarDataServiceImpl(),
getTrackedRace(), /* millisecondsOverWhichToAverage */ 30000, /* waitForLatest */ true);
final Map<Maneuver, Competitor> maneuvers = windTrack.getAllManeuvers(/* waitForLatest */ true);
final int numberOfClusters = 16;
@@ -153,7 +152,7 @@ public class TestWindEstimationFromManeuversOnAFew505Races extends OnlineTracTra
}
private Wind getManeuverBasedAverageWind() throws NotEnoughDataHasBeenAddedException {
ManeuverBasedWindEstimationTrackImpl windTrack = new ManeuverBasedWindEstimationTrackImpl(new PolarDataServiceImpl(Executors.newFixedThreadPool(4)),
ManeuverBasedWindEstimationTrackImpl windTrack = new ManeuverBasedWindEstimationTrackImpl(new PolarDataServiceImpl(),
getTrackedRace(), /* millisecondsOverWhichToAverage */ 30000, /* waitForLatest */ true);
ScalableWind windSum = null;
int count = 0;
@@ -7,9 +7,7 @@ Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ClassPath: .
Export-Package:
com.sap.sailing.polars,
com.sap.sailing.polars.data,
com.sap.sailing.polars.factory,
com.sap.sailing.polars.regression,
com.sap.sailing.polars.windestimation
Bundle-ActivationPolicy: lazy
@@ -21,7 +19,9 @@ Require-Bundle:
com.sap.sse.common,
com.sap.sse,
com.sap.sse.shared.android,
org.apache.commons.math;bundle-version="2.1.0"
org.apache.commons.math;bundle-version="2.1.0",
org.eclipse.osgi
Import-Package:
com.sap.sailing.util,
com.sap.sse.common
Bundle-Activator: com.sap.sailing.polars.impl.Activator
@@ -1,17 +0,0 @@
package com.sap.sailing.polars.factory;
import java.util.concurrent.Executor;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.polars.factory.impl.PolarDataServiceImplFactory;
public abstract class PolarDataServiceFactory {
public static PolarDataService createStandardPolarDataService(Executor executor) {
PolarDataServiceFactory factory = new PolarDataServiceImplFactory();
return factory.createPolarDataService(executor);
}
protected abstract PolarDataService createPolarDataService(Executor executor);
}
@@ -1,16 +0,0 @@
package com.sap.sailing.polars.factory.impl;
import java.util.concurrent.Executor;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.polars.factory.PolarDataServiceFactory;
import com.sap.sailing.polars.impl.PolarDataServiceImpl;
public class PolarDataServiceImplFactory extends PolarDataServiceFactory {
@Override
public PolarDataService createPolarDataService(Executor executor) {
return new PolarDataServiceImpl(executor);
}
}
@@ -0,0 +1,34 @@
package com.sap.sailing.polars.impl;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import com.sap.sailing.domain.polars.PolarDataService;
public class Activator implements BundleActivator {
private static final Logger logger = Logger.getLogger(Activator.class.getName());
private final Set<ServiceRegistration<?>> registrations = new HashSet<>();
@Override
public void start(BundleContext context) throws Exception {
logger.info("Registering PolarDataService");
registrations.add(context.registerService(PolarDataService.class, new PolarDataServiceImpl(), null));
}
@Override
public void stop(BundleContext context) throws Exception {
logger.info("Unregistering PolarDataService");
for (ServiceRegistration<?> reg : registrations) {
reg.unregister();
}
registrations.clear();
}
}
@@ -17,15 +17,18 @@ import com.sap.sailing.domain.common.PolarSheetGenerationSettings;
import com.sap.sailing.domain.common.PolarSheetsData;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
import com.sap.sailing.domain.common.confidence.impl.BearingWithConfidenceImpl;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.polars.aggregation.PolarFixAggregator;
import com.sap.sailing.polars.aggregation.SimplePolarFixRaceInterval;
import com.sap.sailing.polars.data.PolarFix;
import com.sap.sailing.polars.generation.PolarSheetGenerator;
import com.sap.sailing.polars.mining.PolarDataMiner;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.util.SmartFutureCache;
@@ -41,7 +44,7 @@ public class PolarDataServiceImpl implements PolarDataService {
private final PolarDataMiner polarDataMiner;
public PolarDataServiceImpl(Executor executor) {
public PolarDataServiceImpl() {
this.polarDataMiner = new PolarDataMiner();
}
@@ -158,4 +161,32 @@ public class PolarDataServiceImpl implements PolarDataService {
polarDataMiner.raceFinishedTracking(race);
}
@Override
public BearingWithConfidence<Void> getManeuverAngle(BoatClass boatClass, ManeuverType maneuverType, Speed windSpeed)
throws NotEnoughDataHasBeenAddedException {
if (maneuverType != ManeuverType.TACK && maneuverType != ManeuverType.JIBE) {
throw new IllegalArgumentException("ManeuverType needs to be tack or jibe.");
}
LegType legType = maneuverType == ManeuverType.TACK ? LegType.UPWIND : LegType.DOWNWIND;
if (boatClass == null || windSpeed == null) {
throw new IllegalArgumentException("Boatclass and windspeed cannot be null.");
}
SpeedWithBearingWithConfidence<Void> port = getAverageSpeedWithBearing(boatClass, windSpeed, legType, Tack.PORT);
SpeedWithBearingWithConfidence<Void> starboard = getAverageSpeedWithBearing(boatClass, windSpeed, legType,
Tack.STARBOARD);
double angleSumInDeg = Math.abs(port.getObject().getBearing().getDegrees())
+ Math.abs(starboard.getObject().getBearing().getDegrees());
Bearing bearing = new DegreeBearingImpl(angleSumInDeg);
double confidence = (port.getConfidence() + starboard.getConfidence()) / 2;
BearingWithConfidence<Void> bearingWithConfidence = new BearingWithConfidenceImpl<Void>(bearing, confidence,
null);
return bearingWithConfidence;
}
@Override
public SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException {
return getAverageSpeedWithBearing(boatClass, windSpeed, legType, tack, true);
}
}
@@ -14,10 +14,10 @@ import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.polars.impl.CubicEquation;
import com.sap.sailing.polars.regression.IncrementalLeastSquares;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair;
@@ -48,7 +48,7 @@ public class AngleAndSpeedRegression {
double estimatedAngle = angleRegression.getOrCreatePolynomialFunction().value(windSpeedInKnots);
Bearing bearing = new DegreeBearingImpl(estimatedAngle);
SpeedWithBearing speedWithBearing = new KnotSpeedWithBearingImpl(estimatedSpeed, bearing);
return new SpeedWithBearingWithConfidenceImpl<Void>(speedWithBearing, /*FIXME*/ 0.5, null);
return new SpeedWithBearingWithConfidenceImpl<Void>(speedWithBearing, Math.min(1, speedRegression.getNumberOfAddedPoints() / 100.0), null);
}
public Set<SpeedWithBearingWithConfidence<Void>> estimateTrueWindSpeedAndAngleCandidates(Speed speedOverGround) throws NotEnoughDataHasBeenAddedException {
@@ -13,7 +13,7 @@ import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sse.datamining.AdditionalResultDataBuilder;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.factories.GroupKeyFactory;
@@ -34,7 +34,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
private final TrackedRace race;
private final Competitor competitor;
private final ClusterGroup<Speed> windSpeedClusterGroup;
private final Set<WindSource> windSourcesToExcludeForBearing;
private final Set<WindSource> windSourcesToExcludeForSpeed;
private final ClusterGroup<Bearing> angleClusterGroup;
private final BearingWithConfidence<Integer> trueWindAngle;
@@ -48,7 +47,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
this.competitor = competitor;
this.windSpeedClusterGroup = windSpeedClusterGroup;
this.angleClusterGroup = angleClusterGroup;
this.windSourcesToExcludeForBearing = collectWindSourcesToIgnoreForBearing();
this.windSourcesToExcludeForSpeed = collectWindSourcesToIgnoreForSpeed();
this.trueWindAngle = computeTrueWindAngle();
this.wind = race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint(), windSourcesToExcludeForSpeed);
@@ -73,7 +71,7 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
private BearingWithConfidence<Integer> computeTrueWindAngle() {
SpeedWithBearing boatSpeed = race.getTrack(competitor).getEstimatedSpeed(fix.getTimePoint());
WindWithConfidence<Pair<Position, TimePoint>> wind = race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint(), windSourcesToExcludeForBearing);
WindWithConfidence<Pair<Position, TimePoint>> wind = race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint());
BearingWithConfidenceImpl<Integer> result = null;
if (wind != null && boatSpeed != null) {
@@ -105,32 +103,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
track.getMillisecondsOverWhichToAverageSpeed()/2, /* minimumConfidence */ 0.00000001));
}
private Set<WindSource> collectWindSourcesToIgnoreForBearing() {
Set<WindSource> windSourcesToExclude = new HashSet<WindSource>();
Iterable<WindSource> combinedSources = race.getWindSources(WindSourceType.COMBINED);
for (WindSource combinedSource : combinedSources) {
windSourcesToExclude.add(combinedSource);
}
Iterable<WindSource> courseSources = race.getWindSources(WindSourceType.COURSE_BASED);
for (WindSource courseSource : courseSources) {
windSourcesToExclude.add(courseSource);
}
Iterable<WindSource> expSources = race.getWindSources(WindSourceType.EXPEDITION);
for (WindSource expSource : expSources) {
windSourcesToExclude.add(expSource);
}
Iterable<WindSource> rcSources = race.getWindSources(WindSourceType.RACECOMMITTEE);
for (WindSource rcSource : rcSources) {
windSourcesToExclude.add(rcSource);
}
Iterable<WindSource> webSources = race.getWindSources(WindSourceType.WEB);
for (WindSource webSource : webSources) {
windSourcesToExclude.add(webSource);
}
return windSourcesToExclude;
}
private Set<WindSource> collectWindSourcesToIgnoreForSpeed() {
Set<WindSource> windSourcesToExclude = new HashSet<WindSource>();
Iterable<WindSource> combinedSources = race.getWindSources(WindSourceType.COMBINED);
@@ -7,7 +7,7 @@ import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
@@ -20,9 +20,9 @@ import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.polars.regression.MovingAverageBoatSpeedEstimator;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.datamining.AdditionalResultDataBuilder;
@@ -38,10 +38,10 @@ import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl;
import com.sap.sailing.domain.common.impl.PolarSheetsDataImpl;
import com.sap.sailing.domain.common.impl.PolarSheetsHistogramDataImpl;
import com.sap.sailing.domain.common.impl.WindSpeedSteppingWithMaxDistance;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.polars.impl.CubicEquation;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sse.datamining.components.FilterCriterion;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.data.ClusterGroup;
@@ -13,8 +13,8 @@ import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.regression.IncrementalLeastSquares;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
import com.sap.sse.datamining.AdditionalResultDataBuilder;
import com.sap.sse.datamining.components.Processor;
@@ -2,6 +2,8 @@ package com.sap.sailing.polars.regression;
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
/**
* Support incremental regression linear in one variable but potentially of higher order.
*
@@ -28,4 +30,6 @@ public interface IncrementalLeastSquares {
*/
public abstract PolynomialFunction getOrCreatePolynomialFunction() throws NotEnoughDataHasBeenAddedException;
public abstract long getNumberOfAddedPoints();
}
@@ -5,6 +5,7 @@ import java.io.Serializable;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.mining.MovingAverageProcessorImpl;
import com.sap.sse.concurrent.LockUtil;
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
@@ -12,8 +12,8 @@ import org.apache.commons.math.linear.RealMatrixPreservingVisitor;
import org.apache.commons.math.linear.RealVector;
import org.apache.commons.math.linear.SingularMatrixException;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.regression.IncrementalLeastSquares;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sse.concurrent.LockUtil;
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
@@ -297,4 +297,9 @@ public class IncrementalAnyOrderLeastSquaresImpl implements IncrementalLeastSqua
}
@Override
public long getNumberOfAddedPoints() {
return numberOfPointsAdded.get();
}
}
@@ -35,11 +35,11 @@ import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.impl.WindImpl;
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableSpeed;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.WindTrackImpl;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
@@ -5,7 +5,7 @@ import java.util.function.Function;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.confidence.ConfidenceBasedAverager;
import com.sap.sailing.domain.common.confidence.HasConfidenceAndIsScalable;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl.ManeuverClassification;
import com.sap.sse.common.scalablevalue.ScalableValue;
@@ -0,0 +1,29 @@
package com.sap.sailing.server.gateway.serialization.impl;
import org.json.simple.JSONObject;
import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.LeagueConfiguration;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
public class LeagueConfigurationJsonSerializer extends RacingProcedureConfigurationJsonSerializer implements
JsonSerializer<RacingProcedureConfiguration> {
public static LeagueConfigurationJsonSerializer create() {
return new LeagueConfigurationJsonSerializer();
}
public LeagueConfigurationJsonSerializer() {
super();
}
@Override
public JSONObject serialize(RacingProcedureConfiguration baseObject) {
JSONObject result = super.serialize(baseObject);
@SuppressWarnings("unused")
LeagueConfiguration object = (LeagueConfiguration) baseObject;
return result;
}
}
@@ -11,7 +11,7 @@ public class RegattaConfigurationJsonSerializer implements JsonSerializer<Regatt
public static RegattaConfigurationJsonSerializer create() {
return new RegattaConfigurationJsonSerializer(RRS26ConfigurationJsonSerializer.create(),
GateStartConfigurationJsonSerializer.create(), ESSConfigurationJsonSerializer.create(),
RacingProcedureConfigurationJsonSerializer.create());
RacingProcedureConfigurationJsonSerializer.create(), LeagueConfigurationJsonSerializer.create());
}
public static final Object FIELD_DEFAULT_RACING_PROCEDURE_TYPE = "defaultRacingProcedureType";
@@ -19,20 +19,23 @@ public class RegattaConfigurationJsonSerializer implements JsonSerializer<Regatt
public static final String FIELD_RRS26 = "rrs26";
public static final String FIELD_GATE_START = "gateStart";
public static final String FIELD_ESS = "ess";
public static final String FIELD_LEAGUE = "league";
public static final String FIELD_BASIC = "basic";
private final JsonSerializer<RacingProcedureConfiguration> rrs26Serializer;
private final JsonSerializer<RacingProcedureConfiguration> gateStartSerializer;
private final JsonSerializer<RacingProcedureConfiguration> essSerializer;
private final JsonSerializer<RacingProcedureConfiguration> basicSerializer;
private final JsonSerializer<RacingProcedureConfiguration> leagueSerializer;
public RegattaConfigurationJsonSerializer(JsonSerializer<RacingProcedureConfiguration> rrs26,
JsonSerializer<RacingProcedureConfiguration> gateStart, JsonSerializer<RacingProcedureConfiguration> ess,
JsonSerializer<RacingProcedureConfiguration> basicSerializer) {
JsonSerializer<RacingProcedureConfiguration> basicSerializer, JsonSerializer<RacingProcedureConfiguration> leagueSerializer) {
this.rrs26Serializer = rrs26;
this.gateStartSerializer = gateStart;
this.essSerializer = ess;
this.basicSerializer = basicSerializer;
this.leagueSerializer = leagueSerializer;
}
@Override
@@ -59,6 +62,10 @@ public class RegattaConfigurationJsonSerializer implements JsonSerializer<Regatt
if (object.getBasicConfiguration() != null) {
result.put(FIELD_BASIC, basicSerializer.serialize(object.getBasicConfiguration()));
}
if (object.getLeagueConfiguration() != null) {
result.put(FIELD_LEAGUE, leagueSerializer.serialize(object.getLeagueConfiguration()));
}
return result;
}
@@ -5,10 +5,7 @@ Bundle-SymbolicName: com.sap.sailing.server.gateway
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: com.sap.sailing.polars,
com.sap.sailing.polars.regression,
com.sap.sailing.polars.windestimation,
com.sap.sailing.server,
Import-Package: com.sap.sailing.server,
com.sap.sailing.server.operationaltransformation,
javax.ws.rs;version="1.1.1",
javax.ws.rs.core;version="1.1.1",
@@ -55,7 +52,8 @@ Require-Bundle: com.sap.sailing.domain,
org.apache.shiro.core;bundle-version="1.2.2",
org.apache.shiro.web;bundle-version="1.2.2",
org.apache.shiro.ehcache;bundle-version="1.2.3",
org.jvnet.mimepull;bundle-version="1.9.4"
org.jvnet.mimepull;bundle-version="1.9.4",
com.sap.sailing.polars
Bundle-ClassPath: .
Web-ContextPath: /sailingserver
Export-Package: com.sap.sailing.server.gateway,
@@ -31,9 +31,9 @@ import com.sap.sailing.domain.common.confidence.impl.ScalableDouble;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl;
import com.sap.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl.ManeuverClassification;
import com.sap.sailing.polars.windestimation.ScalableBearingAndScalableDouble;
@@ -692,6 +692,19 @@ public class MasterDataImportTest {
windTrackOnDest.unlockAfterRead();
}
//Reimport again to see if db throws exceptions (see console for error for now, since exception is caught deep inside)
try {
streamingOutput.write(os);
os.flush();
inputStream = new ByteArrayInputStream(os.toByteArray());
MasterDataImporter importer = new MasterDataImporter(domainFactory, destService);
importer.importFromStream(inputStream, randomUUID, false);
} finally {
os.close();
inputStream.close();
}
}
@Test
@@ -6,9 +6,7 @@ Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.sap.sailing.server.impl.Activator
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: com.sap.sailing.polars,
com.sap.sailing.polars.factory,
com.sap.sailing.server.gateway.deserialization,
Import-Package: com.sap.sailing.server.gateway.deserialization,
org.json.simple,
org.json.simple.parser,
org.osgi.framework;version="1.3.0",
@@ -24,14 +22,14 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.udpconnector,
com.sap.sailing.domain.shared.android,
com.sap.sailing.server.gateway.serialization,
com.sap.sailing.polars,
com.sap.sse.common,
com.sap.sse.operationaltransformation,
com.sap.sse.replication,
com.sap.sse,
com.sap.sailing.server.gateway.serialization.shared.android,
com.sap.sse.shared.android,
com.sap.sse.filestorage
com.sap.sse.filestorage,
com.sap.sailing.simulator;bundle-version="1.0.0"
Bundle-ClassPath: .
Export-Package: com.sap.sailing.server,
com.sap.sailing.server.impl;
@@ -43,5 +41,6 @@ Export-Package: com.sap.sailing.server,
com.sap.sailing.server.replication.test,
com.sap.sailing.domain.racelogtrackingadapter.test",
com.sap.sailing.server.masterdata,
com.sap.sailing.server.operationaltransformation
com.sap.sailing.server.operationaltransformation,
com.sap.sailing.server.simulation
@@ -55,6 +55,7 @@ import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
@@ -65,8 +66,8 @@ import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.TrackerManager;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.server.masterdata.DataImportLockWithProgress;
import com.sap.sailing.server.simulation.SimulationService;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
import com.sap.sse.common.Util;
@@ -522,6 +523,8 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
PolarDataService getPolarDataService();
SimulationService getSimulationService();
GPSFixStore getGPSFixStore();
RaceTracker getRaceTrackerById(Object id);
@@ -26,6 +26,7 @@ import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.persistence.racelog.tracking.GPSFixMongoHandler;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMongoHandlerImpl;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMovingMongoHandlerImpl;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.server.MasterDataImportClassLoaderService;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.RacingEventServiceMXBean;
@@ -55,6 +56,8 @@ public class Activator implements BundleActivator {
private ServiceTracker<MasterDataImportClassLoaderService, MasterDataImportClassLoaderService> masterDataImportClassLoaderServiceTracker;
private ServiceTracker<PolarDataService, PolarDataService> polarDataServiceTracker;
public Activator() {
clearPersistentCompetitors = Boolean.valueOf(System.getProperty(CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME, ""+false));
logger.log(Level.INFO, "setting "+CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME+" to "+clearPersistentCompetitors);
@@ -78,6 +81,10 @@ public class Activator implements BundleActivator {
new MasterDataImportClassLoaderServiceTrackerCustomizer(context, racingEventService));
masterDataImportClassLoaderServiceTracker.open();
polarDataServiceTracker = new ServiceTracker<PolarDataService, PolarDataService>(context,
PolarDataService.class, new PolarDataServiceTrackerCustomizer(context, racingEventService));
polarDataServiceTracker.open();
// register the racing service in the OSGi registry
racingEventService.setBundleContext(context);
final Dictionary<String, String> replicableServiceProperties = new Hashtable<>();
@@ -86,14 +93,22 @@ public class Activator implements BundleActivator {
context.registerService(RacingEventService.class.getName(), racingEventService, null);
context.registerService(ClearStateTestSupport.class.getName(), racingEventService, null);
Dictionary<String, String> properties = new Hashtable<String, String>();
final GPSFixMongoHandlerImpl gpsFixMongoHandler = new GPSFixMongoHandlerImpl(racingEventService.getMongoObjectFactory(),
racingEventService.getDomainObjectFactory());
properties.put(TypeBasedServiceFinder.TYPE, GPSFixImpl.class.getName());
registrations.add(context.registerService(GPSFixMongoHandler.class,
new GPSFixMongoHandlerImpl(racingEventService.getMongoObjectFactory(),
racingEventService.getDomainObjectFactory()), properties));
properties.put(TypeBasedServiceFinder.TYPE, GPSFixMovingImpl.class.getName());
gpsFixMongoHandler, properties));
// legacy type name; some DBs may still contain fixes marked with this old package name:
properties.put(TypeBasedServiceFinder.TYPE, "com.sap.sailing.domain.tracking.impl.GPSFixImpl");
registrations.add(context.registerService(GPSFixMongoHandler.class,
new GPSFixMovingMongoHandlerImpl(racingEventService.getMongoObjectFactory(),
racingEventService.getDomainObjectFactory()), properties));
gpsFixMongoHandler, properties));
final GPSFixMovingMongoHandlerImpl gpsFixMovingMongoHandler = new GPSFixMovingMongoHandlerImpl(racingEventService.getMongoObjectFactory(),
racingEventService.getDomainObjectFactory());
properties.put(TypeBasedServiceFinder.TYPE, GPSFixMovingImpl.class.getName());
registrations.add(context.registerService(GPSFixMongoHandler.class, gpsFixMovingMongoHandler, properties));
// legacy type name; some DBs may still contain fixes marked with this old package name:
properties.put(TypeBasedServiceFinder.TYPE, "com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl");
registrations.add(context.registerService(GPSFixMongoHandler.class, gpsFixMovingMongoHandler, properties));
// Add an MBean for the service to the JMX bean server:
RacingEventServiceMXBean mbean = new RacingEventServiceMXBeanImpl(racingEventService);
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
@@ -157,4 +172,33 @@ public class Activator implements BundleActivator {
}
private class PolarDataServiceTrackerCustomizer implements
ServiceTrackerCustomizer<PolarDataService, PolarDataService> {
private final BundleContext context;
private RacingEventServiceImpl racingEventService;
public PolarDataServiceTrackerCustomizer(BundleContext context, RacingEventServiceImpl racingEventService) {
this.context = context;
this.racingEventService = racingEventService;
}
@Override
public PolarDataService addingService(ServiceReference<PolarDataService> reference) {
PolarDataService service = context.getService(reference);
racingEventService.setPolarDataService(service);
return service;
}
@Override
public void modifiedService(ServiceReference<PolarDataService> reference, PolarDataService service) {
}
@Override
public void removedService(ServiceReference<PolarDataService> reference, PolarDataService service) {
racingEventService.unsetPolarDataService(service);
}
}
}
@@ -127,6 +127,7 @@ import com.sap.sailing.domain.persistence.PersistenceFactory;
import com.sap.sailing.domain.persistence.media.MediaDB;
import com.sap.sailing.domain.persistence.media.MediaDBFactory;
import com.sap.sailing.domain.persistence.racelog.tracking.MongoGPSFixStoreFactory;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
@@ -153,8 +154,6 @@ import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.polars.factory.PolarDataServiceFactory;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.Replicator;
import com.sap.sailing.server.gateway.deserialization.impl.CourseAreaJsonDeserializer;
@@ -200,6 +199,8 @@ import com.sap.sailing.server.operationaltransformation.UpdateStartTimeReceived;
import com.sap.sailing.server.operationaltransformation.UpdateTrackedRaceStatus;
import com.sap.sailing.server.operationaltransformation.UpdateWindAveragingTime;
import com.sap.sailing.server.operationaltransformation.UpdateWindSourcesToExclude;
import com.sap.sailing.server.simulation.SimulationService;
import com.sap.sailing.server.simulation.SimulationServiceFactory;
import com.sap.sse.BuildVersion;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
@@ -351,7 +352,9 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
private final AbstractLogEventAuthor raceLogEventAuthorForServer = new LogEventAuthorImpl(
RacingEventService.class.getName(), 0);
private final PolarDataService polarDataService;
private PolarDataService polarDataService;
private final SimulationService simulationService;
/**
* Allow only one master data import at a time to avoid situation where multiple Imports override each other in
@@ -504,13 +507,13 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
operationExecutionListeners = new ConcurrentHashMap<>();
courseListeners = new ConcurrentHashMap<>();
persistentRegattasForRaceIDs = new ConcurrentHashMap<>();
final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3);
// TODO find out how many executors we have on server side and how to manage them
Executor polarExecutor = new ThreadPoolExecutor(/* corePoolSize */THREAD_POOL_SIZE,
/* maximumPoolSize */THREAD_POOL_SIZE,
final int SIMULATION_THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors()/3, 1);
Executor simulatorExecutor = new ThreadPoolExecutor(/* corePoolSize */SIMULATION_THREAD_POOL_SIZE,
/* maximumPoolSize */SIMULATION_THREAD_POOL_SIZE,
/* keepAliveTime */60, TimeUnit.SECONDS,
/* workQueue */new LinkedBlockingQueue<Runnable>());
polarDataService = PolarDataServiceFactory.createStandardPolarDataService(polarExecutor);
// TODO: initialize smart-future-cache for simulation-results and add to simulation-service
simulationService = SimulationServiceFactory.INSTANCE.getService(simulatorExecutor, this);
this.raceLogReplicator = new RaceLogReplicator(this);
this.regattaLogReplicator = new RegattaLogReplicator(this);
this.raceLogScoringReplicator = new RaceLogScoringReplicator(this);
@@ -559,6 +562,11 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
return polarDataService;
}
@Override
public SimulationService getSimulationService() {
return simulationService;
}
@Override
public void clearState() throws Exception {
for (String leaderboardGroupName : new ArrayList<>(this.leaderboardGroupsByName.keySet())) {
@@ -1526,6 +1534,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
PolarFixCacheUpdater polarFixCacheUpdater = new PolarFixCacheUpdater(trackedRace);
polarFixCacheUpdaters.put(trackedRace, polarFixCacheUpdater);
trackedRace.addListener(polarFixCacheUpdater);
if (polarDataService != null) {
trackedRace.setPolarDataService(polarDataService);
}
}
}
@@ -1539,16 +1551,20 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
@Override
public void competitorPositionChanged(GPSFixMoving fix, Competitor item) {
if (polarDataService != null) {
polarDataService.competitorPositionChanged(fix, item, race);
}
}
@Override
public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) {
if (oldStatus.getStatus() == TrackedRaceStatusEnum.LOADING
&& newStatus.getStatus() != TrackedRaceStatusEnum.LOADING) {
if (polarDataService != null) {
polarDataService.raceFinishedLoading(race);
}
}
}
}
@@ -3113,4 +3129,31 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
JoinedClassLoader joinedClassLoader = new JoinedClassLoader(masterDataClassLoaders);
return joinedClassLoader;
}
public void setPolarDataService(PolarDataService service) {
if (this.polarDataService == null) {
polarDataService = service;
setPolarDataServiceOnAllTrackedRaces(service);
}
}
private void setPolarDataServiceOnAllTrackedRaces(PolarDataService service) {
Iterable<Regatta> allRegattas = getAllRegattas();
for (Regatta regatta : allRegattas) {
DynamicTrackedRegatta trackedRegatta = getTrackedRegatta(regatta);
if (trackedRegatta != null) {
Iterable<DynamicTrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
for (TrackedRace trackedRace : trackedRaces) {
trackedRace.setPolarDataService(service);
}
}
}
}
public void unsetPolarDataService(PolarDataService service) {
if (polarDataService == service) {
polarDataService = null;
setPolarDataService(null);
}
}
}
Loaded 100 of 171 files, more files were not shown because too many files have changed in this diff. Show more