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
+6404 -1625

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); com.sap.sse.gwt.client.player.Timer timer = new com.sap.sse.gwt.client.player.Timer(PlayModes.Live, 1000l);
timer.pause(); timer.pause();
ArrayList<ZoomTypes> zoomTypes = new ArrayList<ZoomTypes>(); ArrayList<ZoomTypes> zoomTypes = new ArrayList<ZoomTypes>();
if(startAnalysisDTO.racingProcedureType.equals(RacingProcedureType.GateStart)){ if (startAnalysisDTO.racingProcedureType.equals(RacingProcedureType.GateStart)) {
timer.setTime(startAnalysisDTO.timeOfStartInMilliSeconds+startAnalysisDTO.tailLenghtInMilliseconds); timer.setTime(startAnalysisDTO.timeOfStartInMilliSeconds + startAnalysisDTO.tailLenghtInMilliseconds);
zoomTypes.add(ZoomTypes.BUOYS); zoomTypes.add(ZoomTypes.BUOYS);
}else{ } else {
timer.setTime(startAnalysisDTO.timeOfStartInMilliSeconds); timer.setTime(startAnalysisDTO.timeOfStartInMilliSeconds);
zoomTypes.add(ZoomTypes.TAILS); zoomTypes.add(ZoomTypes.TAILS);
} }
@@ -1,7 +1,7 @@
package com.sap.sailing.datamining.data; package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.polars.PolarDataService; import com.sap.sailing.domain.polars.PolarDataService;
public interface HasLeaderboardContext { public interface HasLeaderboardContext {
@@ -1,7 +1,7 @@
package com.sap.sailing.datamining.data; package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.polars.PolarDataService; import com.sap.sailing.domain.polars.PolarDataService;
public interface HasLeaderboardGroupContext { public interface HasLeaderboardGroupContext {
@@ -5,7 +5,7 @@ import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext; 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.sailing.server.RacingEventService;
import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor; 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.datamining.data.HasLeaderboardGroupContext;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup; 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 { 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.datamining.data.HasLeaderboardContext;
import com.sap.sailing.domain.leaderboard.Leaderboard; 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 { 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.scalablevalue.impl.ScalableSpeed;
import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.leaderboard.Leaderboard; 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.GPSFixTrack;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindWithConfidence; import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sse.common.Duration; import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util; 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)"), RRS26("Fix Line Start (RRS26)"),
GateStart("Gate Start"), GateStart("Gate Start"),
ESS("\"Extreme Sailing Series\"-Start"), ESS("\"Extreme Sailing Series\"-Start"),
BASIC("Basic Countdown Start"); BASIC("Basic Countdown Start"),
LEAGUE("League Start");
private String displayName; 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.basic.impl.BasicRacingProcedureImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ess.impl.ESSRacingProcedureImpl; 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.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.abstractlog.race.state.racingprocedure.rrs26.impl.RRS26RacingProcedureImpl;
import com.sap.sailing.domain.base.configuration.ConfigurationLoader; import com.sap.sailing.domain.base.configuration.ConfigurationLoader;
import com.sap.sailing.domain.base.configuration.RegattaConfiguration; 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()); return new RRS26RacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getRRS26Configuration());
case BASIC: case BASIC:
return new BasicRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getBasicConfiguration()); return new BasicRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getBasicConfiguration());
case LEAGUE:
return new LeagueRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getLeagueConfiguration());
default: default:
throw new UnsupportedOperationException("Unknown racing procedure " + type.toString()); 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.abstractlog.race.state.racingprocedure.RacingProcedure;
import com.sap.sailing.domain.base.configuration.procedures.ESSConfiguration; 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.GateStartConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.LeagueConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.RRS26Configuration; import com.sap.sailing.domain.base.configuration.procedures.RRS26Configuration;
import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.racelog.RacingProcedureType; import com.sap.sailing.domain.common.racelog.RacingProcedureType;
@@ -42,7 +43,13 @@ public interface RegattaConfiguration extends Serializable, Cloneable {
* @return <code>null</code> if there is no configuration. * @return <code>null</code> if there is no configuration.
*/ */
ESSConfiguration getESSConfiguration(); 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. * Gets the configuration for Basic races.
* @return <code>null</code> if there is no configuration. * @return <code>null</code> if there is no configuration.
@@ -21,6 +21,7 @@ public class EmptyRegattaConfiguration extends RegattaConfigurationImpl implemen
setGateStartConfiguration(new GateStartConfigurationImpl()); setGateStartConfiguration(new GateStartConfigurationImpl());
setESSConfiguration(new ESSConfigurationImpl()); setESSConfiguration(new ESSConfigurationImpl());
setBasicConfiguration(new RacingProcedureConfigurationImpl()); setBasicConfiguration(new RacingProcedureConfigurationImpl());
setLeagueConfiguration(new LeagueConfigurationImpl());
return clone(); 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.RegattaConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.ESSConfiguration; 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.GateStartConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.LeagueConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.RRS26Configuration; import com.sap.sailing.domain.base.configuration.procedures.RRS26Configuration;
import com.sap.sailing.domain.common.CourseDesignerMode; import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.racelog.RacingProcedureType; import com.sap.sailing.domain.common.racelog.RacingProcedureType;
@@ -18,6 +19,7 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
private RRS26Configuration rrs26Configuration; private RRS26Configuration rrs26Configuration;
private GateStartConfiguration gateStartConfiguration; private GateStartConfiguration gateStartConfiguration;
private ESSConfiguration essConfiguration; private ESSConfiguration essConfiguration;
private LeagueConfiguration leagueConfiguration;
private RacingProcedureConfiguration basicConfiguration; private RacingProcedureConfiguration basicConfiguration;
@Override @Override
@@ -65,6 +67,15 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
this.essConfiguration = essConfiguration; this.essConfiguration = essConfiguration;
} }
@Override
public LeagueConfiguration getLeagueConfiguration() {
return leagueConfiguration;
}
public void setLeagueConfiguration(LeagueConfiguration leagueConfiguration) {
this.leagueConfiguration = leagueConfiguration;
}
@Override @Override
public RacingProcedureConfiguration getBasicConfiguration() { public RacingProcedureConfiguration getBasicConfiguration() {
return basicConfiguration; return basicConfiguration;
@@ -83,6 +94,7 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
copy.setGateStartConfiguration(gateStartConfiguration); copy.setGateStartConfiguration(gateStartConfiguration);
copy.setESSConfiguration(essConfiguration); copy.setESSConfiguration(essConfiguration);
copy.setBasicConfiguration(basicConfiguration); copy.setBasicConfiguration(basicConfiguration);
copy.setLeagueConfiguration(leagueConfiguration);
return copy; return copy;
} }
@@ -112,6 +124,10 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
target.setBasicConfiguration( target.setBasicConfiguration(
(RacingProcedureConfiguration) target.getBasicConfiguration().merge(update.getBasicConfiguration())); (RacingProcedureConfiguration) target.getBasicConfiguration().merge(update.getBasicConfiguration()));
} }
if (update.getLeagueConfiguration() != null) {
target.setLeagueConfiguration(
(LeagueConfiguration) target.getLeagueConfiguration().merge(update.getLeagueConfiguration()));
}
return target; 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); 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 // 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. // 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.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.leaderboard.ScoringScheme; 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.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier; import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
import com.sap.sailing.domain.regattalike.RegattaLikeListener; import com.sap.sailing.domain.regattalike.RegattaLikeListener;
@@ -904,4 +905,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return 0; 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.Wind;
import com.sap.sailing.domain.common.WindSource; import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType; 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.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
@@ -591,12 +592,12 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
public GPSFixTrack<Mark, GPSFix> getTrack(Mark mark) { public GPSFixTrack<Mark, GPSFix> getTrack(Mark mark) {
return null; return null;
} }
@Override @Override
public long getGateStartGolfDownTime() { public long getGateStartGolfDownTime() {
return 0; return 0;
} }
@Override @Override
public boolean isUsingMarkPassingCalculator() { public boolean isUsingMarkPassingCalculator() {
// TODO Auto-generated method stub // TODO Auto-generated method stub
@@ -608,5 +609,9 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return 0; 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.impl,
com.sap.sailing.domain.markpassingcalculation.splining, com.sap.sailing.domain.markpassingcalculation.splining,
com.sap.sailing.domain.masterdataimport, com.sap.sailing.domain.masterdataimport,
com.sap.sailing.domain.polars,
com.sap.sailing.domain.racelog, com.sap.sailing.domain.racelog,
com.sap.sailing.domain.racelog.impl, com.sap.sailing.domain.racelog.impl,
com.sap.sailing.domain.racelog.tracking, 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.datamining.shared,
com.sap.sse.common, com.sap.sse.common,
com.sap.sse, 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.base.BoatClass;
import com.sap.sailing.domain.common.Bearing; 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 { 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.Set;
import java.util.concurrent.ExecutionException; 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.PolarSheetsData;
import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.Tack; 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.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.TrackedRace; 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; import com.sap.sse.common.Util.Pair;
/** /**
@@ -206,7 +205,28 @@ public interface PolarDataService {
*/ */
PolynomialFunction getSpeedRegressionFunction(BoatClass boatClass, double trueWindAngle) throws NotEnoughDataHasBeenAddedException; 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); 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.dto.TrackedRaceDTO;
import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.common.racelog.RacingProcedureType; 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.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
@@ -770,4 +771,6 @@ public interface TrackedRace extends Serializable {
boolean isUsingMarkPassingCalculator(); 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.ConfidenceBasedWindAverager;
import com.sap.sailing.domain.confidence.ConfidenceFactory; import com.sap.sailing.domain.confidence.ConfidenceFactory;
import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator; 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.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.racelogtracking.DeviceMapping; import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack; import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
@@ -317,6 +319,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
*/ */
private transient ShortTimeWindCache shortTimeWindCache; private transient ShortTimeWindCache shortTimeWindCache;
private transient PolarDataService polarDataService;
public TrackedRaceImpl(final TrackedRegatta trackedRegatta, RaceDefinition race, public TrackedRaceImpl(final TrackedRegatta trackedRegatta, RaceDefinition race,
final Iterable<Sideline> sidelines, final WindStore windStore, final GPSFixStore gpsFixStore, final Iterable<Sideline> sidelines, final WindStore windStore, final GPSFixStore gpsFixStore,
long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind, long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind,
@@ -407,7 +411,6 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
windTracks.putAll(loadedWindTracks); windTracks.putAll(loadedWindTracks);
updateEventTimePoints(loadedWindTracks.values()); updateEventTimePoints(loadedWindTracks.values());
logger.info("Finished loading wind tracks for " + getRace().getName() + ". Found " + windTracks.size() + " wind tracks for this race."); logger.info("Finished loading wind tracks for " + getRace().getName() + ". Found " + windTracks.size() + " wind tracks for this race.");
} finally { } finally {
synchronized (TrackedRaceImpl.this) { synchronized (TrackedRaceImpl.this) {
loadingFromWindStoreState = LoadingFromStoresState.FINISHED; loadingFromWindStoreState = LoadingFromStoresState.FINISHED;
@@ -1861,40 +1864,66 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
BearingWithConfidence<TimePoint> resultBearing = null; BearingWithConfidence<TimePoint> resultBearing = null;
ScalablePosition scaledPosition = null; ScalablePosition scaledPosition = null;
int numberOfFixesConsideredForScaledPosition = 0; int numberOfFixesConsideredForScaledPosition = 0;
Set<WindSource> estimationExcluded = new HashSet<>();
estimationExcluded.addAll(getWindSources(WindSourceType.TRACK_BASED_ESTIMATION));
estimationExcluded.addAll(getWindSources(WindSourceType.COURSE_BASED));
if (bearings != null) { if (bearings != null) {
BearingWithConfidenceCluster<TimePoint>[] bearingClustersUpwind = bearings.get(LegType.UPWIND).getA().splitInTwo( int numberOfFixesUpwind = bearings.get(LegType.UPWIND).getA().size();
getMinimumAngleBetweenDifferentTacksUpwind(), timePoint); if (numberOfFixesUpwind > 0) {
if (!bearingClustersUpwind[0].isEmpty() && !bearingClustersUpwind[1].isEmpty()) { ScalablePosition upwindPosition = bearings.get(LegType.UPWIND).getB();
BearingWithConfidence<TimePoint> average0 = bearingClustersUpwind[0].getAverage(timePoint); Pair<Double, Double> minimumAngleBetweenDifferentTacksUpwindWithConfidence = getMinimumAngleBetweenDifferentTacksUpwind(getWind(
BearingWithConfidence<TimePoint> average1 = bearingClustersUpwind[1].getAverage(timePoint); upwindPosition.divide(numberOfFixesUpwind), timePoint, estimationExcluded));
upwindNumberOfRelevantBoats = Math BearingWithConfidenceCluster<TimePoint>[] bearingClustersUpwind = bearings
.min(bearingClustersUpwind[0].size(), bearingClustersUpwind[1].size()); .get(LegType.UPWIND)
confidence = Math.min(average0.getConfidence(), average1.getConfidence()) .getA()
* getRace().getBoatClass().getUpwindWindEstimationConfidence(upwindNumberOfRelevantBoats); .splitInTwo(
reversedUpwindAverage = new BearingWithConfidenceImpl<TimePoint>(average0.getObject() minimumAngleBetweenDifferentTacksUpwindWithConfidence.getA(),
.middle(average1.getObject()).reverse(), confidence, timePoint); timePoint);
scaledPosition = bearings.get(LegType.UPWIND).getB(); if (!bearingClustersUpwind[0].isEmpty() && !bearingClustersUpwind[1].isEmpty()) {
numberOfFixesConsideredForScaledPosition += bearings.get(LegType.UPWIND).getA().size(); BearingWithConfidence<TimePoint> average0 = bearingClustersUpwind[0].getAverage(timePoint);
BearingWithConfidence<TimePoint> average1 = bearingClustersUpwind[1].getAverage(timePoint);
upwindNumberOfRelevantBoats = Math.min(bearingClustersUpwind[0].size(),
bearingClustersUpwind[1].size());
confidence = Math.min(average0.getConfidence(), average1.getConfidence())
* getRace().getBoatClass().getUpwindWindEstimationConfidence(upwindNumberOfRelevantBoats)
* minimumAngleBetweenDifferentTacksUpwindWithConfidence.getB();
reversedUpwindAverage = new BearingWithConfidenceImpl<TimePoint>(average0.getObject()
.middle(average1.getObject()).reverse(), confidence, timePoint);
scaledPosition = upwindPosition;
numberOfFixesConsideredForScaledPosition += bearings.get(LegType.UPWIND).getA().size();
}
} }
BearingWithConfidenceImpl<TimePoint> downwindAverage = null; BearingWithConfidenceImpl<TimePoint> downwindAverage = null;
int downwindNumberOfRelevantBoats = 0; int downwindNumberOfRelevantBoats = 0;
BearingWithConfidenceCluster<TimePoint>[] bearingClustersDownwind = bearings.get(LegType.DOWNWIND).getA() int numberOfFixesDownwind = bearings.get(LegType.DOWNWIND).getA().size();
.splitInTwo(getMinimumAngleBetweenDifferentTacksDownwind(), timePoint); if (numberOfFixesDownwind > 0) {
if (!bearingClustersDownwind[0].isEmpty() && !bearingClustersDownwind[1].isEmpty()) { ScalablePosition downwindPosition = bearings.get(LegType.DOWNWIND).getB();
BearingWithConfidence<TimePoint> average0 = bearingClustersDownwind[0].getAverage(timePoint); Pair<Double, Double> minimumAngleBetweenDifferentTacksDownwindWithConfidence = getMinimumAngleBetweenDifferentTacksDownwind(getWind(
BearingWithConfidence<TimePoint> average1 = bearingClustersDownwind[1].getAverage(timePoint); downwindPosition.divide(numberOfFixesDownwind), timePoint, estimationExcluded));
downwindNumberOfRelevantBoats = Math.min(bearingClustersDownwind[0].size(), BearingWithConfidenceCluster<TimePoint>[] bearingClustersDownwind = bearings
bearingClustersDownwind[1].size()); .get(LegType.DOWNWIND)
confidence = Math.min(average0.getConfidence(), average1.getConfidence()) .getA()
* getRace().getBoatClass().getDownwindWindEstimationConfidence(downwindNumberOfRelevantBoats); .splitInTwo(
downwindAverage = new BearingWithConfidenceImpl<TimePoint>(average0.getObject().middle( minimumAngleBetweenDifferentTacksDownwindWithConfidence.getA(),
average1.getObject()), confidence, timePoint); timePoint);
if (scaledPosition == null) { if (!bearingClustersDownwind[0].isEmpty() && !bearingClustersDownwind[1].isEmpty()) {
scaledPosition = bearings.get(LegType.DOWNWIND).getB(); BearingWithConfidence<TimePoint> average0 = bearingClustersDownwind[0].getAverage(timePoint);
} else { BearingWithConfidence<TimePoint> average1 = bearingClustersDownwind[1].getAverage(timePoint);
scaledPosition.add(bearings.get(LegType.DOWNWIND).getB()); downwindNumberOfRelevantBoats = Math.min(bearingClustersDownwind[0].size(),
bearingClustersDownwind[1].size());
confidence = Math.min(average0.getConfidence(), average1.getConfidence())
* getRace().getBoatClass().getDownwindWindEstimationConfidence(
downwindNumberOfRelevantBoats)
* minimumAngleBetweenDifferentTacksDownwindWithConfidence.getB();
downwindAverage = new BearingWithConfidenceImpl<TimePoint>(average0.getObject().middle(
average1.getObject()), confidence, timePoint);
if (scaledPosition == null) {
scaledPosition = downwindPosition;
} else {
scaledPosition.add(downwindPosition);
}
numberOfFixesConsideredForScaledPosition += bearings.get(LegType.DOWNWIND).getA().size();
} }
numberOfFixesConsideredForScaledPosition += bearings.get(LegType.DOWNWIND).getA().size();
} }
BearingWithConfidenceCluster<TimePoint> resultCluster = new BearingWithConfidenceCluster<TimePoint>(weigher); BearingWithConfidenceCluster<TimePoint> resultCluster = new BearingWithConfidenceCluster<TimePoint>(weigher);
assert upwindNumberOfRelevantBoats == 0 || reversedUpwindAverage != null; assert upwindNumberOfRelevantBoats == 0 || reversedUpwindAverage != null;
@@ -2716,12 +2745,41 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
return getRace().getBoatClass().getManeuverDegreeAngleThreshold(); return getRace().getBoatClass().getManeuverDegreeAngleThreshold();
} }
private double getMinimumAngleBetweenDifferentTacksDownwind() { private Pair<Double, Double> getMinimumAngleBetweenDifferentTacksDownwind(Wind wind) {
return getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksDownwind(); Pair<Double, Double> result;
double defaultAngle = getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksDownwind();
double threshold = 20;
result = usePolarsIfPossible(wind, defaultAngle, LegType.DOWNWIND, threshold);
return result;
}
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 double getMinimumAngleBetweenDifferentTacksUpwind() { private Pair<Double, Double> usePolarsIfPossible(Wind wind, double defaultAngle, LegType legType, double threshold) {
return getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksUpwind(); 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() { private long getApproximateManeuverDurationInMilliseconds() {
@@ -2880,7 +2938,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
(DynamicGPSFixTrack<Competitor, GPSFixMoving>) tracks.get(competitor), log, (DynamicGPSFixTrack<Competitor, GPSFixMoving>) tracks.get(competitor), log,
competitor); competitor);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) { } 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()); 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, gpsFixStore.loadMarkTrack((DynamicGPSFixTrack<Mark, GPSFix>) markTracks.get(mark), log,
mark); mark);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) { } 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()); logger.info("Finished loading mark tracks for " + getRace().getName());
@@ -3456,5 +3514,10 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
} }
return result; 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" version="0.0.0"
unpack="false"/> unpack="false"/>
<plugin
id="com.sap.sailing.polars"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
</feature> </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.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.leaderboard.ScoringScheme; 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.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier; import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
import com.sap.sailing.domain.regattalike.RegattaLikeListener; import com.sap.sailing.domain.regattalike.RegattaLikeListener;
@@ -902,4 +903,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return 0; return 0;
} }
@Override
public void setPolarDataService(PolarDataService polarDataService) {
}
} }
@@ -50,10 +50,7 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sse.gwt.theme com.sap.sse.gwt.theme
Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Import-Package: com.sap.sailing.polars, Import-Package: javax.jms;version="1.1.0",
com.sap.sailing.polars.factory,
com.sap.sailing.polars.regression,
javax.jms;version="1.1.0",
javax.servlet;version="3.1.0", javax.servlet;version="3.1.0",
javax.servlet.descriptor;version="3.1.0", javax.servlet.descriptor;version="3.1.0",
javax.servlet.http;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 overview();
String sapSailing(); String sapSailing();
String search(); String search();
String startSimulator();
String countdownDays(); String countdownDays();
String countdownHours(); String countdownHours();
@@ -33,6 +33,7 @@ whatsNew=What''s new
overview=Overview overview=Overview
sapSailing=SAP Sailing sapSailing=SAP Sailing
search=Search search=Search
startSimulator=Start Simulator
countdownDays=Days countdownDays=Days
countdownHours=Hrs countdownHours=Hrs
@@ -33,6 +33,7 @@ whatsNew=Neuigkeiten
overview=Übersicht overview=Übersicht
sapSailing=SAP Sailing sapSailing=SAP Sailing
search=Suche search=Suche
startSimulator=Simulator starten
countdownDays=Tage countdownDays=Tage
countdownHours=Std. countdownHours=Std.
@@ -1,5 +1,8 @@
package com.sap.sailing.gwt.home.client.app; 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.google.gwt.place.shared.PlaceController;
import com.sap.sailing.gwt.home.client.place.aboutus.AboutUsPlace; import com.sap.sailing.gwt.home.client.place.aboutus.AboutUsPlace;
import com.sap.sailing.gwt.home.client.place.contact.ContactPlace; 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.start.StartPlace;
import com.sap.sailing.gwt.home.client.place.whatsnew.WhatsNewPlace; 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.home.client.place.whatsnew.WhatsNewPlace.WhatsNewNavigationTabs;
import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory;
public class HomePlacesNavigator extends AbstractPlaceNavigator { public class HomePlacesNavigator extends AbstractPlaceNavigator {
@@ -42,6 +46,11 @@ public class HomePlacesNavigator extends AbstractPlaceNavigator {
return createLocalPlaceNavigation(new WhatsNewPlace(navigationTab)); return createLocalPlaceNavigation(new WhatsNewPlace(navigationTab));
} }
public String getSimulatorURL() {
Map<String, String> parameters = new HashMap<String, String>();
return EntryPointLinkFactory.createSimulatorLink(parameters);
}
public PlaceNavigation<SponsoringPlace> getSponsoringNavigation() { public PlaceNavigation<SponsoringPlace> getSponsoringNavigation() {
return createGlobalPlaceNavigation(new SponsoringPlace()); 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); private static final HyperlinkImpl HYPERLINK_IMPL = GWT.create(HyperlinkImpl.class);
@UiField HTML sailingAnalyticsNotes; @UiField HTML sailingAnalyticsNotes;
// @UiField HTML sailingSimulatorNotes; @UiField HTML sailingSimulatorNotes;
@UiField HTML raceCommitteeAppNotes; @UiField HTML raceCommitteeAppNotes;
@UiField Anchor sailingAnalyticsNotesAnchor; @UiField Anchor sailingAnalyticsNotesAnchor;
// @UiField Anchor sailingSimulatorNotesAnchor; @UiField Anchor sailingSimulatorNotesAnchor;
@UiField Anchor raceCommitteeAppNotesAnchor; @UiField Anchor raceCommitteeAppNotesAnchor;
private final PlaceNavigation<WhatsNewPlace> sailingAnalyticNotesNavigation; private final PlaceNavigation<WhatsNewPlace> sailingAnalyticNotesNavigation;
// private final PlaceNavigation<WhatsNewPlace> sailingSimulatorNoteNavigation; private final PlaceNavigation<WhatsNewPlace> sailingSimulatorNoteNavigation;
private final PlaceNavigation<WhatsNewPlace> raceCommitteeAppNotesNavigation; private final PlaceNavigation<WhatsNewPlace> raceCommitteeAppNotesNavigation;
private final List<Anchor> links; private final List<Anchor> links;
@@ -49,19 +49,19 @@ public class TabletAndDesktopWhatsNewView extends Composite implements WhatsNewV
initWidget(uiBinder.createAndBindUi(this)); initWidget(uiBinder.createAndBindUi(this));
sailingAnalyticsNotes.setHTML(WhatsNewResources.INSTANCE.getSailingAnalyticsNotesHtml().getText()); sailingAnalyticsNotes.setHTML(WhatsNewResources.INSTANCE.getSailingAnalyticsNotesHtml().getText());
// sailingSimulatorNotes.setHTML(WhatsNewResources.INSTANCE.getSailingSimulatorNotesHtml().getText()); sailingSimulatorNotes.setHTML(WhatsNewResources.INSTANCE.getSailingSimulatorNotesHtml().getText());
raceCommitteeAppNotes.setHTML(WhatsNewResources.INSTANCE.getRaceCommitteeAppNotesHtml().getText()); raceCommitteeAppNotes.setHTML(WhatsNewResources.INSTANCE.getRaceCommitteeAppNotesHtml().getText());
sailingAnalyticNotesNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingAnalytics); sailingAnalyticNotesNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingAnalytics);
// sailingSimulatorNoteNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingSimulator); sailingSimulatorNoteNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingSimulator);
raceCommitteeAppNotesNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.RaceCommiteeApp); raceCommitteeAppNotesNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.RaceCommiteeApp);
sailingAnalyticsNotesAnchor.setHref(sailingAnalyticNotesNavigation.getTargetUrl()); sailingAnalyticsNotesAnchor.setHref(sailingAnalyticNotesNavigation.getTargetUrl());
// sailingSimulatorNotesAnchor.setHref(sailingSimulatorNoteNavigation.getTargetUrl()); sailingSimulatorNotesAnchor.setHref(sailingSimulatorNoteNavigation.getTargetUrl());
raceCommitteeAppNotesAnchor.setHref(raceCommitteeAppNotesNavigation.getTargetUrl()); raceCommitteeAppNotesAnchor.setHref(raceCommitteeAppNotesNavigation.getTargetUrl());
links = Arrays.asList(new Anchor[] { sailingAnalyticsNotesAnchor, /*sailingSimulatorNotesAnchor,*/ raceCommitteeAppNotesAnchor }); links = Arrays.asList(new Anchor[] { sailingAnalyticsNotesAnchor, sailingSimulatorNotesAnchor, raceCommitteeAppNotesAnchor });
contentWidgets = Arrays.asList(new HTML[] { sailingAnalyticsNotes, /*sailingSimulatorNotes,*/ raceCommitteeAppNotes }); contentWidgets = Arrays.asList(new HTML[] { sailingAnalyticsNotes, sailingSimulatorNotes, raceCommitteeAppNotes });
switch(navigationTab) { switch(navigationTab) {
case PostRaceAnalytics: case PostRaceAnalytics:
@@ -73,7 +73,7 @@ public class TabletAndDesktopWhatsNewView extends Composite implements WhatsNewV
setActiveContent(sailingAnalyticsNotes, sailingAnalyticsNotesAnchor); setActiveContent(sailingAnalyticsNotes, sailingAnalyticsNotesAnchor);
break; break;
case SailingSimulator: case SailingSimulator:
// setActiveContent(sailingSimulatorNotes, sailingSimulatorNotesAnchor); setActiveContent(sailingSimulatorNotes, sailingSimulatorNotesAnchor);
break; break;
case TrainingDiary: case TrainingDiary:
break; break;
@@ -85,13 +85,13 @@ public class TabletAndDesktopWhatsNewView extends Composite implements WhatsNewV
setActiveContent(sailingAnalyticsNotes, sailingAnalyticsNotesAnchor); setActiveContent(sailingAnalyticsNotes, sailingAnalyticsNotesAnchor);
handleClickEventWithLocalNavigation(event, sailingAnalyticNotesNavigation); handleClickEventWithLocalNavigation(event, sailingAnalyticNotesNavigation);
} }
/*
@UiHandler("sailingSimulatorNotesAnchor") @UiHandler("sailingSimulatorNotesAnchor")
void featuresClicked(ClickEvent event) { void featuresClicked(ClickEvent event) {
setActiveContent(sailingSimulatorNotes, sailingSimulatorNotesAnchor); setActiveContent(sailingSimulatorNotes, sailingSimulatorNotesAnchor);
handleClickEventWithLocalNavigation(event, sailingSimulatorNoteNavigation); handleClickEventWithLocalNavigation(event, sailingSimulatorNoteNavigation);
} }
*/
@UiHandler("raceCommitteeAppNotesAnchor") @UiHandler("raceCommitteeAppNotesAnchor")
void releaseNotesClicked(ClickEvent event) { void releaseNotesClicked(ClickEvent event) {
setActiveContent(raceCommitteeAppNotes, raceCommitteeAppNotesAnchor); setActiveContent(raceCommitteeAppNotes, raceCommitteeAppNotesAnchor);
@@ -10,9 +10,7 @@
<div class="{res.mediaCss.grid}"> <div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.columns}"> <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="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="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> <g:Anchor ui:field="raceCommitteeAppNotesAnchor" href="javascript:;" styleName="{local_res.css.whatsnew_nav_link}"><ui:text from='{i18n.solutionsRaceHeadline}'/></g:Anchor>
</div> </div>
</div> </div>
@@ -20,9 +18,7 @@
<div class="{res.mediaCss.grid}"> <div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small12} {res.mediaCss.columns}"> <div class="{res.mediaCss.small12} {res.mediaCss.columns}">
<g:HTML ui:field="sailingAnalyticsNotes" /> <g:HTML ui:field="sailingAnalyticsNotes" />
<!--
<g:HTML ui:field="sailingSimulatorNotes" /> <g:HTML ui:field="sailingSimulatorNotes" />
-->
<g:HTML ui:field="raceCommitteeAppNotes" /> <g:HTML ui:field="raceCommitteeAppNotes" />
</div> </div>
</div> </div>
@@ -44,6 +44,8 @@ public class Solutions extends Composite {
@UiField Anchor sailingAnalyticsDetailsAnchor; @UiField Anchor sailingAnalyticsDetailsAnchor;
@UiField Anchor raceCommitteeAppDetailsAnchor; @UiField Anchor raceCommitteeAppDetailsAnchor;
@UiField Anchor simulatorStartAnchor;
@UiField Anchor simulatorAppDetailsAnchor;
private final PlaceNavigation<SolutionsPlace> sailingAnalyticsNavigation; private final PlaceNavigation<SolutionsPlace> sailingAnalyticsNavigation;
private final PlaceNavigation<SolutionsPlace> raceCommitteeAppNavigation; private final PlaceNavigation<SolutionsPlace> raceCommitteeAppNavigation;
@@ -55,6 +57,7 @@ public class Solutions extends Composite {
private final PlaceNavigation<WhatsNewPlace> sailingAnalyticsDetailsNavigation; private final PlaceNavigation<WhatsNewPlace> sailingAnalyticsDetailsNavigation;
private final PlaceNavigation<WhatsNewPlace> raceCommitteeAppDetailsNavigation; private final PlaceNavigation<WhatsNewPlace> raceCommitteeAppDetailsNavigation;
private final PlaceNavigation<WhatsNewPlace> simulatorAppDetailsNavigation;
private final HomePlacesNavigator placesNavigator; private final HomePlacesNavigator placesNavigator;
public Solutions(SolutionsNavigationTabs navigationTab, HomePlacesNavigator placesNavigator) { public Solutions(SolutionsNavigationTabs navigationTab, HomePlacesNavigator placesNavigator) {
@@ -67,9 +70,12 @@ public class Solutions extends Composite {
sailingAnalyticsDetailsNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingAnalytics); sailingAnalyticsDetailsNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingAnalytics);
raceCommitteeAppDetailsNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.RaceCommiteeApp); raceCommitteeAppDetailsNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.RaceCommiteeApp);
simulatorAppDetailsNavigation = placesNavigator.getWhatsNewNavigation(WhatsNewNavigationTabs.SailingSimulator);
sailingAnalyticsDetailsAnchor.setHref(sailingAnalyticsDetailsNavigation.getTargetUrl()); sailingAnalyticsDetailsAnchor.setHref(sailingAnalyticsDetailsNavigation.getTargetUrl());
raceCommitteeAppDetailsAnchor.setHref(raceCommitteeAppDetailsNavigation.getTargetUrl()); raceCommitteeAppDetailsAnchor.setHref(raceCommitteeAppDetailsNavigation.getTargetUrl());
simulatorAppDetailsAnchor.setHref(simulatorAppDetailsNavigation.getTargetUrl());
simulatorStartAnchor.setHref(placesNavigator.getSimulatorURL());
sailingAnalyticsNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.SailingAnalytics); sailingAnalyticsNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.SailingAnalytics);
raceCommitteeAppNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.RaceCommiteeApp); raceCommitteeAppNavigation = placesNavigator.getSolutionsNavigation(SolutionsNavigationTabs.RaceCommiteeApp);
@@ -127,7 +133,12 @@ public class Solutions extends Composite {
public void sailingAnalyticsDetailsClicked(ClickEvent e) { public void sailingAnalyticsDetailsClicked(ClickEvent e) {
handleClickEventWithPlaceController(e, sailingAnalyticsDetailsNavigation); handleClickEventWithPlaceController(e, sailingAnalyticsDetailsNavigation);
} }
@UiHandler("simulatorAppDetailsAnchor")
public void simulatorAppDetailsAnchorClicked(ClickEvent e) {
handleClickEventWithPlaceController(e, simulatorAppDetailsNavigation);
}
private void scrollToView(SolutionsNavigationTabs navigationTab) { private void scrollToView(SolutionsNavigationTabs navigationTab) {
switch (navigationTab) { switch (navigationTab) {
case SailingAnalytics: case SailingAnalytics:
@@ -67,7 +67,9 @@
<div class="{res.mediaCss.small5} {res.mediaCss.smalloffset7} {res.mediaCss.columns}"> <div class="{res.mediaCss.small5} {res.mediaCss.smalloffset7} {res.mediaCss.columns}">
<h2><ui:text from='{i18n.solutionsSimulatorHeadline}'/></h2> <h2><ui:text from='{i18n.solutionsSimulatorHeadline}'/></h2>
<p><ui:text from='{i18n.solutionsSimulatorText}'/></p> <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> </div>
</div> </div>
@@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.google.gwt.user.client.rpc.AsyncCallback; 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.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.CompetitorDTO; import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync; 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 Map<CompetitorDTO, Date> to;
private final boolean extrapolate; private final boolean extrapolate;
private final Date date; private final Date date;
private final LegIdentifier simulationLegIdentifier;
public GetRaceMapDataAction(SailingServiceAsync sailingService, Iterable<CompetitorDTO> allCompetitors, public GetRaceMapDataAction(SailingServiceAsync sailingService, Iterable<CompetitorDTO> allCompetitors,
RegattaAndRaceIdentifier raceIdentifier, Date date, Map<CompetitorDTO, Date> from, 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.allCompetitors = allCompetitors;
this.sailingService = sailingService; this.sailingService = sailingService;
this.raceIdentifier = raceIdentifier; this.raceIdentifier = raceIdentifier;
@@ -31,6 +33,7 @@ public class GetRaceMapDataAction implements AsyncAction<RaceMapDataDTO> {
this.from = from; this.from = from;
this.to = to; this.to = to;
this.extrapolate = extrapolate; this.extrapolate = extrapolate;
this.simulationLegIdentifier = simulationLegIdentifier;
} }
@Override @Override
@@ -46,7 +49,7 @@ public class GetRaceMapDataAction implements AsyncAction<RaceMapDataDTO> {
} }
sailingService.getRaceMapData(raceIdentifier, date, fromByCompetitorIdAsString, toByCompetitorIdAsString, sailingService.getRaceMapData(raceIdentifier, date, fromByCompetitorIdAsString, toByCompetitorIdAsString,
extrapolate, new AsyncCallback<CompactRaceMapDataDTO>() { extrapolate, simulationLegIdentifier, new AsyncCallback<CompactRaceMapDataDTO>() {
@Override @Override
public void onFailure(Throwable caught) { public void onFailure(Throwable caught) {
callback.onFailure(caught); callback.onFailure(caught);
@@ -1,12 +1,11 @@
package com.sap.sailing.gwt.ui.actions; package com.sap.sailing.gwt.ui.actions;
import java.util.Date;
import com.google.gwt.user.client.rpc.AsyncCallback; 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.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMap; 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.SimulatorResultsDTO;
import com.sap.sailing.gwt.ui.shared.racemap.RaceSimulationOverlay;
import com.sap.sse.gwt.client.async.AsyncAction; 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> { public class GetSimulationAction implements AsyncAction<SimulatorResultsDTO> {
private final SailingServiceAsync sailingService; private final SailingServiceAsync sailingService;
private final RegattaAndRaceIdentifier raceIdentifier; private final LegIdentifier legIdentifier;
private final Date from;
private final Date prevStartTime;
public GetSimulationAction(SailingServiceAsync sailingService, RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime) { public GetSimulationAction(SailingServiceAsync sailingService, LegIdentifier legIdentifier) {
this.sailingService = sailingService; this.sailingService = sailingService;
this.raceIdentifier = raceIdentifier; this.legIdentifier = legIdentifier;
this.from = from;
this.prevStartTime = prevStartTime;
} }
@Override @Override
public void execute(AsyncCallback<SimulatorResultsDTO> callback) { 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 sailId;
private final TextBox email; private final TextBox email;
private final StringMessages stringMessages; private final StringMessages stringMessages;
private final TextBox flagImageURL; private final URLFieldWithFileUpload flagImageURL;
private final URLFieldWithFileUpload imageUrlAndUploadComposite; private final URLFieldWithFileUpload imageUrlAndUploadComposite;
public CompetitorEditDialog(final StringMessages stringMessages, CompetitorDTO competitorToEdit, public CompetitorEditDialog(final StringMessages stringMessages, CompetitorDTO competitorToEdit,
@@ -123,12 +123,12 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> {
} }
} }
this.sailId = createTextBox(competitorToEdit.getSailID()); this.sailId = createTextBox(competitorToEdit.getSailID());
this.flagImageURL = createTextBox(competitorToEdit.getFlagImageURL(), 100); this.flagImageURL = new URLFieldWithFileUpload(stringMessages);
imageUrlAndUploadComposite = new URLFieldWithFileUpload(stringMessages); this.flagImageURL.setURL(competitorToEdit.getFlagImageURL());
imageUrlAndUploadComposite.setURL(competitorToEdit.getImageURL()); this.imageUrlAndUploadComposite = new URLFieldWithFileUpload(stringMessages);
this.imageUrlAndUploadComposite.setURL(competitorToEdit.getImageURL());
} }
@Override @Override
public void show() { public void show() {
super.show(); super.show();
@@ -182,7 +182,7 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> {
/* twoLetterIsoCountryCode */ null, /* twoLetterIsoCountryCode */ null,
threeLetterIocCountryCode.getValue(threeLetterIocCountryCode.getSelectedIndex()), threeLetterIocCountryCode.getValue(threeLetterIocCountryCode.getSelectedIndex()),
/* countryName */ null, sailId.getText(), competitorToEdit.getIdAsString(), /* countryName */ null, sailId.getText(), competitorToEdit.getIdAsString(),
imageUrlAndUploadComposite.getURL(), flagImageURL.getText(), boatClass); imageUrlAndUploadComposite.getURL(), flagImageURL.getURL(), boatClass);
return result; return result;
} }
@@ -60,6 +60,11 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
private ListBox basicClassFlagListBox; private ListBox basicClassFlagListBox;
private CheckBox basicRecallBox; private CheckBox basicRecallBox;
private DisclosurePanel leagueDisclosurePanel;
private CheckBox leagueEnabledBox;
private ListBox leagueClassFlagListBox;
private CheckBox leagueRecallBox;
public RegattaConfigurationDialog(DeviceConfigurationDTO.RegattaConfigurationDTO regattaConfiguration, public RegattaConfigurationDialog(DeviceConfigurationDTO.RegattaConfigurationDTO regattaConfiguration,
StringMessages messages, DataEntryDialog.DialogCallback<RegattaConfigurationDTO> callback) { StringMessages messages, DataEntryDialog.DialogCallback<RegattaConfigurationDTO> callback) {
super(messages.racingProcedureConfiguration(), "", messages.save(), messages.cancel(), /* validator */ null, callback); super(messages.racingProcedureConfiguration(), "", messages.save(), messages.cancel(), /* validator */ null, callback);
@@ -75,6 +80,7 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
setupGateStart(); setupGateStart();
setupESS(); setupESS();
setupBasic(); setupBasic();
setupLeague();
if (rrs26EnabledBox.getValue()) { if (rrs26EnabledBox.getValue()) {
rrs26DisclosurePanel.setOpen(true); rrs26DisclosurePanel.setOpen(true);
@@ -88,6 +94,9 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
if (basicEnabledBox.getValue()) { if (basicEnabledBox.getValue()) {
basicDisclosurePanel.setOpen(true); basicDisclosurePanel.setOpen(true);
} }
if (leagueEnabledBox.getValue()) {
leagueDisclosurePanel.setOpen(true);
}
return contentPanel; return contentPanel;
} }
@@ -109,7 +118,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
racingProcedureListBox.addChangeHandler(new ChangeHandler() { racingProcedureListBox.addChangeHandler(new ChangeHandler() {
@Override @Override
public void onChange(ChangeEvent event) { public void onChange(ChangeEvent event) {
markAsDrity(true);
} }
}); });
grid.setWidget(gridRow, 0, new Label(stringMessages.racingProcedure())); grid.setWidget(gridRow, 0, new Label(stringMessages.racingProcedure()));
@@ -126,7 +134,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
designerModeEntryListBox.addChangeHandler(new ChangeHandler() { designerModeEntryListBox.addChangeHandler(new ChangeHandler() {
@Override @Override
public void onChange(ChangeEvent event) { public void onChange(ChangeEvent event) {
markAsDrity(true);
} }
}); });
grid.setWidget(gridRow, 0, new Label(stringMessages.courseDesignerMode())); grid.setWidget(gridRow, 0, new Label(stringMessages.courseDesignerMode()));
@@ -143,7 +150,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
box.addChangeHandler(new ChangeHandler() { box.addChangeHandler(new ChangeHandler() {
@Override @Override
public void onChange(ChangeEvent event) { public void onChange(ChangeEvent event) {
markAsDrity(true);
} }
}); });
return box; return box;
@@ -155,7 +161,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
@Override @Override
public void onValueChange(ValueChangeEvent<Boolean> event) { public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
} }
}); });
return box; return box;
@@ -170,7 +175,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
rrs26EnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() { rrs26EnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override @Override
public void onValueChange(ValueChangeEvent<Boolean> event) { public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
boolean isActive = event.getValue(); boolean isActive = event.getValue();
rrs26ClassFlagListBox.setEnabled(isActive); rrs26ClassFlagListBox.setEnabled(isActive);
rrs26RecallBox.setEnabled(isActive); rrs26RecallBox.setEnabled(isActive);
@@ -215,7 +219,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
rrs26StartModeFlagsBox.addChangeHandler(new ChangeHandler() { rrs26StartModeFlagsBox.addChangeHandler(new ChangeHandler() {
@Override @Override
public void onChange(ChangeEvent event) { public void onChange(ChangeEvent event) {
markAsDrity(true);
} }
}); });
} }
@@ -229,7 +232,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
gateStartEnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() { gateStartEnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override @Override
public void onValueChange(ValueChangeEvent<Boolean> event) { public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
gateStartClassFlagListBox.setEnabled(event.getValue()); gateStartClassFlagListBox.setEnabled(event.getValue());
gateStartRecallBox.setEnabled(event.getValue()); gateStartRecallBox.setEnabled(event.getValue());
gateStartPathfinderBox.setEnabled(event.getValue()); gateStartPathfinderBox.setEnabled(event.getValue());
@@ -244,14 +246,12 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
gateStartPathfinderBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() { gateStartPathfinderBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override @Override
public void onValueChange(ValueChangeEvent<Boolean> event) { public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
} }
}); });
gateStartGolfDownBox = createCheckbox(stringMessages.hasAdditionalGolfDownTime()); gateStartGolfDownBox = createCheckbox(stringMessages.hasAdditionalGolfDownTime());
gateStartGolfDownBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() { gateStartGolfDownBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override @Override
public void onValueChange(ValueChangeEvent<Boolean> event) { public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
} }
}); });
@@ -284,7 +284,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
essEnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() { essEnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override @Override
public void onValueChange(ValueChangeEvent<Boolean> event) { public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
essClassFlagListBox.setEnabled(event.getValue()); essClassFlagListBox.setEnabled(event.getValue());
essRecallBox.setEnabled(event.getValue()); essRecallBox.setEnabled(event.getValue());
} }
@@ -318,7 +317,6 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
basicEnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() { basicEnabledBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override @Override
public void onValueChange(ValueChangeEvent<Boolean> event) { public void onValueChange(ValueChangeEvent<Boolean> event) {
markAsDrity(true);
basicClassFlagListBox.setEnabled(event.getValue()); basicClassFlagListBox.setEnabled(event.getValue());
basicRecallBox.setEnabled(event.getValue()); basicRecallBox.setEnabled(event.getValue());
} }
@@ -343,8 +341,37 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
contentPanel.add(basicDisclosurePanel); contentPanel.add(basicDisclosurePanel);
} }
private void markAsDrity(boolean b) { private void setupLeague() {
// hmnn do we need to this? 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) { private Widget createHelpImage(String tooltip) {
@@ -399,6 +426,10 @@ public class RegattaConfigurationDialog extends DataEntryDialog<DeviceConfigurat
result.basicConfiguration = new DeviceConfigurationDTO.RegattaConfigurationDTO.RacingProcedureConfigurationDTO(); result.basicConfiguration = new DeviceConfigurationDTO.RegattaConfigurationDTO.RacingProcedureConfigurationDTO();
getRacingProcedureConfigurationResults(result.basicConfiguration, basicClassFlagListBox, basicRecallBox); getRacingProcedureConfigurationResults(result.basicConfiguration, basicClassFlagListBox, basicRecallBox);
} }
if (leagueEnabledBox.getValue()) {
result.leagueConfiguration = new DeviceConfigurationDTO.RegattaConfigurationDTO.LeagueConfigurationDTO();
getRacingProcedureConfigurationResults(result.leagueConfiguration, leagueClassFlagListBox, leagueRecallBox);
}
return result; return result;
} }
@@ -9,6 +9,10 @@ public class EntryPointLinkFactory extends AbstractEntryPointLinkFactory {
return createEntryPointLink("/gwt/RaceBoard.html", parameters); 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) { public static String createLeaderboardLink(Map<String, String> parameters) {
return createEntryPointLink("/gwt/Leaderboard.html", 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.DataImportProgress;
import com.sap.sailing.domain.common.DetailType; import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.LeaderboardType; 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.MaxPointsReason;
import com.sap.sailing.domain.common.NoWindException; import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.PassingInstruction; import com.sap.sailing.domain.common.PassingInstruction;
@@ -144,10 +145,10 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
boolean getPolarResults(RegattaAndRaceIdentifier raceIdentifier); 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, 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); 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.DataImportProgress;
import com.sap.sailing.domain.common.DetailType; import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.domain.common.LeaderboardType; 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.MaxPointsReason;
import com.sap.sailing.domain.common.PassingInstruction; import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.common.PolarSheetGenerationResponse; 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 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); 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. * identified by <code>raceIdentifier</code> will be used, considering that race's delay.
*/ */
void getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map<String, Date> fromPerCompetitorIdAsString, 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); void getReplicaInfo(AsyncCallback<ReplicationStateDTO> callback);
@@ -19,6 +19,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String wind(); String wind();
String windPanelLabel(); String windPanelLabel();
String refresh(); String refresh();
@Override
String remove(); String remove();
String windSource(); String windSource();
String dampeningInterval(); String dampeningInterval();
@@ -53,6 +54,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String linkToColumn(); String linkToColumn();
String unlink(); String unlink();
String leaderboardName(); String leaderboardName();
@Override
String cancel(); String cancel();
String pleaseEnterAName(); String pleaseEnterAName();
String pleaseEnterABoatClass(); String pleaseEnterABoatClass();
@@ -65,6 +67,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String renameLeaderboard(); String renameLeaderboard();
String addColumnToLeaderboard(); String addColumnToLeaderboard();
String pleaseEnterNameForNewRaceColumn(); String pleaseEnterNameForNewRaceColumn();
@Override
String ok(); String ok();
String medalRace(); String medalRace();
String renameRace(); String renameRace();
@@ -81,6 +84,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String leaderboard(); String leaderboard();
String leaderboards(); String leaderboards();
String leaderboardSettings(); String leaderboardSettings();
@Override
String settings(); String settings();
String linkedRaces(); String linkedRaces();
String selectAtLeastOneLegDetail(); String selectAtLeastOneLegDetail();
@@ -154,6 +158,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String penaltyCircles(); String penaltyCircles();
String medalRaceIsNull(); String medalRaceIsNull();
String maneuverTypes(); String maneuverTypes();
@Override
String configuration(); String configuration();
String chooseChart(); String chooseChart();
String distanceTraveled(); String distanceTraveled();
@@ -166,12 +171,14 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String in(); String in();
String secondsUnit(); String secondsUnit();
String metersUnit(); String metersUnit();
@Override
String close(); String close();
String compareCompetitors(); String compareCompetitors();
String description(); String description();
String sailNumber(); String sailNumber();
String country(); String country();
String no3LetterCodes(); String no3LetterCodes();
@Override
String add(); String add();
String delete(); String delete();
String showCharts(); String showCharts();
@@ -944,6 +951,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String pathfinderHelpText(); String pathfinderHelpText();
String essStart(); String essStart();
String basicStart(); String basicStart();
String leagueStart();
String configured(); String configured();
String overwriteRacingProceduresConfiguration(); String overwriteRacingProceduresConfiguration();
String overwriteRacingProceduresConfigurationHelpText(); String overwriteRacingProceduresConfigurationHelpText();
@@ -1141,9 +1149,13 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String enterRaceName(); String enterRaceName();
String enterCourseName(); String enterCourseName();
String scoringSchemeHighPointFirstGetsTenOrEightDescription(); String scoringSchemeHighPointFirstGetsTenOrEightDescription();
@Override
String serverError(); String serverError();
@Override
String remoteProcedureCall(); String remoteProcedureCall();
@Override
String serverReplies(); String serverReplies();
@Override
String errorCommunicatingWithServer(); String errorCommunicatingWithServer();
String userManagement(); String userManagement();
String structureImportUrls(); String structureImportUrls();
@@ -1191,10 +1203,15 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String sendingMailsSuccessful(); String sendingMailsSuccessful();
String selectEventForInvitation(); String selectEventForInvitation();
String imageURL(); String imageURL();
@Override
String upload(); String upload();
String removeResult(JSONValue status, JSONValue message); String removeResult(JSONValue status, JSONValue message);
@Override
String uploadSuccessful(); String uploadSuccessful();
String fileUploadResult(JSONValue status, JSONValue message); @Override
String fileUploadResult(String status, String message);
@Override
String removeUploadedImage();
String showCompetitorSailIdColumn(); String showCompetitorSailIdColumn();
String showCompetitorFullNameColumn(); String showCompetitorFullNameColumn();
String loadingDimensionValues(); String loadingDimensionValues();
@@ -924,6 +924,7 @@ activatePathfinder=Activate Pathfinder
pathfinderHelpText=When activated the Race Officer is able to set the Pathfinder boat. pathfinderHelpText=When activated the Race Officer is able to set the Pathfinder boat.
essStart=ESS Start essStart=ESS Start
basicStart=Basic Start basicStart=Basic Start
leagueStart=League Start
configured=Configured configured=Configured
overwriteRacingProceduresConfiguration=Activate regatta configuration overwriteRacingProceduresConfiguration=Activate regatta configuration
overwriteRacingProceduresConfigurationHelpText=Enabling this option will provide a base regatta configuration for all options unconfigured in the regatta-specific 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} removeResult=Remove operation: {0} {1}
uploadSuccessful=Upload successful uploadSuccessful=Upload successful
fileUploadResult=File upload: {0} {1}.\nIn case of error please check that your File Storage service is properly configured. 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 showCompetitorSailIdColumn=Show Competitor Sail Id
showCompetitorFullNameColumn=Show Competitor Full Name showCompetitorFullNameColumn=Show Competitor Full Name
loadingDimensionValues=Loading dimension values loadingDimensionValues=Loading dimension values
@@ -920,6 +920,7 @@ activatePathfinder=Aktiviere Pathfinder
pathfinderHelpText=Wenn aktiviert, ermöglicht dem Race Officer einen Pathfinder auszuwählen. pathfinderHelpText=Wenn aktiviert, ermöglicht dem Race Officer einen Pathfinder auszuwählen.
essStart=ESS Start essStart=ESS Start
basicStart=Basic Start basicStart=Basic Start
leagueStart=Liga Start
configured=Konfiguriert configured=Konfiguriert
overwriteRacingProceduresConfiguration=Aktivere Regattakonfiguration overwriteRacingProceduresConfiguration=Aktivere Regattakonfiguration
overwriteRacingProceduresConfigurationHelpText=Wenn aktiviert überschreibt jegliche Konfiguration der Rennarten durch eine Regatta. overwriteRacingProceduresConfigurationHelpText=Wenn aktiviert überschreibt jegliche Konfiguration der Rennarten durch eine Regatta.
@@ -1166,6 +1167,7 @@ upload=Hochladen
removeResult=Löschergebnis: {0} {1} removeResult=Löschergebnis: {0} {1}
uploadSuccessful=Hochladen erfolgreich uploadSuccessful=Hochladen erfolgreich
fileUploadResult=Ergebnis des Hochladens: {0} {1}\nIm Fehlerfall bitte die Konfiguration für "Datei Speicherung" prüfen. 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 showCompetitorSailIdColumn=Sail Id anzeigen
showCompetitorFullNameColumn=Vollen Namen anzeigen showCompetitorFullNameColumn=Vollen Namen anzeigen
loadingDimensionValues=Lade Dimensionswerte loadingDimensionValues=Lade Dimensionswerte
@@ -913,7 +913,8 @@ gateStart=Ворота старта
activatePathfinder=Активировать «Следопыт» activatePathfinder=Активировать «Следопыт»
pathfinderHelpText=После активации официальное лицо гонки может настроить судно «Следопыт». pathfinderHelpText=После активации официальное лицо гонки может настроить судно «Следопыт».
essStart=Старт ESS essStart=Старт ESS
basicStart=Основной старт basicStart=Основной старт
leagueStart=League Start
configured=Настроенный configured=Настроенный
overwriteRacingProceduresConfiguration=Активировать конфигурацию регаты overwriteRacingProceduresConfiguration=Активировать конфигурацию регаты
overwriteRacingProceduresConfigurationHelpText=Включение этой опции предоставляет базовую конфигурацию регаты для всех опций, не настроенных в специальной конфигурации регаты. overwriteRacingProceduresConfigurationHelpText=Включение этой опции предоставляет базовую конфигурацию регаты для всех опций, не настроенных в специальной конфигурации регаты.
@@ -1115,6 +1116,7 @@ upload=Upload
removeResult=Remove operation: {0} {1} removeResult=Remove operation: {0} {1}
uploadSuccessful=Upload successful uploadSuccessful=Upload successful
fileUploadResult=File upload: {0} {1}.\nIn case of error please check that your File Storage service is properly configured. 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 showCompetitorSailIdColumn=Show Competitor Sail Id
showCompetitorFullNameColumn=Show Competitor Full Name showCompetitorFullNameColumn=Show Competitor Full Name
loadingDimensionValues=Loading dimension values loadingDimensionValues=Loading dimension values
@@ -307,6 +307,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
private boolean isMapInitialized; private boolean isMapInitialized;
private Date lastTimeChangeBeforeInitialization; private Date lastTimeChangeBeforeInitialization;
private int lastLegNumber;
/** /**
* The last quick ranks received from a call to {@link SailingServiceAsync#getQuickRanks(RaceIdentifier, Date, AsyncCallback)} upon * The last quick ranks received from a call to {@link SailingServiceAsync#getQuickRanks(RaceIdentifier, Date, AsyncCallback)} upon
@@ -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 // 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 // supersedes the earlier call which may get dropped then
GetRaceMapDataAction getRaceMapDataAction = new GetRaceMapDataAction(sailingService, competitorSelection.getAllCompetitors(), race, 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, asyncActionsExecutor.execute(getRaceMapDataAction, GET_RACE_MAP_DATA_CATEGORY,
getRaceMapDataCallback(oldTime, newTime, fromAndToAndOverlap.getC(), competitorsToShow, requestID)); getRaceMapDataCallback(oldTime, newTime, fromAndToAndOverlap.getC(), competitorsToShow, requestID));
@@ -820,7 +822,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
final GetRaceMapDataAction result; final GetRaceMapDataAction result;
if (!fromTimes.isEmpty()) { if (!fromTimes.isEmpty()) {
result = new GetRaceMapDataAction(sailingService, competitorSelection.getAllCompetitors(), 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 { } else {
result = null; result = null;
} }
@@ -843,7 +845,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
if (map != null && raceMapDataDTO != null) { if (map != null && raceMapDataDTO != null) {
quickRanks = raceMapDataDTO.quickRanks; quickRanks = raceMapDataDTO.quickRanks;
if (showViewSimulation && settings.isShowSimulationOverlay()) { 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 // process response only if not received out of order
if (startedProcessingRequestID < requestID) { if (startedProcessingRequestID < requestID) {
@@ -2228,7 +2231,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
if (newSettings.isShowSimulationOverlay() != settings.isShowSimulationOverlay()) { if (newSettings.isShowSimulationOverlay() != settings.isShowSimulationOverlay()) {
settings.setShowSimulationOverlay(newSettings.isShowSimulationOverlay()); settings.setShowSimulationOverlay(newSettings.isShowSimulationOverlay());
simulationOverlay.setVisible(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()) { if (newSettings.isWindUp() != settings.isWindUp()) {
settings.setWindUp(newSettings.isWindUp()); settings.setWindUp(newSettings.isWindUp());
@@ -2437,16 +2442,6 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
return result; 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() { private Image createSAPLogo() {
ImageResource sapLogoResource = resources.sapLogoOverlay(); ImageResource sapLogoResource = resources.sapLogoOverlay();
Image sapLogo = new Image(sapLogoResource); 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.DeviceConfigurationMatcherSingle;
import com.sap.sailing.domain.base.configuration.impl.ESSConfigurationImpl; 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.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.RRS26ConfigurationImpl;
import com.sap.sailing.domain.base.configuration.impl.RacingProcedureConfigurationImpl; import com.sap.sailing.domain.base.configuration.impl.RacingProcedureConfigurationImpl;
import com.sap.sailing.domain.base.configuration.impl.RegattaConfigurationImpl; 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.Distance;
import com.sap.sailing.domain.common.LeaderboardNameConstants; import com.sap.sailing.domain.common.LeaderboardNameConstants;
import com.sap.sailing.domain.common.LeaderboardType; 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.LegType;
import com.sap.sailing.domain.common.ManeuverType; import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.MaxPointsReason; 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.MongoObjectFactory;
import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory; import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
import com.sap.sailing.domain.persistence.MongoRegattaLogStoreFactory; 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.RaceLogStore;
import com.sap.sailing.domain.racelog.RaceStateOfSameDayHelper; import com.sap.sailing.domain.racelog.RaceStateOfSameDayHelper;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; 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.Manage2SailEventResultsParserImpl;
import com.sap.sailing.manage2sail.RaceResultDescriptor; import com.sap.sailing.manage2sail.RaceResultDescriptor;
import com.sap.sailing.manage2sail.RegattaResultDescriptor; 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.ResultUrlProvider;
import com.sap.sailing.resultimport.ResultUrlRegistry; import com.sap.sailing.resultimport.ResultUrlRegistry;
import com.sap.sailing.server.RacingEventService; 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.UpdateRaceDelayToLive;
import com.sap.sailing.server.operationaltransformation.UpdateSeries; import com.sap.sailing.server.operationaltransformation.UpdateSeries;
import com.sap.sailing.server.operationaltransformation.UpdateSpecificRegatta; 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.Path;
import com.sap.sailing.simulator.PathType;
import com.sap.sailing.simulator.PolarDiagram; import com.sap.sailing.simulator.PolarDiagram;
import com.sap.sailing.simulator.SailingSimulator; import com.sap.sailing.simulator.SimulationResults;
import com.sap.sailing.simulator.SimulationParameters;
import com.sap.sailing.simulator.TimedPositionWithSpeed; import com.sap.sailing.simulator.TimedPositionWithSpeed;
import com.sap.sailing.simulator.impl.PolarDiagramGPS; import com.sap.sailing.simulator.impl.PolarDiagramGPS;
import com.sap.sailing.simulator.impl.SailingSimulatorImpl; import com.sap.sailing.simulator.impl.SparseSimulationDataException;
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.xrr.schema.RegattaResults; import com.sap.sailing.xrr.schema.RegattaResults;
import com.sap.sailing.xrr.structureimport.SeriesParameters; import com.sap.sailing.xrr.structureimport.SeriesParameters;
import com.sap.sailing.xrr.structureimport.StructureImporter; import com.sap.sailing.xrr.structureimport.StructureImporter;
import com.sap.sailing.xrr.structureimport.buildstructure.SetRacenumberFromSeries; import com.sap.sailing.xrr.structureimport.buildstructure.SetRacenumberFromSeries;
import com.sap.sse.BuildVersion; import com.sap.sse.BuildVersion;
import com.sap.sse.common.CountryCode; import com.sap.sse.common.CountryCode;
import com.sap.sse.common.Duration;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException; import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TimeRange; 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;
import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.Util.Triple; 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.MillisecondsTimePoint;
import com.sap.sse.common.impl.TimeRangeImpl; import com.sap.sse.common.impl.TimeRangeImpl;
import com.sap.sse.common.mail.MailException; import com.sap.sse.common.mail.MailException;
@@ -1436,107 +1433,55 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
} else { } else {
BoatClass boatClass = trackedRace.getRace().getBoatClass(); BoatClass boatClass = trackedRace.getRace().getBoatClass();
PolarDataService polarData = getService().getPolarDataService(); 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; result = polarDiagram != null;
} }
return result; return result;
} }
@Override @Override
public SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime) { public SimulatorResultsDTO getSimulatorResults(LegIdentifier legIdentifier) {
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier); // get simulation-results from smart-future-cached simulation-service
SimulatorResultsDTO result = null; SimulatorResultsDTO result = null;
SimulationService simulationService = getService().getSimulationService();
if (trackedRace != null) { if (simulationService == null)
TimePoint fromTimePoint = from == null ? new MillisecondsTimePoint(trackedRace.getStartOfRace().asMillis() + 10000) : new MillisecondsTimePoint(from); return result;
SimulationResults simulationResults = simulationService.getSimulationResults(legIdentifier);
// get previous mark or start line as start-position if (simulationResults == null)
TrackedLeg trackedLeg = trackedRace.getCurrentLeg(fromTimePoint); return result;
if (trackedLeg == 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 // prepare simulator-results-dto
if (pathsAndNames != null) { Map<PathType, Path> paths = simulationResults.getPaths();
int noOfPaths = pathsAndNames.size(); if (paths != null) {
int noOfPaths = paths.size();
PathDTO[] pathDTOs = new PathDTO[noOfPaths]; PathDTO[] pathDTOs = new PathDTO[noOfPaths];
int index = noOfPaths - 1; int index = noOfPaths - 1;
for (Entry<String, Path> entry : pathsAndNames.entrySet()) { for (Entry<PathType, Path> entry : paths.entrySet()) {
pathDTOs[index] = new PathDTO(entry.getKey()); pathDTOs[index] = new PathDTO(entry.getKey().getTxtId());
// fill pathDTO with path points where speed is true wind speed // fill pathDTO with path points where speed is true wind speed
List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>(); List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>();
for (TimedPositionWithSpeed p : entry.getValue().getPathPoints()) { for (TimedPositionWithSpeed p : entry.getValue().getPathPoints()) {
wList.add(createSimulatorWindDTO(p)); wList.add(createSimulatorWindDTO(p));
} }
pathDTOs[index].setPoints(wList); pathDTOs[index].setPoints(wList);
pathDTOs[index].setAlgorithmTimedOut(entry.getValue().getAlgorithmTimedOut());
pathDTOs[index].setMixedLeg(entry.getValue().getMixedLeg());
index--; index--;
} }
RaceMapDataDTO rcDTO; RaceMapDataDTO rcDTO;
rcDTO = new RaceMapDataDTO(); rcDTO = new RaceMapDataDTO();
rcDTO.coursePositions = new CoursePositionsDTO(); rcDTO.coursePositions = new CoursePositionsDTO();
rcDTO.coursePositions.waypointPositions = new ArrayList<>(); rcDTO.coursePositions.waypointPositions = new ArrayList<Position>();
rcDTO.coursePositions.waypointPositions.add(startPosition); rcDTO.coursePositions.waypointPositions.add(simulationResults.getStartPosition());
rcDTO.coursePositions.waypointPositions.add(endPosition); rcDTO.coursePositions.waypointPositions.add(simulationResults.getEndPosition());
result = new SimulatorResultsDTO(startTimePoint.asDate(), timeStep.asMillis(), legDuration, rcDTO, pathDTOs, null, null); result = new SimulatorResultsDTO(simulationResults.hashCode(), simulationResults.getStartTime(), simulationResults.getTimeStep(),
simulationResults.getLegDuration(), rcDTO, pathDTOs, null, null);
} }
}
return result; return result;
} }
@@ -1612,13 +1557,18 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
@Override @Override
public CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, public CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date,
Map<String, Date> fromPerCompetitorIdAsString, Map<String, Date> toPerCompetitorIdAsString, 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, final Map<CompetitorDTO, List<GPSFixDTO>> boatPositions = getBoatPositions(raceIdentifier,
fromPerCompetitorIdAsString, toPerCompetitorIdAsString, extrapolate); fromPerCompetitorIdAsString, toPerCompetitorIdAsString, extrapolate);
final CoursePositionsDTO coursePositions = getCoursePositions(raceIdentifier, date); final CoursePositionsDTO coursePositions = getCoursePositions(raceIdentifier, date);
final List<SidelineDTO> courseSidelines = getCourseSidelines(raceIdentifier, date); final List<SidelineDTO> courseSidelines = getCourseSidelines(raceIdentifier, date);
final List<QuickRankDTO> quickRanks = getQuickRanks(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 { } else {
dateAsTimePoint = new MillisecondsTimePoint(date); dateAsTimePoint = new MillisecondsTimePoint(date);
} }
result.totalLegsCount = trackedRace.getRace().getCourse().getLegs().size();
result.currentLegNumber = trackedRace.getLastLegStarted(dateAsTimePoint);
result.marks = new HashSet<MarkDTO>(); result.marks = new HashSet<MarkDTO>();
result.waypointPositions = new ArrayList<>(); result.waypointPositions = new ArrayList<>();
Set<Mark> marks = new HashSet<Mark>(); Set<Mark> marks = new HashSet<Mark>();
@@ -4527,8 +4479,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
getService().apply( getService().apply(
new UpdateCompetitor(competitor.getIdAsString(), competitor.getName(), competitor new UpdateCompetitor(competitor.getIdAsString(), competitor.getName(), competitor
.getColor(), competitor.getEmail(), competitor.getSailID(), nationality, .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; return result;
} }
@@ -4643,6 +4595,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
dto.basicConfiguration.classFlag = configuration.getBasicConfiguration().getClassFlag(); dto.basicConfiguration.classFlag = configuration.getBasicConfiguration().getClassFlag();
dto.basicConfiguration.hasInidividualRecall = configuration.getBasicConfiguration().hasInidividualRecall(); 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; return dto;
} }
@@ -4688,6 +4645,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
config.setHasInidividualRecall(dto.basicConfiguration.hasInidividualRecall); config.setHasInidividualRecall(dto.basicConfiguration.hasInidividualRecall);
configuration.setBasicConfiguration(config); 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; return configuration;
} }
@@ -9,6 +9,11 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.NavigableMap; import java.util.NavigableMap;
import java.util.Set; 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 java.util.logging.Logger;
import com.google.gwt.user.server.rpc.RemoteServiceServlet; 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.dto.BoatClassDTO;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition; 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.domain.common.impl.NauticalMileDistance;
import com.sap.sailing.gwt.ui.client.SimulatorService; import com.sap.sailing.gwt.ui.client.SimulatorService;
import com.sap.sailing.gwt.ui.shared.BoatClassDTOsAndNotificationMessage; 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.WindPatternDisplayManager;
import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternNotFoundException; import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternNotFoundException;
import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternSetting; 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.BoatClassProperties;
import com.sap.sailing.simulator.Grid; import com.sap.sailing.simulator.Grid;
import com.sap.sailing.simulator.Path; import com.sap.sailing.simulator.Path;
import com.sap.sailing.simulator.PathType;
import com.sap.sailing.simulator.PolarDiagram; 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.SimulationParameters;
import com.sap.sailing.simulator.TimedPosition; import com.sap.sailing.simulator.TimedPosition;
import com.sap.sailing.simulator.TimedPositionWithSpeed; 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.PathImpl;
import com.sap.sailing.simulator.impl.PolarDiagramCSV; import com.sap.sailing.simulator.impl.PolarDiagramCSV;
import com.sap.sailing.simulator.impl.ReadingConfigurationFileStatus; 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.SimulationParametersImpl;
import com.sap.sailing.simulator.impl.TimedPositionImpl; import com.sap.sailing.simulator.impl.TimedPositionImpl;
import com.sap.sailing.simulator.impl.TimedPositionWithSpeedImpl; 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.TimePoint;
import com.sap.sse.common.Util; import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint;
public class SimulatorServiceImpl extends RemoteServiceServlet implements SimulatorService { public class SimulatorServiceImpl extends RemoteServiceServlet implements SimulatorService {
private static final long serialVersionUID = 4445427185387524086L; 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 double TOTAL_TIME_SCALE_FACTOR = 0.9;
private static final int DEFAULT_STEP_MAX = 800; private static final int DEFAULT_STEP_MAX = 800;
private static final long DEFAULT_TIMESTEP = 6666; private static final long DEFAULT_TIMESTEP = 6666;
private final SimulationService simulationService;
private double stepSizeMeters = 0.0; private double stepSizeMeters = 0.0;
private WindControlParameters controlParameters = new WindControlParameters(0, 0); private WindControlParameters controlParameters = new WindControlParameters(0, 0);
private SpeedWithBearing averageWind = null; 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 @Override
public Position[] getRaceLocations() { public Position[] getRaceLocations() {
Position lakeGarda = new DegreePosition(45.57055337226086, 10.693345069885254); 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."); 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); wf.setPositionGrid(grid);
TimePoint startTime = new MillisecondsTimePoint(params.getStartTime().getTime()); TimePoint startTime = new MillisecondsTimePoint(params.getStartTime().getTime());
@@ -220,13 +243,13 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
e.printStackTrace(); e.printStackTrace();
} }
return null; return null;
} }
@Override @Override
public SimulatorResultsDTO getSimulatorResults(char mode, char rcDirection, WindFieldGenParamsDTO params, WindPatternDisplay pattern, boolean withWindField, public SimulatorResultsDTO getSimulatorResults(char mode, char rcDirection, WindFieldGenParamsDTO params,
SimulatorUISelectionDTO selection) throws WindPatternNotFoundException, WindPatternDisplay pattern, boolean withWindField, SimulatorUISelectionDTO selection)
ConfigurationException { throws WindPatternNotFoundException, ConfigurationException {
WindFieldGenerator wf = null; WindFieldGenerator wf = null;
List<Position> course = null; List<Position> course = null;
TimePoint startTime = new MillisecondsTimePoint(params.getStartTime().getTime()); TimePoint startTime = new MillisecondsTimePoint(params.getStartTime().getTime());
@@ -235,7 +258,7 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
this.controlParameters.resetBlastRandomStream = params.isKeepState(); this.controlParameters.resetBlastRandomStream = params.isKeepState();
this.retreiveWindControlParameters(pattern); this.retreiveWindControlParameters(pattern);
if (rcDirection == SailingSimulatorConstants.LegTypeDownwind) { if (rcDirection == SailingSimulatorConstants.LegTypeDownwind) {
this.controlParameters.baseWindBearing += 180.0; this.controlParameters.baseWindBearing += 180.0;
} }
wf = wfGenFactory.createWindFieldGenerator(pattern.getWindPatternName(), null, this.controlParameters); wf = wfGenFactory.createWindFieldGenerator(pattern.getWindPatternName(), null, this.controlParameters);
@@ -259,13 +282,14 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
gridRes[0] = params.getxRes(); gridRes[0] = params.getxRes();
gridRes[1] = params.getyRes(); gridRes[1] = params.getyRes();
gridRes[2] = params.getBorderY(); gridRes[2] = params.getBorderY();
gridRes[3] = params.getBorderX(); gridRes[3] = params.getBorderX();
wf.setGridResolution(gridRes); wf.setGridResolution(gridRes);
wf.generate(startTime, null, timeStep); wf.generate(startTime, null, timeStep);
Long longestPathTime = 0L; 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; PathDTO[] pathDTOs = simulatedPaths.pathDTOs;
RaceMapDataDTO rcDTO = simulatedPaths.raceMapDataDTO; RaceMapDataDTO rcDTO = simulatedPaths.raceMapDataDTO;
@@ -283,10 +307,13 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
WindFieldDTO windFieldDTO = null; WindFieldDTO windFieldDTO = null;
if (pattern != 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 @Override
@@ -349,20 +376,23 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
@Override @Override
public ResponseTotalTimeDTO getTotalTime(RequestTotalTimeDTO requestData) throws ConfigurationException { public ResponseTotalTimeDTO getTotalTime(RequestTotalTimeDTO requestData) throws ConfigurationException {
this.averageWind = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils.getAverage(requestData.allPoints) this.averageWind = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils
: SimulatorServiceUtils.DEFAULT_AVERAGE_WIND; .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, // List<Position> points = SimulatorServiceUtils.getIntermediatePoints2(requestData.turnPoints,
// this.stepSizeMeters); // this.stepSizeMeters);
// int noOfPointsMinus1 = points.size() - 1; // 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(); PolarDiagram polarDiagram = polarDiagramAndNotificationMessage.getA();
String notificationMessage = polarDiagramAndNotificationMessage.getB(); 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)); Path gpsTrack = simulator.getLegGPSTrack(SimulatorServiceUtils.toSimulatorUISelection(requestData.selection));
// Position startPoint = null; // Position startPoint = null;
@@ -405,14 +435,12 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
// //
// double totalTimeSeconds = (timepointAsMillis - courseStartPoint.timepoint) / 1000; // double totalTimeSeconds = (timepointAsMillis - courseStartPoint.timepoint) / 1000;
// //
double totalTimeGPSTrackSeconds = (gpsTrack.getPathPoints().get(gpsTrack.getPathPoints().size() - 1).getTimePoint().asMillis() - gpsTrack double totalTimeGPSTrackSeconds = (gpsTrack.getPathPoints().get(gpsTrack.getPathPoints().size() - 1)
.getPathPoints().get(0).getTimePoint().asMillis()) / 1000; .getTimePoint().asMillis() - gpsTrack.getPathPoints().get(0).getTimePoint().asMillis()) / 1000;
//while (totalTimeSeconds > totalTimeGPSTrackSeconds) {
// totalTimeSeconds *= TOTAL_TIME_SCALE_FACTOR;
//}
// while (totalTimeSeconds > totalTimeGPSTrackSeconds) {
// totalTimeSeconds *= TOTAL_TIME_SCALE_FACTOR;
// }
long startTimePoint = requestData.allPoints.get(0).timepoint; long startTimePoint = requestData.allPoints.get(0).timepoint;
long segmentTime = 0; long segmentTime = 0;
@@ -425,8 +453,9 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
totalTime += segmentTime; totalTime += segmentTime;
segmentTime = getTimeMillisecondsBetween(requestData.turnPoints.get(index), requestData.turnPoints.get(index + 1), this.stepSizeMeters, segmentTime = getTimeMillisecondsBetween(requestData.turnPoints.get(index),
requestData.useRealAverageWindSpeed, gpsTrack, polarDiagram, startTimePoint + totalTime); requestData.turnPoints.get(index + 1), this.stepSizeMeters, requestData.useRealAverageWindSpeed,
gpsTrack, polarDiagram, startTimePoint + totalTime);
System.out.println("Total time of segment " + segmentIndex + " = " + segmentTime + " milliseconds"); 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); 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 { public ResponseTotalTimeDTO getTotalTimeOld(RequestTotalTimeDTO requestData) throws ConfigurationException {
this.averageWind = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils.getAverage(requestData.allPoints) this.averageWind = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils
: SimulatorServiceUtils.DEFAULT_AVERAGE_WIND; .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; 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(); PolarDiagram polarDiagram = polarDiagramAndNotificationMessage.getA();
String notificationMessage = polarDiagramAndNotificationMessage.getB(); 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)); Path gpsTrack = simulator.getLegGPSTrack(SimulatorServiceUtils.toSimulatorUISelection(requestData.selection));
Position startPoint = null; Position startPoint = null;
@@ -476,17 +510,18 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
endPoint = points.get(index + 1); endPoint = points.get(index + 1);
distanceMeters = startPoint.getDistance(endPoint).getMeters(); distanceMeters = startPoint.getDistance(endPoint).getMeters();
windAtTimePoint = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils.getWindAtTimepoint(timepointAsMillis, gpsTrack) windAtTimePoint = requestData.useRealAverageWindSpeed ? SimulatorServiceUtils.getWindAtTimepoint(
: SimulatorServiceUtils.DEFAULT_AVERAGE_WIND; timepointAsMillis, gpsTrack) : SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
boatBearingDeg = SimulatorServiceUtils.getInitialBearing(startPoint, endPoint); boatBearingDeg = SimulatorServiceUtils.getInitialBearing(startPoint, endPoint);
polarDiagram.setWind(windAtTimePoint); polarDiagram.setWind(windAtTimePoint);
boatSpeedMetersPerSecond = polarDiagram.getSpeedAtBearing(new DegreeBearingImpl(boatBearingDeg)).getMetersPerSecond(); boatSpeedMetersPerSecond = polarDiagram.getSpeedAtBearing(new DegreeBearingImpl(boatBearingDeg))
.getMetersPerSecond();
stepTimeMilliseconds = (long) ((distanceMeters / boatSpeedMetersPerSecond) * 1000); stepTimeMilliseconds = (long) ((distanceMeters / boatSpeedMetersPerSecond) * 1000);
//problem right here // problem right here
//boatSpeed might be 0 for very small distances // boatSpeed might be 0 for very small distances
//this is a rough fix // this is a rough fix
if(boatSpeedMetersPerSecond == 0.0) { if (boatSpeedMetersPerSecond == 0.0) {
stepTimeMilliseconds = 1000; stepTimeMilliseconds = 1000;
} }
@@ -496,23 +531,23 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
double totalTimeSeconds = (timepointAsMillis - requestData.allPoints.get(0).timepoint) / 1000; double totalTimeSeconds = (timepointAsMillis - requestData.allPoints.get(0).timepoint) / 1000;
double totalTimeGPSTrackSeconds = (gpsTrack.getPathPoints().get(gpsTrack.getPathPoints().size() - 1).getTimePoint().asMillis() - gpsTrack double totalTimeGPSTrackSeconds = (gpsTrack.getPathPoints().get(gpsTrack.getPathPoints().size() - 1)
.getPathPoints().get(0).getTimePoint().asMillis()) / 1000; .getTimePoint().asMillis() - gpsTrack.getPathPoints().get(0).getTimePoint().asMillis()) / 1000;
// while (totalTimeSeconds > totalTimeGPSTrackSeconds) {
// totalTimeSeconds *= TOTAL_TIME_SCALE_FACTOR;
// }
System.out.println("TotalTimeGPS: " + totalTimeGPSTrackSeconds + " TotalTimePoly: " + totalTimeSeconds);
//while (totalTimeSeconds > totalTimeGPSTrackSeconds) { return new ResponseTotalTimeDTO((long) totalTimeSeconds, (double) totalTimeSeconds
// totalTimeSeconds *= TOTAL_TIME_SCALE_FACTOR; / (double) totalTimeGPSTrackSeconds, notificationMessage);
//}
System.out.println("TotalTimeGPS: "+totalTimeGPSTrackSeconds+" TotalTimePoly: "+totalTimeSeconds);
return new ResponseTotalTimeDTO((long) totalTimeSeconds, (double)totalTimeSeconds/(double)totalTimeGPSTrackSeconds, notificationMessage);
} }
@Override @Override
public Response1TurnerDTO get1Turner(Request1TurnerDTO requestData) throws ConfigurationException { 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(); PolarDiagram polarDiagram = polarDiagramAndNotificationMessage.getA();
String notificationMessage = polarDiagramAndNotificationMessage.getB(); String notificationMessage = polarDiagramAndNotificationMessage.getB();
@@ -522,16 +557,19 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
Position oldMovedPosition = requestData.oldMovedPoint; Position oldMovedPosition = requestData.oldMovedPoint;
Position newMovedPosition = requestData.newMovedPoint; Position newMovedPosition = requestData.newMovedPoint;
Bearing oldMovedToNewMovedBearing = oldMovedPosition.getBearingGreatCircle(newMovedPosition); Bearing oldMovedToNewMovedBearing = oldMovedPosition.getBearingGreatCircle(newMovedPosition);
boolean areTowardsSameDirection = SimulatorServiceUtils.areTowardsSameDirection(oldMovedToNewMovedBearing, new DegreeBearingImpl( boolean areTowardsSameDirection = SimulatorServiceUtils.areTowardsSameDirection(oldMovedToNewMovedBearing,
requestData.startToEndBearingDegrees)); new DegreeBearingImpl(requestData.startToEndBearingDegrees));
System.out.println("oldMovedToNewMovedBearing = " + oldMovedToNewMovedBearing.getDegrees() + " degrees"); 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); System.out.println("areTowardsSameDirection = " + areTowardsSameDirection);
SimulationParameters simulationParameters = new SimulationParametersImpl(null, polarDiagram, null, SailingSimulatorConstants.ModeMeasured, true, true); SimulationParameters simulationParameters = new SimulationParametersImpl(null, polarDiagram, null, null,
SailingSimulator sailingSimulator = new SailingSimulatorImpl(simulationParameters); SailingSimulatorConstants.ModeMeasured, true, true);
Path gpsWind = sailingSimulator.getLegGPSTrack(SimulatorServiceUtils.toSimulatorUISelection(requestData.selection)); Simulator sailingSimulator = new SimulatorImpl(simulationParameters);
Path gpsWind = sailingSimulator.getLegGPSTrack(SimulatorServiceUtils
.toSimulatorUISelection(requestData.selection));
Grid grid = new CurvedGrid(oldMovedPosition, newMovedPosition); Grid grid = new CurvedGrid(oldMovedPosition, newMovedPosition);
this.controlParameters.baseWindBearing += grid.getSouth().getDegrees(); this.controlParameters.baseWindBearing += grid.getSouth().getDegrees();
@@ -548,8 +586,10 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
Position realStart = areTowardsSameDirection ? oldMovedPosition : newMovedPosition; Position realStart = areTowardsSameDirection ? oldMovedPosition : newMovedPosition;
Position realEnd = areTowardsSameDirection ? newMovedPosition : oldMovedPosition; Position realEnd = areTowardsSameDirection ? newMovedPosition : oldMovedPosition;
leftSide1Turner = pathGenerator.get1Turner(windFieldGenerator, polarDiagram, realStart, realEnd, startTime, true, DEFAULT_STEP_MAX, DEFAULT_TIMESTEP); leftSide1Turner = pathGenerator.get1Turner(windFieldGenerator, polarDiagram, realStart, realEnd, startTime,
rightSide1Turner = pathGenerator.get1Turner(windFieldGenerator, polarDiagram, realStart, realEnd, startTime, false, DEFAULT_STEP_MAX, DEFAULT_TIMESTEP); 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(), boolean isLeftSide1TurnerOnTheInside = SimulatorServiceUtils.isPointInsideTriangle(leftSide1Turner.getPosition(),
requestData.beforeMovedPoint, requestData.beforeMovedPoint,
@@ -579,8 +619,7 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
} else if (SimulatorServiceUtils.equals(rightSide1Turner.getPosition(), newMovedPosition, 0.0001)) { } else if (SimulatorServiceUtils.equals(rightSide1Turner.getPosition(), newMovedPosition, 0.0001)) {
System.out.println("voi folosi endPosition = rightSide1Turner!"); System.out.println("voi folosi endPosition = rightSide1Turner!");
correct1Turner = rightSide1Turner; correct1Turner = rightSide1Turner;
} } else {
else {
System.out.println("nu ar trebui sa ajunga aici NICIODATA!"); System.out.println("nu ar trebui sa ajunga aici NICIODATA!");
} }
} }
@@ -588,11 +627,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
long timeStepMilliseconds = 2000; long timeStepMilliseconds = 2000;
double minimumDistanceMeters = 4.0; double minimumDistanceMeters = 4.0;
List<TimedPositionWithSpeed> path = pathGenerator.getIntersectionOptimalTowardWind(windFieldGenerator, polarDiagram, edgeStart, edgeEnd, List<TimedPositionWithSpeed> path = pathGenerator.getIntersectionOptimalTowardWind(windFieldGenerator,
correct1Turner, polarDiagram, edgeStart, edgeEnd, correct1Turner, true, timeStepMilliseconds, minimumDistanceMeters);
true,
timeStepMilliseconds, minimumDistanceMeters);
return new Response1TurnerDTO(SimulatorServiceUtils.toSimulatorWindDTOList(path), SimulatorServiceUtils.toSimulatorWindDTO(leftSide1Turner), return new Response1TurnerDTO(SimulatorServiceUtils.toSimulatorWindDTOList(path), SimulatorServiceUtils.toSimulatorWindDTO(leftSide1Turner),
SimulatorServiceUtils.toSimulatorWindDTO(rightSide1Turner), oldMovedPosition, SimulatorServiceUtils.toSimulatorWindDTO(rightSide1Turner), oldMovedPosition,
@@ -607,7 +643,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
selectedRaceIndex = 0; 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); return simulator.getLegsNames(selectedRaceIndex);
} }
@@ -615,7 +652,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
@Override @Override
public List<String> getRacesNames() { 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(); return simulator.getRacesNames();
} }
@@ -627,9 +665,10 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
selectedRaceIndex = 0; 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) { private void retreiveWindControlParameters(WindPatternDisplay pattern) {
@@ -687,11 +726,11 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
SimulatorWindDTO result = new SimulatorWindDTO(); SimulatorWindDTO result = new SimulatorWindDTO();
if (speedWithBearing == null) { if (speedWithBearing == null) {
result.trueWindBearingDeg = 0.0; result.trueWindBearingDeg = 0.0;
result.trueWindSpeedInKnots = 0.0; result.trueWindSpeedInKnots = 0.0;
} else { } else {
result.trueWindBearingDeg = speedWithBearing.getBearing().getDegrees(); result.trueWindBearingDeg = speedWithBearing.getBearing().getDegrees();
result.trueWindSpeedInKnots = speedWithBearing.getKnots(); result.trueWindSpeedInKnots = speedWithBearing.getKnots();
} }
if (position != null) { if (position != null) {
@@ -779,9 +818,9 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
} }
} }
} }
//TODO: throws null pointer exception for when reading serialized paths. // TODO: throws null pointer exception for when reading serialized paths.
//TODO: should windlines also be serialized? // TODO: should windlines also be serialized?
//logger.info("Added : " + windFieldDTO.getWindLinesDTO().getWindLinesMap().size() + " wind lines"); // logger.info("Added : " + windFieldDTO.getWindLinesDTO().getWindLinesMap().size() + " wind lines");
} }
private void getWindLinesFromEndLine(WindFieldGenerator wf, WindFieldDTO windFieldDTO, TimePoint startTime, 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, private SimulatedPathsEvenTimedResultDTO getSimulatedPathsEvenTimed(List<Position> course, WindFieldGenerator wf,
SimulatorUISelectionDTO selection, boolean showOmniscient, boolean showOpportunist) throws ConfigurationException { char mode, SimulatorUISelectionDTO selection, boolean showOmniscient, boolean showOpportunist)
throws ConfigurationException {
LOGGER.info("Retrieving simulated paths"); LOGGER.info("Retrieving simulated paths");
Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this.getPolarDiagram(selection.boatClassIndex); Util.Pair<PolarDiagram, String> polarDiagramAndNotificationMessage = this.getPolarDiagram(selection.boatClassIndex);
PolarDiagram pd = polarDiagramAndNotificationMessage.getA(); PolarDiagram pd = polarDiagramAndNotificationMessage.getA();
int[] gridRes = wf.getGridResolution();
SimulationParameters sp = new SimulationParametersImpl(course, pd, wf, mode, showOmniscient, showOpportunist); Position[] gridArea = wf.getGridAreaGps();
SailingSimulator simulator = new SailingSimulatorImpl(sp); LOGGER.info("showOmniscient : "+showOmniscient);
LOGGER.info("showOpportunist: "+showOpportunist);
Map<String, Path> pathsAndNames = null; if (gridArea != null) {
// initialize grid of supporting location for windfield
pathsAndNames = simulator.getAllPathsEvenTimed(wf.getTimeStep().asMillis(), Grid bd = new CurvedGrid(gridArea[0], gridArea[1]);
(mode == SailingSimulatorConstants.ModeMeasured) ? SimulatorServiceUtils.toSimulatorUISelection(selection) : null); // 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(); int noOfPaths = pathsAndNames.size();
if (mode == SailingSimulatorConstants.ModeMeasured) { if (mode == SailingSimulatorConstants.ModeMeasured) {
noOfPaths++; // the last path is the polyline 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")); pathDTOs[0] = this.getPolylinePathDTO(pathsAndNames.get("6#GPS Poly"), pathsAndNames.get("7#GPS Track"));
} }
for (Entry<String, Path> entry : pathsAndNames.entrySet()) { for (Entry<PathType, Path> entry : pathsAndNames.entrySet()) {
LOGGER.info("Path " + entry.getKey()); LOGGER.info("Path " + entry.getKey().getTxtId());
// NOTE: pathName convention is: sort-digit + "#" + path-name // NOTE: pathName convention is: sort-digit + "#" + path-name
// pathsAndNames is TreeMap which ensures sorting // 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 // fill pathDTO with path points where speed is true wind speed
List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>(); List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>();
for (TimedPositionWithSpeed p : entry.getValue().getPathPoints()) { for (TimedPositionWithSpeed p : entry.getValue().getPathPoints()) {
wList.add(createSimulatorWindDTO(p)); wList.add(createSimulatorWindDTO(p));
} }
pathDTOs[index].setPoints(wList); pathDTOs[index].setPoints(wList);
pathDTOs[index].setAlgorithmTimedOut(entry.getValue().getAlgorithmTimedOut());
pathDTOs[index].setMixedLeg(entry.getValue().getMixedLeg());
index--; index--;
} }
@@ -901,9 +968,8 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
rcDTO = new RaceMapDataDTO(); rcDTO = new RaceMapDataDTO();
rcDTO.coursePositions = new CoursePositionsDTO(); rcDTO.coursePositions = new CoursePositionsDTO();
rcDTO.coursePositions.waypointPositions = new ArrayList<>(); rcDTO.coursePositions.waypointPositions = new ArrayList<>();
Path rc = simulator.getRaceCourse(); rcDTO.coursePositions.waypointPositions.add(course.get(0));
rcDTO.coursePositions.waypointPositions.add(rc.getPathPoints().get(0).getPosition()); rcDTO.coursePositions.waypointPositions.add(course.get(1));
rcDTO.coursePositions.waypointPositions.add(rc.getPathPoints().get(1).getPosition());
} else { } else {
rcDTO = null; rcDTO = null;
} }
@@ -963,7 +1029,7 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
List<TimedPositionWithSpeed> polylinePoints = gpsTrackPoints.subList(startPointIndex, endPointIndex + 1); 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"); // PathImpl.saveToGpxFile(new PathImpl(turns, null), "C:\\gps_path_turns_20deg_not_even_timed.gpx");
List<SimulatorWindDTO> points = new ArrayList<SimulatorWindDTO>(); List<SimulatorWindDTO> points = new ArrayList<SimulatorWindDTO>();
@@ -977,8 +1043,10 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
isTurn = false; isTurn = false;
for (TimedPositionWithSpeed turn : turns) { for (TimedPositionWithSpeed turn : turns) {
if (turn.getPosition().getLatDeg() == point.getPosition().getLatDeg() && turn.getPosition().getLngDeg() == point.getPosition().getLngDeg() if (turn.getPosition().getLatDeg() == point.getPosition().getLatDeg()
&& turn.getTimePoint().asMillis() == point.getTimePoint().asMillis() && turn.getSpeed().getKnots() == point.getSpeed().getKnots() && 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()) { && turn.getSpeed().getBearing().getDegrees() == point.getSpeed().getBearing().getDegrees()) {
isTurn = true; isTurn = true;
break; break;
@@ -989,12 +1057,12 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
position = point.getPosition(); position = point.getPosition();
points.add(new SimulatorWindDTO(position.getLatDeg(), position.getLngDeg(), speedWithBearing.getKnots(), points.add(new SimulatorWindDTO(position.getLatDeg(), position.getLngDeg(), speedWithBearing.getKnots(),
speedWithBearing.getBearing() speedWithBearing.getBearing().getDegrees(), point.getTimePoint().asMillis(), isTurn));
.getDegrees(), point.getTimePoint().asMillis(), isTurn));
} }
PathDTO result = new PathDTO(POLYLINE_PATH_NAME); PathDTO result = new PathDTO(POLYLINE_PATH_NAME);
result.setPoints(points); result.setPoints(points);
result.setAlgorithmTimedOut(false);
return result; return result;
} }
@@ -1081,17 +1149,18 @@ public class SimulatorServiceImpl extends RemoteServiceServlet implements Simula
endPoint = points.get(index + 1); endPoint = points.get(index + 1);
distanceMeters = startPoint.getDistance(endPoint).getMeters(); distanceMeters = startPoint.getDistance(endPoint).getMeters();
windAtTimePoint = useRealAverageWindSpeed ? SimulatorServiceUtils.getWindAtTimepoint(timepointAsMillis, gpsTrack) windAtTimePoint = useRealAverageWindSpeed ? SimulatorServiceUtils.getWindAtTimepoint(timepointAsMillis,
: SimulatorServiceUtils.DEFAULT_AVERAGE_WIND; gpsTrack) : SimulatorServiceUtils.DEFAULT_AVERAGE_WIND;
boatBearingDeg = SimulatorServiceUtils.getInitialBearing(startPoint, endPoint); boatBearingDeg = SimulatorServiceUtils.getInitialBearing(startPoint, endPoint);
polarDiagram.setWind(windAtTimePoint); polarDiagram.setWind(windAtTimePoint);
boatSpeedMetersPerSecond = polarDiagram.getSpeedAtBearing(new DegreeBearingImpl(boatBearingDeg)).getMetersPerSecond(); boatSpeedMetersPerSecond = polarDiagram.getSpeedAtBearing(new DegreeBearingImpl(boatBearingDeg))
.getMetersPerSecond();
stepTimeMilliseconds = (long) ((distanceMeters / boatSpeedMetersPerSecond) * 1000); stepTimeMilliseconds = (long) ((distanceMeters / boatSpeedMetersPerSecond) * 1000);
// problem right here: boatSpeed might be 0 for very small distances // problem right here: boatSpeed might be 0 for very small distances
// this is a rough fix // this is a rough fix
if(boatSpeedMetersPerSecond == 0.0) { if (boatSpeedMetersPerSecond == 0.0) {
stepTimeMilliseconds = 1000; stepTimeMilliseconds = 1000;
} }
@@ -25,11 +25,12 @@ public class CompactRaceMapDataDTO implements IsSerializable {
private CoursePositionsDTO coursePositions; private CoursePositionsDTO coursePositions;
private List<SidelineDTO> courseSidelines; private List<SidelineDTO> courseSidelines;
private List<CompactQuickRankDTO> quickRanks; private List<CompactQuickRankDTO> quickRanks;
private int simulationResultVersion;
CompactRaceMapDataDTO() {} CompactRaceMapDataDTO() {}
public CompactRaceMapDataDTO(Map<CompetitorDTO, List<GPSFixDTO>> boatPositions, CoursePositionsDTO coursePositions, 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>>(); this.boatPositionsByCompetitorIdAsString = new HashMap<String, List<GPSFixDTO>>();
for (Map.Entry<CompetitorDTO, List<GPSFixDTO>> e : boatPositions.entrySet()) { for (Map.Entry<CompetitorDTO, List<GPSFixDTO>> e : boatPositions.entrySet()) {
this.boatPositionsByCompetitorIdAsString.put(e.getKey().getIdAsString(), e.getValue()); this.boatPositionsByCompetitorIdAsString.put(e.getKey().getIdAsString(), e.getValue());
@@ -43,6 +44,7 @@ public class CompactRaceMapDataDTO implements IsSerializable {
} }
this.courseSidelines = courseSidelines; this.courseSidelines = courseSidelines;
this.coursePositions = coursePositions; this.coursePositions = coursePositions;
this.simulationResultVersion = simulationResultVersion;
} }
public RaceMapDataDTO getRaceMapDataDTO(Iterable<CompetitorDTO> competitors) { public RaceMapDataDTO getRaceMapDataDTO(Iterable<CompetitorDTO> competitors) {
@@ -68,6 +70,7 @@ public class CompactRaceMapDataDTO implements IsSerializable {
result.boatPositions.put(competitor, e.getValue()); result.boatPositions.put(competitor, e.getValue());
} }
} }
result.simulationResultVersion = simulationResultVersion;
return result; return result;
} }
} }
@@ -13,6 +13,9 @@ public class CoursePositionsDTO implements IsSerializable {
public List<Position> finishMarkPositions; public List<Position> finishMarkPositions;
public Set<MarkDTO> marks; 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, * <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 * {@link #startLineAdvantageousSide}, {@link #startLineAdvantageInMeters} and {@link #startLineLengthInMeters} are
@@ -22,7 +22,11 @@ public class DeviceConfigurationDTO implements IsSerializable {
public static class ESSConfigurationDTO extends RacingProcedureConfigurationDTO { public static class ESSConfigurationDTO extends RacingProcedureConfigurationDTO {
} }
public static class LeagueConfigurationDTO extends RacingProcedureConfigurationDTO {
}
public static class RacingProcedureConfigurationDTO implements IsSerializable { public static class RacingProcedureConfigurationDTO implements IsSerializable {
public Flags classFlag; public Flags classFlag;
public Boolean hasInidividualRecall; public Boolean hasInidividualRecall;
@@ -34,6 +38,7 @@ public class DeviceConfigurationDTO implements IsSerializable {
public GateStartConfigurationDTO gateStartConfiguration; public GateStartConfigurationDTO gateStartConfiguration;
public ESSConfigurationDTO essConfiguration; public ESSConfigurationDTO essConfiguration;
public RacingProcedureConfigurationDTO basicConfiguration; public RacingProcedureConfigurationDTO basicConfiguration;
public LeagueConfigurationDTO leagueConfiguration;
} }
public List<String> allowedCourseAreaNames; public List<String> allowedCourseAreaNames;
@@ -7,9 +7,10 @@ import com.sap.sailing.domain.common.dto.NamedDTO;
public class PathDTO extends NamedDTO { public class PathDTO extends NamedDTO {
private static final long serialVersionUID = 2381814072763342186L; private static final long serialVersionUID = 2381814072763342186L;
private List<SimulatorWindDTO> points; private List<SimulatorWindDTO> points;
private boolean algorithmTimedOut;
private boolean mixedLeg;
public PathDTO() { public PathDTO() {
} }
public PathDTO(final String name) { public PathDTO(final String name) {
@@ -31,5 +32,21 @@ public class PathDTO extends NamedDTO {
return points.get(points.size() - 1).timepoint - points.get(0).timepoint; 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 CoursePositionsDTO coursePositions;
public List<SidelineDTO> courseSidelines; public List<SidelineDTO> courseSidelines;
public LinkedHashMap<CompetitorDTO, QuickRankDTO> quickRanks; 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 { public class SimulatorResultsDTO implements IsSerializable {
private int version;
private Date startTime; private Date startTime;
private long timeStep; private long timeStep;
private long legDuration; private long legDuration;
@@ -15,6 +16,7 @@ public class SimulatorResultsDTO implements IsSerializable {
private String notificationMessage; private String notificationMessage;
public SimulatorResultsDTO(){ public SimulatorResultsDTO(){
this.version = 0;
this.startTime = null; this.startTime = null;
this.timeStep = 0; this.timeStep = 0;
this.legDuration = 0; this.legDuration = 0;
@@ -24,7 +26,8 @@ public class SimulatorResultsDTO implements IsSerializable {
this.notificationMessage = ""; 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.startTime = startTime;
this.timeStep = timeStep; this.timeStep = timeStep;
this.legDuration = legDuration; this.legDuration = legDuration;
@@ -34,6 +37,14 @@ public class SimulatorResultsDTO implements IsSerializable {
this.notificationMessage = notificationMessage; this.notificationMessage = notificationMessage;
} }
public int getVersion() {
return this.version;
}
public void setVersion(int version) {
this.version = version;
}
public Date getStartTime() { public Date getStartTime() {
return this.startTime; 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.maps.client.controls.ControlPosition;
import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback; 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.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.gwt.ui.actions.GetSimulationAction; import com.sap.sailing.gwt.ui.actions.GetSimulationAction;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync; 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"; public static final String GET_SIMULATION_CATEGORY = "getSimulation";
private final String textColor = "Black"; private final String textColor = "Black";
private final String textFont = "10pt OpenSansRegular"; private final String textFont = "10pt OpenSansRegular";
private String algorithmTimedOutText = "out-of-bounds";
private String mixedLegText = "ambiguous wind";
private int xOffset = 0; private int xOffset = 0;
private int yOffset = 0; //150; private int yOffset = 0; //150;
private double rectWidth = 20; private double rectWidth = 20;
@@ -52,7 +56,6 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
private SimulatorResultsDTO simulationResult; private SimulatorResultsDTO simulationResult;
private PathDTO racePath; private PathDTO racePath;
private int raceLeg = 0; private int raceLeg = 0;
private Date prevStartTime;
private Canvas simulationLegend; private Canvas simulationLegend;
public RaceSimulationOverlay(MapWidget map, int zIndex, RegattaAndRaceIdentifier raceIdentifier, SailingServiceAsync sailingService, StringMessages stringMessages, AsyncActionsExecutor asyncActionsExecutor, CoordinateSystem coordinateSystem) { public RaceSimulationOverlay(MapWidget map, int zIndex, RegattaAndRaceIdentifier raceIdentifier, SailingServiceAsync sailingService, StringMessages stringMessages, AsyncActionsExecutor asyncActionsExecutor, CoordinateSystem coordinateSystem) {
@@ -64,16 +67,28 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
this.colors = new ColorPaletteGenerator(); this.colors = new ColorPaletteGenerator();
} }
public void updateLeg(int newLeg, Date newTime, boolean clearCanvas) { public void updateLeg(int newLeg, boolean clearCanvas, int newVersion) {
if ((newLeg != raceLeg) && (this.isVisible())) { if (((newLeg != raceLeg)||((newLeg == raceLeg)&&(newVersion != (simulationResult==null ? 0 : simulationResult.getVersion())))) && (this.isVisible())) {
raceLeg = newLeg; raceLeg = newLeg;
if (clearCanvas) { if (clearCanvas) {
this.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();
}
}
@Override @Override
public void setVisible(boolean isVisible) { public void setVisible(boolean isVisible) {
super.setVisible(isVisible); super.setVisible(isVisible);
@@ -146,8 +161,12 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
Context2d ctxt = canvas.getContext2d(); Context2d ctxt = canvas.getContext2d();
PathDTO[] paths = simulationResult.getPaths(); PathDTO[] paths = simulationResult.getPaths();
boolean first = true; boolean first = true;
int colorIdx = paths.length - 1; int colorIdx = paths.length;
for (PathDTO path : paths) { for (PathDTO path : paths) {
colorIdx--;
if (path.getMixedLeg()) {
continue;
}
List<SimulatorWindDTO> points = path.getPoints(); List<SimulatorWindDTO> points = path.getPoints();
ctxt.setLineWidth(3.0); ctxt.setLineWidth(3.0);
ctxt.setGlobalAlpha(0.7); ctxt.setGlobalAlpha(0.7);
@@ -175,7 +194,6 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
ctxt.closePath(); ctxt.closePath();
ctxt.stroke(); ctxt.stroke();
} }
colorIdx--;
} }
} }
@@ -190,22 +208,57 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
txtmet = context2d.measureText("00:00:00"); txtmet = context2d.measureText("00:00:00");
double timewidth = txtmet.getWidth(); double timewidth = txtmet.getWidth();
double txtmaxwidth = 0.0; double txtmaxwidth = 0.0;
txtmet = context2d.measureText(racePath.getName().split("#")[1]); if (racePath != null) {
txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth()); txtmet = context2d.measureText(racePath.getName().split("#")[1]);
PathDTO[] paths = this.simulationResult.getPaths();
for (PathDTO path : paths) {
txtmet = context2d.measureText(path.getName());
txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth()); txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth());
} }
//canvas.setSize(xOffset + rectWidth + txtmaxwidth + timewidth + 10.0+"px", rectHeight*(paths.length+1)+"px"); boolean containsTimeOut = false;
int canvasWidth = (int)Math.ceil(xOffset + rectWidth + txtmaxwidth + timewidth + 10.0 + 5.0); boolean containsMixedLeg = false;
int canvasHeight = (int)Math.ceil(yOffset + rectHeight*(paths.length+1)); PathDTO[] paths = this.simulationResult.getPaths();
setCanvasSize(canvas, canvasWidth, canvasHeight);
drawRectangleWithText(context2d, xOffset, yOffset, "rgba(255,255,255,0.8);",
racePath.getName().split("#")[1], getFormattedTime(racePath.getPathTime()), txtmaxwidth, timewidth);
for (PathDTO path : paths) { for (PathDTO path : paths) {
drawRectangleWithText(context2d, xOffset, yOffset + (paths.length-index) * rectHeight, this.colors.getColor(paths.length-1-index), if (path.getAlgorithmTimedOut()) {
path.getName().split("#")[1], getFormattedTime(path.getPathTime()), txtmaxwidth, timewidth); 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 + 10.0);
int canvasHeight = (int)Math.ceil(yOffset + rectHeight*(paths.length + (racePath == null? 0 : 1)));
setCanvasSize(canvas, canvasWidth, canvasHeight);
if (racePath != null) {
drawRectangleWithText(context2d, xOffset, yOffset, null,
racePath.getName().split("#")[1], getFormattedTime(racePath.getPathTime()), txtmaxwidth, timewidth, deltaTime);
}
for (PathDTO path : paths) {
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++; index++;
} }
} }
@@ -223,17 +276,19 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
context2d.fillRect(x, y, rectWidth, rectHeight); 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; double offset = 3.0;
context2d.setFont(textFont); context2d.setFont(textFont);
drawRectangle(context2d, x, y, color); if (color != null) {
drawRectangle(context2d, x, y, color);
}
context2d.setGlobalAlpha(0.80); context2d.setGlobalAlpha(0.80);
context2d.setFillStyle("white"); 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.setGlobalAlpha(1.0);
context2d.setFillStyle(textColor); context2d.setFillStyle(textColor);
context2d.fillText(text, x + rectWidth + 5.0, y + 12.0 + offset); 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) { protected String getFormattedTime(long pathTime) {
@@ -244,8 +299,9 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
return pathTimeStr; return pathTimeStr;
} }
public void simulate(Date from) { public void simulate(int leg) {
GetSimulationAction getSimulation = new GetSimulationAction(sailingService, raceIdentifier, from, prevStartTime); LegIdentifier legIdentifier = new LegIdentifierImpl(raceIdentifier, String.valueOf(leg));
GetSimulationAction getSimulation = new GetSimulationAction(sailingService, legIdentifier);
asyncActionsExecutor.execute(getSimulation, GET_SIMULATION_CATEGORY, asyncActionsExecutor.execute(getSimulation, GET_SIMULATION_CATEGORY,
new MarkedAsyncCallback<>(new AsyncCallback<SimulatorResultsDTO>() { new MarkedAsyncCallback<>(new AsyncCallback<SimulatorResultsDTO>() {
@Override @Override
@@ -259,19 +315,26 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
public void onSuccess(SimulatorResultsDTO result) { public void onSuccess(SimulatorResultsDTO result) {
// store results // store results
if (result != null) { if (result != null) {
prevStartTime = result.getStartTime();
if (result.getPaths() != null) { if (result.getPaths() != null) {
simulationResult = result; simulationResult = result;
PathDTO[] paths = result.getPaths(); PathDTO[] paths = result.getPaths();
racePath = new PathDTO(); if (result.getLegDuration() > 0) {
List<SimulatorWindDTO> racePathPoints = new ArrayList<SimulatorWindDTO>(); racePath = new PathDTO();
racePathPoints.add(new SimulatorWindDTO(null, 0, 0, paths[0].getPoints().get(0).timepoint)); List<SimulatorWindDTO> racePathPoints = new ArrayList<SimulatorWindDTO>();
racePathPoints.add(new SimulatorWindDTO(null, 0, 0, paths[0].getPoints().get(0).timepoint + result.getLegDuration())); racePathPoints.add(new SimulatorWindDTO(null, 0, 0, paths[0].getPoints().get(0).timepoint));
racePath.setPoints(racePathPoints); racePathPoints.add(new SimulatorWindDTO(null, 0, 0, paths[0].getPoints().get(0).timepoint + result.getLegDuration()));
racePath.setName("0#Race"); racePath.setPoints(racePathPoints);
racePath.setName("0#Race");
} else {
racePath = null;
}
clearCanvas(); clearCanvas();
drawPaths(); drawPaths();
} }
} else {
raceLeg = 0;
simulationResult = null;
clearCanvas();
} }
} }
})); }));
@@ -43,6 +43,8 @@ public class PathCanvasOverlay extends WindFieldCanvasOverlay implements Named {
private long totalTimeMilliseconds = 0; private long totalTimeMilliseconds = 0;
private String name; private String name;
private boolean algorithmTimedOut;
private boolean mixedLeg;
private String pathColor = "Green"; private String pathColor = "Green";
@@ -56,9 +58,11 @@ public class PathCanvasOverlay extends WindFieldCanvasOverlay implements Named {
this.name = name; 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); super(map, zIndex, timer, windParams, coordinateSystem);
this.name = name; this.name = name;
this.algorithmTimedOut = algorithmTimedOut;
this.mixedLeg = mixedLeg;
} }
public PathCanvasOverlay(MapWidget map, int zIndex, String name, long totalTimeMilliseconds, CoordinateSystem coordinateSystem) { 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; return name;
} }
public boolean getAlgorithmTimedOut() {
return algorithmTimedOut;
}
public boolean getMixedLeg() {
return mixedLeg;
}
public long getPathTime() { public long getPathTime() {
if (totalTimeIsGiven) { if (totalTimeIsGiven) {
return totalTimeMilliseconds; return totalTimeMilliseconds;
@@ -40,6 +40,8 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
private String textColor = "Black"; private String textColor = "Black";
private String textFont = "10pt OpenSansRegular"; 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) { public PathLegendCanvasOverlay(MapWidget map, int zIndex, char mode, CoordinateSystem coordinateSystem) {
super(map, zIndex, coordinateSystem); super(map, zIndex, coordinateSystem);
@@ -82,13 +84,44 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
txtmet = context2d.measureText("00:00:00"); txtmet = context2d.measureText("00:00:00");
double timewidth = txtmet.getWidth(); double timewidth = txtmet.getWidth();
double txtmaxwidth = 0.0; double txtmaxwidth = 0.0;
boolean containsTimeOut = false;
boolean containsMixedLeg = false;
for (PathCanvasOverlay path : pathOverlays) { for (PathCanvasOverlay path : pathOverlays) {
if (path.getAlgorithmTimedOut()) {
containsTimeOut = true;
}
if (path.getMixedLeg()) {
containsMixedLeg = true;
}
txtmet = context2d.measureText(path.getName()); txtmet = context2d.measureText(path.getName());
txtmaxwidth = Math.max(txtmaxwidth, txtmet.getWidth()); 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) { 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(), 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++; index++;
} }
// //
@@ -170,7 +203,7 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
context2d.fillRect(x, y, rectWidth, rectHeight); 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; double offset = 3.0;
@@ -179,11 +212,11 @@ public class PathLegendCanvasOverlay extends FullCanvasOverlay {
drawRectangle(x, y, color); drawRectangle(x, y, color);
context2d.setGlobalAlpha(0.80); context2d.setGlobalAlpha(0.80);
context2d.setFillStyle("white"); 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.setGlobalAlpha(1.0);
context2d.setFillStyle(textColor); context2d.setFillStyle(textColor);
context2d.fillText(text, x + rectWidth + 5.0, y + 12.0 + offset); 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) { protected String getFormattedTime(long pathTime) {
@@ -18,8 +18,8 @@ public class ReplayPathCanvasOverlay extends PathCanvasOverlay {
private List<SimulatorWindDTO> windDTOToDraw; private List<SimulatorWindDTO> windDTOToDraw;
public ReplayPathCanvasOverlay(MapWidget map, int zIndex, final String name, final Timer timer, public ReplayPathCanvasOverlay(MapWidget map, int zIndex, final String name, final Timer timer,
WindFieldGenParamsDTO windParams, CoordinateSystem coordinateSystem) { WindFieldGenParamsDTO windParams, boolean algorithmTimedOut, boolean mixedLeg, CoordinateSystem coordinateSystem) {
super(map, zIndex, name, timer, windParams, coordinateSystem); super(map, zIndex, name, timer, windParams, algorithmTimedOut, mixedLeg, coordinateSystem);
this.displayWindAlongPath = false; this.displayWindAlongPath = false;
windDTOToDraw = null; windDTOToDraw = null;
canvas.setStyleName("replayPanel"); canvas.setStyleName("replayPanel");
@@ -34,6 +34,10 @@ public class ReplayPathCanvasOverlay extends PathCanvasOverlay {
@Override @Override
public void timeChanged(final Date newTime, Date oldTime) { public void timeChanged(final Date newTime, Date oldTime) {
if (windFieldDTO == null) {
return;
}
canvas.getContext2d().clearRect(0/* canvas.getAbsoluteLeft() */, 0/* canvas.getAbsoluteTop() */, canvas.getContext2d().clearRect(0/* canvas.getAbsoluteLeft() */, 0/* canvas.getAbsoluteTop() */,
canvas.getCoordinateSpaceWidth(), canvas.getCoordinateSpaceHeight()); canvas.getCoordinateSpaceWidth(), canvas.getCoordinateSpaceHeight());
@@ -50,7 +54,10 @@ public class ReplayPathCanvasOverlay extends PathCanvasOverlay {
@Override @Override
public boolean shallStop() { public boolean shallStop() {
if (!isVisible() || windDTOToDraw == null || windFieldDTO == null) { if (windDTOToDraw == null || windFieldDTO == null) {
return false;
}
if (!isVisible()) {
return true; return true;
} }
if (windDTOToDraw.size() >= (windFieldDTO.getMatrix().size()-1)) { if (windDTOToDraw.size() >= (windFieldDTO.getMatrix().size()-1)) {
@@ -158,27 +158,31 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
PathDTO currentPath = null; PathDTO currentPath = null;
//String color = null; //String color = null;
String pathName = null; String pathName = null;
boolean algorithmTimedOut = false;
int noOfPaths = paths.length; int noOfPaths = paths.length;
for (int index = 0; index < noOfPaths; ++index) { for (int index = 0; index < noOfPaths; ++index) {
currentPath = paths[index]; currentPath = paths[index];
pathName = currentPath.getName(); pathName = currentPath.getName();
algorithmTimedOut = currentPath.getAlgorithmTimedOut();
//color = colorPalette.getColor(noOfPaths - 1 - index); //color = colorPalette.getColor(noOfPaths - 1 - index);
if (pathName.equals("Polyline")) { if (pathName.equals("Polyline")) {
pathPolyline = createPathPolyline(currentPath); pathPolyline = createPathPolyline(currentPath);
} else if (pathName.equals("GPS Poly")) { } else if (pathName.equals("GPS Poly")) {
continue; continue;
} } else {
else {
/* TODO Revisit for now creating a WindFieldDTO from the path */ /* TODO Revisit for now creating a WindFieldDTO from the path */
WindFieldDTO pathWindDTO = new WindFieldDTO(); WindFieldDTO pathWindDTO = null;
pathWindDTO.setMatrix(currentPath.getPoints()); if (!currentPath.getMixedLeg()) {
pathWindDTO = new WindFieldDTO();
pathWindDTO.setMatrix(currentPath.getPoints());
}
ReplayPathCanvasOverlay replayPathCanvasOverlay = new ReplayPathCanvasOverlay(map, SimulatorMapOverlaysZIndexes.PATH_ZINDEX, 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); replayPathCanvasOverlays.add(replayPathCanvasOverlay);
replayPathCanvasOverlay.setPathColor(colorPalette.getColor(Integer.parseInt(pathName.split("#")[0])-1)); replayPathCanvasOverlay.setPathColor(colorPalette.getColor(Integer.parseInt(pathName.split("#")[0])-1));
@@ -205,7 +209,7 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
legendCanvasOverlay.setPathOverlays(replayPathCanvasOverlays); legendCanvasOverlay.setPathOverlays(replayPathCanvasOverlays);
long tmpDurationTime = currentPath.getPathTime(); long tmpDurationTime = currentPath.getPathTime();
if (tmpDurationTime > maxDurationTime) { if ((!currentPath.getMixedLeg())&&(!currentPath.getAlgorithmTimedOut())&&(tmpDurationTime > maxDurationTime)) {
maxDurationTime = tmpDurationTime; maxDurationTime = tmpDurationTime;
} }
} }
@@ -4,12 +4,64 @@
<div id="mainContent"> <div id="mainContent">
<h4 class="articleHeadline">What's New - Strategy Simulator</h4> <h4 class="articleHeadline">What's New - Strategy Simulator</h4>
<div class="innerContent"> <div class="innerContent">
<h5 class="articleSubheadline">September 2014</h5> <h5 class="articleSubheadline">October 2014</h5>
<ul class="bulletList"> <ul class="bulletList">
<li>Point 1... <li>Simulation is being integrated into the race board (see What's New in Sailing Analytics)</li>
</li>
</ul> </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>
</div> </div>
</body> </body>
@@ -13,4 +13,5 @@ Require-Bundle: org.hamcrest;bundle-version="1.1.0",
com.sap.sailing.domain.test, com.sap.sailing.domain.test,
com.sap.sse.common, com.sap.sse.common,
com.sap.sailing.domain.tractracadapter, 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.WindImpl;
import com.sap.sailing.domain.common.impl.WindSpeedSteppingWithMaxDistance; import com.sap.sailing.domain.common.impl.WindSpeedSteppingWithMaxDistance;
import com.sap.sailing.domain.common.tracking.GPSFixMoving; 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.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.MarkPassing; import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace; 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.DynamicGPSFixMovingTrackImpl;
import com.sap.sailing.domain.tracking.impl.WindWithConfidenceImpl; import com.sap.sailing.domain.tracking.impl.WindWithConfidenceImpl;
import com.sap.sailing.polars.mining.PolarDataMiner; 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.TimePoint;
import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -12,8 +12,8 @@ import java.util.Random;
import org.junit.Test; import org.junit.Test;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.regression.IncrementalLeastSquares; 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.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
public class IncrementalLeastSquaresTest { public class IncrementalLeastSquaresTest {
@@ -7,8 +7,8 @@ import static org.junit.Assert.assertTrue;
import org.hamcrest.number.IsCloseTo; import org.hamcrest.number.IsCloseTo;
import org.junit.Test; import org.junit.Test;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.regression.IncrementalLeastSquares; 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.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
public class IncrementalLinearRegressionOrderOneTest { public class IncrementalLinearRegressionOrderOneTest {
@@ -12,7 +12,6 @@ import java.text.ParseException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Executors;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import java.util.stream.Stream; 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.confidence.impl.ScalableWind;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing; 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.test.OnlineTracTracBasedTest;
import com.sap.sailing.domain.tracking.Maneuver; import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tractracadapter.ReceiverType; import com.sap.sailing.domain.tractracadapter.ReceiverType;
import com.sap.sailing.polars.impl.PolarDataServiceImpl; 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.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl.ManeuverClassification;
import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Pair;
import com.sap.sse.util.kmeans.Cluster; import com.sap.sse.util.kmeans.Cluster;
@@ -117,7 +116,7 @@ public class TestWindEstimationFromManeuversOnAFew505Races extends OnlineTracTra
IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException, IOException, InterruptedException, URISyntaxException, ParseException, SubscriberInitializationException,
CreateModelException { CreateModelException {
setUp("event_20110609_KielerWoch-505_Race_3"); 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); getTrackedRace(), /* millisecondsOverWhichToAverage */ 30000, /* waitForLatest */ true);
final Map<Maneuver, Competitor> maneuvers = windTrack.getAllManeuvers(/* waitForLatest */ true); final Map<Maneuver, Competitor> maneuvers = windTrack.getAllManeuvers(/* waitForLatest */ true);
final int numberOfClusters = 16; final int numberOfClusters = 16;
@@ -153,7 +152,7 @@ public class TestWindEstimationFromManeuversOnAFew505Races extends OnlineTracTra
} }
private Wind getManeuverBasedAverageWind() throws NotEnoughDataHasBeenAddedException { 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); getTrackedRace(), /* millisecondsOverWhichToAverage */ 30000, /* waitForLatest */ true);
ScalableWind windSum = null; ScalableWind windSum = null;
int count = 0; int count = 0;
@@ -7,9 +7,7 @@ Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ClassPath: . Bundle-ClassPath: .
Export-Package: Export-Package:
com.sap.sailing.polars,
com.sap.sailing.polars.data, com.sap.sailing.polars.data,
com.sap.sailing.polars.factory,
com.sap.sailing.polars.regression, com.sap.sailing.polars.regression,
com.sap.sailing.polars.windestimation com.sap.sailing.polars.windestimation
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
@@ -21,7 +19,9 @@ Require-Bundle:
com.sap.sse.common, com.sap.sse.common,
com.sap.sse, com.sap.sse,
com.sap.sse.shared.android, 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: Import-Package:
com.sap.sailing.util, com.sap.sailing.util,
com.sap.sse.common 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.PolarSheetsData;
import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.Tack; 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.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.domain.tracking.TrackedRace;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.polars.aggregation.PolarFixAggregator; import com.sap.sailing.polars.aggregation.PolarFixAggregator;
import com.sap.sailing.polars.aggregation.SimplePolarFixRaceInterval; import com.sap.sailing.polars.aggregation.SimplePolarFixRaceInterval;
import com.sap.sailing.polars.data.PolarFix; import com.sap.sailing.polars.data.PolarFix;
import com.sap.sailing.polars.generation.PolarSheetGenerator; import com.sap.sailing.polars.generation.PolarSheetGenerator;
import com.sap.sailing.polars.mining.PolarDataMiner; 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.common.Util.Pair;
import com.sap.sse.util.SmartFutureCache; import com.sap.sse.util.SmartFutureCache;
@@ -41,7 +44,7 @@ public class PolarDataServiceImpl implements PolarDataService {
private final PolarDataMiner polarDataMiner; private final PolarDataMiner polarDataMiner;
public PolarDataServiceImpl(Executor executor) { public PolarDataServiceImpl() {
this.polarDataMiner = new PolarDataMiner(); this.polarDataMiner = new PolarDataMiner();
} }
@@ -158,4 +161,32 @@ public class PolarDataServiceImpl implements PolarDataService {
polarDataMiner.raceFinishedTracking(race); 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.confidence.BearingWithConfidence;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; 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.domain.tracking.WindWithConfidence;
import com.sap.sailing.polars.impl.CubicEquation; import com.sap.sailing.polars.impl.CubicEquation;
import com.sap.sailing.polars.regression.IncrementalLeastSquares; 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.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Pair;
@@ -48,7 +48,7 @@ public class AngleAndSpeedRegression {
double estimatedAngle = angleRegression.getOrCreatePolynomialFunction().value(windSpeedInKnots); double estimatedAngle = angleRegression.getOrCreatePolynomialFunction().value(windSpeedInKnots);
Bearing bearing = new DegreeBearingImpl(estimatedAngle); Bearing bearing = new DegreeBearingImpl(estimatedAngle);
SpeedWithBearing speedWithBearing = new KnotSpeedWithBearingImpl(estimatedSpeed, bearing); 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 { 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.LegType;
import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.Tack; 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.AdditionalResultDataBuilder;
import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.factories.GroupKeyFactory; import com.sap.sse.datamining.factories.GroupKeyFactory;
@@ -34,7 +34,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
private final TrackedRace race; private final TrackedRace race;
private final Competitor competitor; private final Competitor competitor;
private final ClusterGroup<Speed> windSpeedClusterGroup; private final ClusterGroup<Speed> windSpeedClusterGroup;
private final Set<WindSource> windSourcesToExcludeForBearing;
private final Set<WindSource> windSourcesToExcludeForSpeed; private final Set<WindSource> windSourcesToExcludeForSpeed;
private final ClusterGroup<Bearing> angleClusterGroup; private final ClusterGroup<Bearing> angleClusterGroup;
private final BearingWithConfidence<Integer> trueWindAngle; private final BearingWithConfidence<Integer> trueWindAngle;
@@ -48,7 +47,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
this.competitor = competitor; this.competitor = competitor;
this.windSpeedClusterGroup = windSpeedClusterGroup; this.windSpeedClusterGroup = windSpeedClusterGroup;
this.angleClusterGroup = angleClusterGroup; this.angleClusterGroup = angleClusterGroup;
this.windSourcesToExcludeForBearing = collectWindSourcesToIgnoreForBearing();
this.windSourcesToExcludeForSpeed = collectWindSourcesToIgnoreForSpeed(); this.windSourcesToExcludeForSpeed = collectWindSourcesToIgnoreForSpeed();
this.trueWindAngle = computeTrueWindAngle(); this.trueWindAngle = computeTrueWindAngle();
this.wind = race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint(), windSourcesToExcludeForSpeed); this.wind = race.getWindWithConfidence(fix.getPosition(), fix.getTimePoint(), windSourcesToExcludeForSpeed);
@@ -73,7 +71,7 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
private BearingWithConfidence<Integer> computeTrueWindAngle() { private BearingWithConfidence<Integer> computeTrueWindAngle() {
SpeedWithBearing boatSpeed = race.getTrack(competitor).getEstimatedSpeed(fix.getTimePoint()); 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; BearingWithConfidenceImpl<Integer> result = null;
if (wind != null && boatSpeed != null) { if (wind != null && boatSpeed != null) {
@@ -105,32 +103,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
track.getMillisecondsOverWhichToAverageSpeed()/2, /* minimumConfidence */ 0.00000001)); 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() { private Set<WindSource> collectWindSourcesToIgnoreForSpeed() {
Set<WindSource> windSourcesToExclude = new HashSet<WindSource>(); Set<WindSource> windSourcesToExclude = new HashSet<WindSource>();
Iterable<WindSource> combinedSources = race.getWindSources(WindSourceType.COMBINED); 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.LegType;
import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.Tack; 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.components.Processor;
import com.sap.sse.datamining.impl.components.GroupedDataEntry; 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.confidence.BearingWithConfidence;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; 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.domain.tracking.WindWithConfidence;
import com.sap.sailing.polars.regression.MovingAverageBoatSpeedEstimator; 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.TimePoint;
import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Pair;
import com.sap.sse.datamining.AdditionalResultDataBuilder; 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.PolarSheetsDataImpl;
import com.sap.sailing.domain.common.impl.PolarSheetsHistogramDataImpl; import com.sap.sailing.domain.common.impl.PolarSheetsHistogramDataImpl;
import com.sap.sailing.domain.common.impl.WindSpeedSteppingWithMaxDistance; 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.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.polars.impl.CubicEquation; 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.FilterCriterion;
import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.data.ClusterGroup; 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.Speed;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedImpl; 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.IncrementalLeastSquares;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl; import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl;
import com.sap.sse.datamining.AdditionalResultDataBuilder; import com.sap.sse.datamining.AdditionalResultDataBuilder;
import com.sap.sse.datamining.components.Processor; 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 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. * 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 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.Speed;
import com.sap.sailing.domain.common.impl.KnotSpeedImpl; 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.sailing.polars.mining.MovingAverageProcessorImpl;
import com.sap.sse.concurrent.LockUtil; import com.sap.sse.concurrent.LockUtil;
import com.sap.sse.concurrent.NamedReentrantReadWriteLock; 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.RealVector;
import org.apache.commons.math.linear.SingularMatrixException; 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.IncrementalLeastSquares;
import com.sap.sailing.polars.regression.NotEnoughDataHasBeenAddedException;
import com.sap.sse.concurrent.LockUtil; import com.sap.sse.concurrent.LockUtil;
import com.sap.sse.concurrent.NamedReentrantReadWriteLock; 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.impl.WindImpl;
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing; import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableSpeed; 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.Maneuver;
import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.WindTrackImpl; 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.TimePoint;
import com.sap.sse.common.Util; import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair; 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.ManeuverType;
import com.sap.sailing.domain.common.confidence.ConfidenceBasedAverager; import com.sap.sailing.domain.common.confidence.ConfidenceBasedAverager;
import com.sap.sailing.domain.common.confidence.HasConfidenceAndIsScalable; 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.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl.ManeuverClassification;
import com.sap.sse.common.scalablevalue.ScalableValue; 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() { public static RegattaConfigurationJsonSerializer create() {
return new RegattaConfigurationJsonSerializer(RRS26ConfigurationJsonSerializer.create(), return new RegattaConfigurationJsonSerializer(RRS26ConfigurationJsonSerializer.create(),
GateStartConfigurationJsonSerializer.create(), ESSConfigurationJsonSerializer.create(), GateStartConfigurationJsonSerializer.create(), ESSConfigurationJsonSerializer.create(),
RacingProcedureConfigurationJsonSerializer.create()); RacingProcedureConfigurationJsonSerializer.create(), LeagueConfigurationJsonSerializer.create());
} }
public static final Object FIELD_DEFAULT_RACING_PROCEDURE_TYPE = "defaultRacingProcedureType"; 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_RRS26 = "rrs26";
public static final String FIELD_GATE_START = "gateStart"; public static final String FIELD_GATE_START = "gateStart";
public static final String FIELD_ESS = "ess"; public static final String FIELD_ESS = "ess";
public static final String FIELD_LEAGUE = "league";
public static final String FIELD_BASIC = "basic"; public static final String FIELD_BASIC = "basic";
private final JsonSerializer<RacingProcedureConfiguration> rrs26Serializer; private final JsonSerializer<RacingProcedureConfiguration> rrs26Serializer;
private final JsonSerializer<RacingProcedureConfiguration> gateStartSerializer; private final JsonSerializer<RacingProcedureConfiguration> gateStartSerializer;
private final JsonSerializer<RacingProcedureConfiguration> essSerializer; private final JsonSerializer<RacingProcedureConfiguration> essSerializer;
private final JsonSerializer<RacingProcedureConfiguration> basicSerializer; private final JsonSerializer<RacingProcedureConfiguration> basicSerializer;
private final JsonSerializer<RacingProcedureConfiguration> leagueSerializer;
public RegattaConfigurationJsonSerializer(JsonSerializer<RacingProcedureConfiguration> rrs26, public RegattaConfigurationJsonSerializer(JsonSerializer<RacingProcedureConfiguration> rrs26,
JsonSerializer<RacingProcedureConfiguration> gateStart, JsonSerializer<RacingProcedureConfiguration> ess, JsonSerializer<RacingProcedureConfiguration> gateStart, JsonSerializer<RacingProcedureConfiguration> ess,
JsonSerializer<RacingProcedureConfiguration> basicSerializer) { JsonSerializer<RacingProcedureConfiguration> basicSerializer, JsonSerializer<RacingProcedureConfiguration> leagueSerializer) {
this.rrs26Serializer = rrs26; this.rrs26Serializer = rrs26;
this.gateStartSerializer = gateStart; this.gateStartSerializer = gateStart;
this.essSerializer = ess; this.essSerializer = ess;
this.basicSerializer = basicSerializer; this.basicSerializer = basicSerializer;
this.leagueSerializer = leagueSerializer;
} }
@Override @Override
@@ -59,6 +62,10 @@ public class RegattaConfigurationJsonSerializer implements JsonSerializer<Regatt
if (object.getBasicConfiguration() != null) { if (object.getBasicConfiguration() != null) {
result.put(FIELD_BASIC, basicSerializer.serialize(object.getBasicConfiguration())); result.put(FIELD_BASIC, basicSerializer.serialize(object.getBasicConfiguration()));
} }
if (object.getLeagueConfiguration() != null) {
result.put(FIELD_LEAGUE, leagueSerializer.serialize(object.getLeagueConfiguration()));
}
return result; return result;
} }
@@ -5,10 +5,7 @@ Bundle-SymbolicName: com.sap.sailing.server.gateway
Bundle-Version: 1.0.0.qualifier Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: com.sap.sailing.polars, Import-Package: com.sap.sailing.server,
com.sap.sailing.polars.regression,
com.sap.sailing.polars.windestimation,
com.sap.sailing.server,
com.sap.sailing.server.operationaltransformation, com.sap.sailing.server.operationaltransformation,
javax.ws.rs;version="1.1.1", javax.ws.rs;version="1.1.1",
javax.ws.rs.core;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.core;bundle-version="1.2.2",
org.apache.shiro.web;bundle-version="1.2.2", org.apache.shiro.web;bundle-version="1.2.2",
org.apache.shiro.ehcache;bundle-version="1.2.3", 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: . Bundle-ClassPath: .
Web-ContextPath: /sailingserver Web-ContextPath: /sailingserver
Export-Package: com.sap.sailing.server.gateway, 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.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedImpl; import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing; 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.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;
import com.sap.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl.ManeuverClassification; import com.sap.sailing.polars.windestimation.ManeuverBasedWindEstimationTrackImpl.ManeuverClassification;
import com.sap.sailing.polars.windestimation.ScalableBearingAndScalableDouble; import com.sap.sailing.polars.windestimation.ScalableBearingAndScalableDouble;
@@ -691,6 +691,19 @@ public class MasterDataImportTest {
} finally { } finally {
windTrackOnDest.unlockAfterRead(); 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();
}
} }
@@ -6,9 +6,7 @@ Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.sap.sailing.server.impl.Activator Bundle-Activator: com.sap.sailing.server.impl.Activator
Bundle-Vendor: SAP Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: com.sap.sailing.polars, Import-Package: com.sap.sailing.server.gateway.deserialization,
com.sap.sailing.polars.factory,
com.sap.sailing.server.gateway.deserialization,
org.json.simple, org.json.simple,
org.json.simple.parser, org.json.simple.parser,
org.osgi.framework;version="1.3.0", org.osgi.framework;version="1.3.0",
@@ -24,14 +22,14 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.udpconnector, com.sap.sailing.udpconnector,
com.sap.sailing.domain.shared.android, com.sap.sailing.domain.shared.android,
com.sap.sailing.server.gateway.serialization, com.sap.sailing.server.gateway.serialization,
com.sap.sailing.polars,
com.sap.sse.common, com.sap.sse.common,
com.sap.sse.operationaltransformation, com.sap.sse.operationaltransformation,
com.sap.sse.replication, com.sap.sse.replication,
com.sap.sse, com.sap.sse,
com.sap.sailing.server.gateway.serialization.shared.android, com.sap.sailing.server.gateway.serialization.shared.android,
com.sap.sse.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: . Bundle-ClassPath: .
Export-Package: com.sap.sailing.server, Export-Package: com.sap.sailing.server,
com.sap.sailing.server.impl; com.sap.sailing.server.impl;
@@ -43,5 +41,6 @@ Export-Package: com.sap.sailing.server,
com.sap.sailing.server.replication.test, com.sap.sailing.server.replication.test,
com.sap.sailing.domain.racelogtrackingadapter.test", com.sap.sailing.domain.racelogtrackingadapter.test",
com.sap.sailing.server.masterdata, 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.leaderboard.ScoringScheme;
import com.sap.sailing.domain.persistence.DomainObjectFactory; import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory; 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.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike; import com.sap.sailing.domain.regattalike.LeaderboardThatHasRegattaLike;
import com.sap.sailing.domain.tracking.DynamicTrackedRace; 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.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.TrackerManager; import com.sap.sailing.domain.tracking.TrackerManager;
import com.sap.sailing.domain.tracking.WindStore; 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.masterdata.DataImportLockWithProgress;
import com.sap.sailing.server.simulation.SimulationService;
import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TypeBasedServiceFinderFactory; import com.sap.sse.common.TypeBasedServiceFinderFactory;
import com.sap.sse.common.Util; import com.sap.sse.common.Util;
@@ -521,7 +522,9 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
WindStore getWindStore(); WindStore getWindStore();
PolarDataService getPolarDataService(); PolarDataService getPolarDataService();
SimulationService getSimulationService();
GPSFixStore getGPSFixStore(); GPSFixStore getGPSFixStore();
RaceTracker getRaceTrackerById(Object id); 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.GPSFixMongoHandler;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMongoHandlerImpl; 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.persistence.racelog.tracking.impl.GPSFixMovingMongoHandlerImpl;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.server.MasterDataImportClassLoaderService; import com.sap.sailing.server.MasterDataImportClassLoaderService;
import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.RacingEventServiceMXBean; import com.sap.sailing.server.RacingEventServiceMXBean;
@@ -55,6 +56,8 @@ public class Activator implements BundleActivator {
private ServiceTracker<MasterDataImportClassLoaderService, MasterDataImportClassLoaderService> masterDataImportClassLoaderServiceTracker; private ServiceTracker<MasterDataImportClassLoaderService, MasterDataImportClassLoaderService> masterDataImportClassLoaderServiceTracker;
private ServiceTracker<PolarDataService, PolarDataService> polarDataServiceTracker;
public Activator() { public Activator() {
clearPersistentCompetitors = Boolean.valueOf(System.getProperty(CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME, ""+false)); clearPersistentCompetitors = Boolean.valueOf(System.getProperty(CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME, ""+false));
logger.log(Level.INFO, "setting "+CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME+" to "+clearPersistentCompetitors); logger.log(Level.INFO, "setting "+CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME+" to "+clearPersistentCompetitors);
@@ -77,6 +80,10 @@ public class Activator implements BundleActivator {
context, MasterDataImportClassLoaderService.class, context, MasterDataImportClassLoaderService.class,
new MasterDataImportClassLoaderServiceTrackerCustomizer(context, racingEventService)); new MasterDataImportClassLoaderServiceTrackerCustomizer(context, racingEventService));
masterDataImportClassLoaderServiceTracker.open(); masterDataImportClassLoaderServiceTracker.open();
polarDataServiceTracker = new ServiceTracker<PolarDataService, PolarDataService>(context,
PolarDataService.class, new PolarDataServiceTrackerCustomizer(context, racingEventService));
polarDataServiceTracker.open();
// register the racing service in the OSGi registry // register the racing service in the OSGi registry
racingEventService.setBundleContext(context); racingEventService.setBundleContext(context);
@@ -86,14 +93,22 @@ public class Activator implements BundleActivator {
context.registerService(RacingEventService.class.getName(), racingEventService, null); context.registerService(RacingEventService.class.getName(), racingEventService, null);
context.registerService(ClearStateTestSupport.class.getName(), racingEventService, null); context.registerService(ClearStateTestSupport.class.getName(), racingEventService, null);
Dictionary<String, String> properties = new Hashtable<String, String>(); Dictionary<String, String> properties = new Hashtable<String, String>();
final GPSFixMongoHandlerImpl gpsFixMongoHandler = new GPSFixMongoHandlerImpl(racingEventService.getMongoObjectFactory(),
racingEventService.getDomainObjectFactory());
properties.put(TypeBasedServiceFinder.TYPE, GPSFixImpl.class.getName()); properties.put(TypeBasedServiceFinder.TYPE, GPSFixImpl.class.getName());
registrations.add(context.registerService(GPSFixMongoHandler.class, registrations.add(context.registerService(GPSFixMongoHandler.class,
new GPSFixMongoHandlerImpl(racingEventService.getMongoObjectFactory(), gpsFixMongoHandler, properties));
racingEventService.getDomainObjectFactory()), properties)); // legacy type name; some DBs may still contain fixes marked with this old package name:
properties.put(TypeBasedServiceFinder.TYPE, GPSFixMovingImpl.class.getName()); properties.put(TypeBasedServiceFinder.TYPE, "com.sap.sailing.domain.tracking.impl.GPSFixImpl");
registrations.add(context.registerService(GPSFixMongoHandler.class, registrations.add(context.registerService(GPSFixMongoHandler.class,
new GPSFixMovingMongoHandlerImpl(racingEventService.getMongoObjectFactory(), gpsFixMongoHandler, properties));
racingEventService.getDomainObjectFactory()), 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: // Add an MBean for the service to the JMX bean server:
RacingEventServiceMXBean mbean = new RacingEventServiceMXBeanImpl(racingEventService); RacingEventServiceMXBean mbean = new RacingEventServiceMXBeanImpl(racingEventService);
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
@@ -156,5 +171,34 @@ 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.MediaDB;
import com.sap.sailing.domain.persistence.media.MediaDBFactory; import com.sap.sailing.domain.persistence.media.MediaDBFactory;
import com.sap.sailing.domain.persistence.racelog.tracking.MongoGPSFixStoreFactory; 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.RaceLogIdentifier;
import com.sap.sailing.domain.racelog.RaceLogStore; import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore; 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.DynamicGPSFixTrackImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl; import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory; 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.RacingEventService;
import com.sap.sailing.server.Replicator; import com.sap.sailing.server.Replicator;
import com.sap.sailing.server.gateway.deserialization.impl.CourseAreaJsonDeserializer; 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.UpdateTrackedRaceStatus;
import com.sap.sailing.server.operationaltransformation.UpdateWindAveragingTime; import com.sap.sailing.server.operationaltransformation.UpdateWindAveragingTime;
import com.sap.sailing.server.operationaltransformation.UpdateWindSourcesToExclude; 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.BuildVersion;
import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TypeBasedServiceFinderFactory; import com.sap.sse.common.TypeBasedServiceFinderFactory;
@@ -351,7 +352,9 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
private final AbstractLogEventAuthor raceLogEventAuthorForServer = new LogEventAuthorImpl( private final AbstractLogEventAuthor raceLogEventAuthorForServer = new LogEventAuthorImpl(
RacingEventService.class.getName(), 0); 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 * 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<>(); operationExecutionListeners = new ConcurrentHashMap<>();
courseListeners = new ConcurrentHashMap<>(); courseListeners = new ConcurrentHashMap<>();
persistentRegattasForRaceIDs = new ConcurrentHashMap<>(); persistentRegattasForRaceIDs = new ConcurrentHashMap<>();
final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3); final int SIMULATION_THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors()/3, 1);
// TODO find out how many executors we have on server side and how to manage them Executor simulatorExecutor = new ThreadPoolExecutor(/* corePoolSize */SIMULATION_THREAD_POOL_SIZE,
Executor polarExecutor = new ThreadPoolExecutor(/* corePoolSize */THREAD_POOL_SIZE, /* maximumPoolSize */SIMULATION_THREAD_POOL_SIZE,
/* maximumPoolSize */THREAD_POOL_SIZE,
/* keepAliveTime */60, TimeUnit.SECONDS, /* keepAliveTime */60, TimeUnit.SECONDS,
/* workQueue */new LinkedBlockingQueue<Runnable>()); /* 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.raceLogReplicator = new RaceLogReplicator(this);
this.regattaLogReplicator = new RegattaLogReplicator(this); this.regattaLogReplicator = new RegattaLogReplicator(this);
this.raceLogScoringReplicator = new RaceLogScoringReplicator(this); this.raceLogScoringReplicator = new RaceLogScoringReplicator(this);
@@ -559,6 +562,11 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
return polarDataService; return polarDataService;
} }
@Override
public SimulationService getSimulationService() {
return simulationService;
}
@Override @Override
public void clearState() throws Exception { public void clearState() throws Exception {
for (String leaderboardGroupName : new ArrayList<>(this.leaderboardGroupsByName.keySet())) { for (String leaderboardGroupName : new ArrayList<>(this.leaderboardGroupsByName.keySet())) {
@@ -1526,6 +1534,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
PolarFixCacheUpdater polarFixCacheUpdater = new PolarFixCacheUpdater(trackedRace); PolarFixCacheUpdater polarFixCacheUpdater = new PolarFixCacheUpdater(trackedRace);
polarFixCacheUpdaters.put(trackedRace, polarFixCacheUpdater); polarFixCacheUpdaters.put(trackedRace, polarFixCacheUpdater);
trackedRace.addListener(polarFixCacheUpdater); trackedRace.addListener(polarFixCacheUpdater);
if (polarDataService != null) {
trackedRace.setPolarDataService(polarDataService);
}
} }
} }
@@ -1539,14 +1551,18 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
@Override @Override
public void competitorPositionChanged(GPSFixMoving fix, Competitor item) { public void competitorPositionChanged(GPSFixMoving fix, Competitor item) {
polarDataService.competitorPositionChanged(fix, item, race); if (polarDataService != null) {
polarDataService.competitorPositionChanged(fix, item, race);
}
} }
@Override @Override
public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) { public void statusChanged(TrackedRaceStatus newStatus, TrackedRaceStatus oldStatus) {
if (oldStatus.getStatus() == TrackedRaceStatusEnum.LOADING if (oldStatus.getStatus() == TrackedRaceStatusEnum.LOADING
&& newStatus.getStatus() != TrackedRaceStatusEnum.LOADING) { && newStatus.getStatus() != TrackedRaceStatusEnum.LOADING) {
polarDataService.raceFinishedLoading(race); if (polarDataService != null) {
polarDataService.raceFinishedLoading(race);
}
} }
} }
@@ -3113,4 +3129,31 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
JoinedClassLoader joinedClassLoader = new JoinedClassLoader(masterDataClassLoaders); JoinedClassLoader joinedClassLoader = new JoinedClassLoader(masterDataClassLoaders);
return joinedClassLoader; 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