Merge branch 'ubilabs--ios--develop' of ssh://sapsailing.com/home/trac/git into ubilabs--ios--develop

This commit is contained in:
Raimund Wege committed 2015-06-02 08:12:50 +02:00
commit ba0a7a97f7
1785 files changed
+70441 -24532

No files matched your search

+35 -21
View File
@@ -1,21 +1,35 @@
/target
www-test
war
build.log
reporting.log
.metadata
*.class
*.swp
*~
manifest.txt
java/com.sap.sailing.gwt.ui/gwt-unitCache/*
java/com.sap.sailing.gwt.ui/war/WEB-INF/deploy/*
java/com.sap.sse.security.ui/WEB-INF/deploy/*
sailing_debug0*
dist
build
/java/.settings/org.eclipse.jdt.core.prefs
/java/com.sap.sailing.server.gateway.serialization.test/.settings/*.prefs
.DS_Store
java/com.sap.sailing.simulator/bin/com/sap/sailing/simulator/Simulator.gwt.xml
/mobile/com.sap.sailing.racecommittee.app/res/values/keys.xml
/target
www-test
war
build.log
reporting.log
.metadata
*.class
*.swp
*~
manifest.txt
java/com.sap.sailing.gwt.ui/gwt-unitCache/*
java/com.sap.sailing.gwt.ui/war/WEB-INF/deploy/*
java/com.sap.sse.security.ui/WEB-INF/deploy/*
sailing_debug0*
dist
build
/java/.settings/org.eclipse.jdt.core.prefs
/java/com.sap.sailing.server.gateway.serialization.test/.settings/*.prefs
.DS_Store
java/com.sap.sailing.simulator/bin/com/sap/sailing/simulator/Simulator.gwt.xml
/mobile/com.sap.sailing.racecommittee.app/res/values/keys.xml
java/com.sap.sailing.gwt.ui/SailingGWT Remote Profiling (Run-Mode only).launch
java/com.sap.sailing.gwt.ui/SailingGWT.launch
## Android Studio and Intellij and Android in general
gen/
.idea/
*.ipr
*.iws
*.iml
out/
.gradle
local.properties
git.xml
build.info
@@ -2,6 +2,8 @@
For wind measurements we're trying to consistently use Igtimi WindBot equipment. The AdminConsole has a tab "Igtimi Accounts" where accounts for the Igtimi YachtBot web site can be managed. WindBots associated with any of these accounts will feed their wind readings, when active, into races being tracked. Operations of the WindBots mainly needs to take care of charging the devices, turning them on when they leave the harbor and turning them off when they leave the race course. This can also be delegated to race officials carrying these devices on their vessels.
# Status LEDs
The devices have three LEDs whose status works as follows:
1. The three LED’s are “power”, “connection”, and “GPS” in order from top to bottom.
@@ -10,4 +12,16 @@ The devices have three LEDs whose status works as follows:
4. Fast flashing means that function can’t start or has failed - e.g. SIM not inserted. i.e. you shouldn’t see this
5. During sync, the “power” light blips and the “connection” LED should stay on until the sync has finished.
More information on running the WindBots can be found [here](https://igtimi.desk.com/customer/portal/articles/1494533-yachtbot-tracker-basic-operation?b_id=1690).
More information on running the WindBots can be found [here](https://igtimi.desk.com/customer/portal/articles/1494533-yachtbot-tracker-basic-operation?b_id=1690).
# Update Firmware
[How to update the firmware](https://igtimi.desk.com/customer/portal/articles/1122866-how-to-update-the-firmware-in-the-yachtbot-trackers?b_id=1690)
# WindBot User Guide (v. 1.0 R3)
[User Guide v. 1.0 R3](wiki/uploads/WindBot%20User%20Guide%201.0%20R3.pdf)
# Is the WindBot waterproof and does it sink if dropped it in the water?
Yes and yes.
+22
View File
@@ -0,0 +1,22 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
}
}
allprojects {
repositories {
mavenCentral()
}
version = "1.0.0-SNAPSHOT"
tasks.withType(JavaCompile) {
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
}
}
+25
View File
@@ -0,0 +1,25 @@
#!/bin/bash
# Originally written by Ralf Kistner <ralf@embarkmobile.com>, but placed in the public domain
set +e
bootanim=""
failcounter=0
timeout_in_sec=600
until [[ "$bootanim" =~ "stopped" ]]; do
bootanim=`adb -e shell getprop init.svc.bootanim 2>&1 &`
if [[ "$bootanim" =~ "device not found" || "$bootanim" =~ "device offline"
|| "$bootanim" =~ "running" ]]; then
let "failcounter += 1"
echo "Waiting for emulator to start"
if [[ $failcounter -gt timeout_in_sec ]]; then
echo "Timeout ($timeout_in_sec seconds) reached; failed to start emulator"
exit 1
fi
fi
sleep 1
done
echo "Emulator is ready"
+64 -3
View File
@@ -190,15 +190,20 @@ if [[ $@ == "" ]]; then
exit 2
fi
rm $START_DIR/build.log
if [[ "$@" == "clean" ]]; then
./gradlew clean
if [[ $? != 0 ]]; then
exit 100
fi
cd $PROJECT_HOME/java
rm -rf com.sap.$PROJECT_TYPE.gwt.ui/com.sap.$PROJECT_TYPE.*
rm -rf com.sap.sse.security.ui/com.sap.sse.security.ui.*
cd $PROJECT_HOME
echo "Using following command: mvn $extra -DargLine=\"$APP_PARAMETERS\" -fae -s $MAVEN_SETTINGS $clean"
echo "Maven version used: `mvn --version`"
mvn $extra -DargLine="$APP_PARAMETERS" -fae -s $MAVEN_SETTINGS $clean 2>&1 | tee $START_DIR/build.log
mvn $extra -DargLine="$APP_PARAMETERS" -fae -s $MAVEN_SETTINGS $clean 2>&1 | tee -a $START_DIR/build.log
MVN_EXIT_CODE=${PIPESTATUS[0]}
echo "Maven exit code is $MVN_EXIT_CODE"
exit 0
@@ -533,8 +538,10 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
echo "INFO: Activating proxy profile"
extra="$extra -P no-debug.with-proxy"
MAVEN_SETTINGS=$MAVEN_SETTINGS_PROXY
ANDROID_OPTIONS="--proxy-host proxy --proxy-port 8080"
else
extra="$extra -P no-debug.without-proxy"
ANDROID_OPTIONS=""
fi
cd $PROJECT_HOME/java
@@ -570,7 +577,7 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
#build local p2 repo
echo "Using following command (pwd: java/com.sap.sailing.targetplatform.base): mvn -fae -s $MAVEN_SETTINGS $clean compile"
echo "Maven version used: `mvn --version`"
(cd com.sap.$PROJECT_TYPE.targetplatform.base; mvn -fae -s $MAVEN_SETTINGS $clean compile 2>&1 | tee $START_DIR/build.log)
(cd com.sap.$PROJECT_TYPE.targetplatform.base; mvn -fae -s $MAVEN_SETTINGS $clean compile 2>&1 | tee -a $START_DIR/build.log)
# now get the exit status from mvn, and not that of tee which is what $? contains now
MVN_EXIT_CODE=${PIPESTATUS[0]}
echo "Maven exit code is $MVN_EXIT_CODE"
@@ -612,6 +619,10 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
echo "ANDROID_HOME=$ANDROID_HOME"
PATH=$PATH:$ANDROID_HOME/tools
PATH=$PATH:$ANDROID_HOME/platform-tools
ANDROID="$ANDROID_HOME/tools/android"
if [ \! -x "$ANDROID" ]; then
ANDROID="$ANDROID_HOME/tools/android.bat"
fi
RC_APP_VERSION=`grep "android:versionCode=" mobile/com.sap.$PROJECT_TYPE.racecommittee.app/AndroidManifest.xml | cut -d "\"" -f 2`
echo "RC_APP_VERSION=$RC_APP_VERSION"
@@ -620,6 +631,56 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
TRACKING_APP_VERSION=`grep "android:versionCode=" mobile/com.sap.$PROJECT_TYPE.android.tracking.app/AndroidManifest.xml | cut -d "\"" -f 2`
echo "TRACKING_APP_VERSION=$TRACKING_APP_VERSION"
extra="$extra -Dtracking-app-version=$TRACKING_APP_VERSION"
NOW=$(date +"%s")
BUILD_TOOLS=22.0.0
TARGET_API=22
TEST_API=18
ANDROID_ABI=armeabi-v7a
AVD_NAME="androidTest-${NOW}"
echo "Updating Android SDK (tools)..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter tools --no-ui --force --all > /dev/null
echo "Updating Android SDK (platform-tools)..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter platform-tools --no-ui --force --all > /dev/null
echo "Updating Android SDK (build-tools-${BUILD_TOOLS})..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter build-tools-${BUILD_TOOLS} --no-ui --force --all > /dev/null
echo "Updating Android SDK (android-${TARGET_API})..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter android-${TARGET_API} --no-ui --force --all > /dev/null
echo "Updating Android SDK (extra-android-m2repository)..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter extra-android-m2repository --no-ui --force --all > /dev/null
echo "Updating Android SDK (extra-google-m2repository)..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter extra-google-m2repository --no-ui --force --all > /dev/null
./gradlew clean build | tee -a $START_DIR/build.log
if [[ $? != 0 ]]; then
exit 100
fi
# testing deactivated due to errors in hudson
if [ $testing -eq 1 ]; then
adb emu kill
echo "Downloading image (sys-img-${ANDROID_ABI}-android-${TEST_API})..." | tee -a $START_DIR/build.log
echo yes | "$ANDROID" update sdk $ANDROID_OPTIONS --filter sys-img-${ANDROID_ABI}-android-${TEST_API} --no-ui --force --all > /dev/null
echo no | "$ANDROID" create avd --name ${AVD_NAME} --target android-${TEST_API} --abi ${ANDROID_ABI} --force -p ${START_DIR}/emulator
echo "Starting emulator..." | tee -a $START_DIR/build.log
emulator -avd ${AVD_NAME} -no-skin -no-audio -no-window &
echo "Waiting for startup..." | tee -a $START_DIR/build.log
adb wait-for-device
sleep 60
$PROJECT_HOME/configuration/androidWaitForEmulator.sh
if [[ $? != 0 ]]; then
adb emu kill
"$ANDROID" delete avd --name ${AVD_NAME}
exit 102
fi
adb shell input keyevent 82 &
./gradlew deviceCheck connectedCheck | tee -a $START_DIR/build.log
if [[ $? != 0 ]]; then
adb emu kill
"$ANDROID" delete avd --name ${AVD_NAME}
exit 101
fi
adb emu kill
"$ANDROID" delete avd --name ${AVD_NAME}
fi
else
echo "INFO: Deactivating mobile modules"
extra="$extra -P !with-mobile"
@@ -636,7 +697,7 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
echo "Using following command: mvn $extra -DargLine=\"$APP_PARAMETERS\" -fae -s $MAVEN_SETTINGS $clean install"
echo "Maven version used: `mvn --version`"
mvn $extra -DargLine="$APP_PARAMETERS" -fae -s $MAVEN_SETTINGS $clean install 2>&1 | tee $START_DIR/build.log
mvn $extra -DargLine="$APP_PARAMETERS" -fae -s $MAVEN_SETTINGS $clean install 2>&1 | tee -a $START_DIR/build.log
# now get the exit status from mvn, and not that of tee which is what $? contains now
MVN_EXIT_CODE=${PIPESTATUS[0]}
echo "Maven exit code is $MVN_EXIT_CODE"
+59
View File
@@ -0,0 +1,59 @@
#!/bin/sh
find_project_home ()
{
if [[ "$1" == '/' ]] || [[ "$1" == "" ]]; then
echo ""
return 0
fi
if [ ! -d "$1/.git" ]; then
PARENT_DIR="`cd "$1/..";pwd`"
OUTPUT=$(find_project_home "$PARENT_DIR")
if [ "$OUTPUT" = "" ] && [ -d "$PARENT_DIR/$CODE_DIRECTORY" ] && [ -d "$PARENT_DIR/$CODE_DIRECTORY/.git" ]; then
OUTPUT="$PARENT_DIR/$CODE_DIRECTORY"
fi
echo $OUTPUT
return 0
fi
echo $1 | sed -e 's/\/cygdrive\/\([a-zA-Z]\)/\1:/'
}
sign_apk()
{
ALIAS=$1
PROJECT_NAME=$2
PROJECT_UNALIGNED=$PROJECT_NAME-unaligned.apk
cd $PROJECT_HOME/mobile/$PROJECT_NAME/build/outputs/apk
rm $PROJECT_NAME.apk
cp $PROJECT_NAME-release-unsigned.apk $PROJECT_UNALIGNED
jarsigner -verbose -tsa -sigalg SHA1withRSA -digestalg SHA1 -keystore $PROJECT_HOME/mobile/android-keystore/STG.jks $PROJECT_UNALIGNED $ALIAS
$ANDROID_HOME/build-tools/$BUILD_TOOLS/zipalign -v 4 $PROJECT_UNALIGNED $PROJECT_NAME.apk
}
if [ $# -eq 0 ]; then
echo "Usage: $0 <key_alias>"
exit 2
fi
# this holds for default installation
BUILD_TOOLS="21.1.2"
USER_HOME=~
START_DIR="`pwd`"
if [ "$PROJECT_HOME" = "" ]; then
PROJECT_HOME=$(find_project_home "$START_DIR")
fi
# if project_home is still empty we could not determine any suitable directory
if [[ "$PROJECT_HOME" == "" ]]; then
echo "Could neither determine nor get PROJECT_HOME. Please provide it by setting an environment variable with this name."
exit 1
fi
sign_apk $1 com.sap.sailing.android.tracking.app
sign_apk $1 com.sap.sailing.racecommittee.app
+18
View File
@@ -0,0 +1,18 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
#Wed Apr 10 15:27:10 PDT 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
Vendored Executable
+164
View File
@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
Vendored
+90
View File
@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@@ -0,0 +1,7 @@
apply plugin: "java"
sourceSets {
main {
java.srcDirs = ["src"]
}
}
@@ -77,4 +77,62 @@
height: 22.5pt;
z-index: 1;
}
.wrongOrientationNotification {
position: absolute !important;
top: 50%;
right: 50%;
background-color: white;
z-index: 2;
}
.wrongOrientationNotification_shown {
width: 200px;
height: 200px;
margin-right: -100px;
margin-top: -100px;
border-radius: 100px;
-webkit-transition: all 700ms cubic-bezier(0.480, 0, 0.000, 1);
/* older webkit */
-webkit-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 1.250);
-moz-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 1.250);
-o-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 1.250);
transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 1.250);
opacity: 1.0;
}
.wrongOrientationNotification_hidden {
width: 0px;
height: 0px;
marin-right: 0px;
margin-top: 0px;
border-radius: 0px;
overflow: hidden;
-webkit-transition: all 300ms;
/* older webkit */
-webkit-transition: all 300ms;
-moz-transition: all 300ms;
-o-transition: all 300ms;
transition: all 300ms;
opacity: 0.0;
}
.wrongOrientationNotification_logo {
max-width: 40%;
max-height: 40%;
margin: 30%;
margin-top: 23%
}
.wrongOrientationNotification_text {
position: absolute;
width: 100%;
height: 14px;
top: 76%;
line-height: 10px;
text-align: center;
font-weight: bold;
font-size: 13px;
color: grey;
font-family: "Arial";
}
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="false"/>
<stringAttribute key="com.google.gwt.eclipse.core.CODE_SERVER_PORT" value="9998"/>
<booleanAttribute key="com.google.gwt.eclipse.core.CODE_SERVER_PORT_AUTO" value="true"/>
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
<listEntry value="com.sap.sailing.dashboards.gwt.RibDashboard"/>
</listAttribute>
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/dashboards/RibDashboard.html"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/com.sap.sailing.dashboards.gwt"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.dashboards.gwt/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.dashboards.gwt/src/main/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.server/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;com.sap.sailing.dashboards.gwt&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.google.gwt.osgi/lib/gwt-servlet.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.google.gwt.osgi/lib/gwt-user.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.moxieapps.gwt.highcharts/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.adminconsole/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -incremental -war &quot;${project_loc:com.sap.sailing.dashboards.gwt}&quot; -startupUrl /dashboards/RibDashboard.html -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort auto com.sap.sailing.dashboards.gwt.RibDashboard"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.dashboards.gwt"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m"/>
</launchConfiguration>
@@ -4,6 +4,20 @@
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.eclipse.jetty.servlet.DefaultServlet
</servlet-class>
<init-param>
<param-name>dirAllowed</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>useFileMappedBuffer</param-name>
<param-value>false</param-value>
</init-param>
</servlet>
<servlet>
<display-name>Rib Dashboard Service</display-name>
<servlet-name>RibDashboardService</servlet-name>
@@ -8,6 +8,8 @@ import com.googlecode.mgwt.ui.client.MGWTSettings;
import com.googlecode.mgwt.ui.client.MGWTSettings.StatusBarStyle;
import com.googlecode.mgwt.ui.client.MGWTSettings.ViewPort;
import com.googlecode.mgwt.ui.client.MGWTStyle;
import com.sap.sailing.dashboards.gwt.client.dataretriever.RibDashboardDataRetriever;
import com.sap.sailing.dashboards.gwt.client.dataretriever.WindBotDataRetriever;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
@@ -61,6 +63,6 @@ public class RibDashboardEntryPoint extends AbstractEntryPoint<StringMessages> {
@Override
protected StringMessages createStringMessages() {
return GWT.create(StringMessages.class);
return StringMessages.INSTANCE;
}
}
@@ -41,4 +41,7 @@ public interface RibDashboardImageResources extends ClientBundle {
@Source("images/settings.png")
ImageResource settings();
@Source("images/rotatedevice.png")
ImageResource rotatedevice();
}
@@ -17,6 +17,12 @@ import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.Widget;
import com.googlecode.mgwt.ui.client.widget.carousel.Carousel;
import com.sap.sailing.dashboards.gwt.client.dataretriever.NumberOfWindBotsChangeListener;
import com.sap.sailing.dashboards.gwt.client.dataretriever.RibDashboardDataRetriever;
import com.sap.sailing.dashboards.gwt.client.dataretriever.RibDashboardDataRetrieverListener;
import com.sap.sailing.dashboards.gwt.client.dataretriever.WindBotDataRetrieverProvider;
import com.sap.sailing.dashboards.gwt.client.eventlogo.EventLogo;
import com.sap.sailing.dashboards.gwt.client.notifications.WrongDeviceOrientationNotification;
import com.sap.sailing.dashboards.gwt.client.startanalysis.StartlineAnalysisComponent;
import com.sap.sailing.dashboards.gwt.client.startlineadvantage.StartLineAdvantageComponent;
import com.sap.sailing.dashboards.gwt.client.windchart.WindBotComponent;
@@ -89,9 +95,10 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr
initWidget(uiBinder.createAndBindUi(this));
initLogos();
windcharthint.getElement().setInnerText(stringConstants.dashboardWindChartHint());
windloadinghintleft.setInnerText(stringConstants.dashboardWindBotLoading());
windloadinghintright.setInnerText(stringConstants.dashboardWindBotLoading());
loadAndDisplayEventLogo(sailingServiceAsync);
windloadinghintleft.setInnerHTML(stringConstants.dashboardWindBotLoadingText()+"<br>"+stringConstants.dashboardWindBotLoadingMessage());
windloadinghintright.setInnerHTML(stringConstants.dashboardWindBotLoadingText()+"<br>"+stringConstants.dashboardWindBotLoadingMessage());
loadAndAddEventLogo(sailingServiceAsync);
initAndAddWrongOrientationNotification();
}
private void initLogos() {
@@ -101,7 +108,7 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr
Document.get().getBody().appendChild(logo.getElement());
}
private void loadAndDisplayEventLogo(SailingServiceAsync sailingServiceAsync){
private void loadAndAddEventLogo(SailingServiceAsync sailingServiceAsync){
String eventId = Window.Location.getParameter(EVENT_ID_PARAMETER);
if (eventId != null) {
EventLogo eventLogo = EventLogo.getEventLogoFromEventId(sailingServiceAsync, eventId);
@@ -110,6 +117,11 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr
}
}
}
private void initAndAddWrongOrientationNotification(){
WrongDeviceOrientationNotification wrongDeviceOrientationNotification = new WrongDeviceOrientationNotification();
Document.get().getBody().appendChild(wrongDeviceOrientationNotification.getElement());
}
private void initWindBotComponents(List<String> windBotIDs,
WindBotDataRetrieverProvider windBotDataRetrieverProvider) {
@@ -1,4 +1,4 @@
package com.sap.sailing.dashboards.gwt.client;
package com.sap.sailing.dashboards.gwt.client.dataretriever;
import java.util.List;
@@ -1,4 +1,4 @@
package com.sap.sailing.dashboards.gwt.client;
package com.sap.sailing.dashboards.gwt.client.dataretriever;
import java.util.ArrayList;
import java.util.Collections;
@@ -7,6 +7,7 @@ import java.util.List;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.dashboards.gwt.client.RibDashboardServiceAsync;
import com.sap.sailing.dashboards.gwt.client.actions.GetRibDashboardRaceInfoAction;
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
@@ -1,7 +1,7 @@
/**
*
*/
package com.sap.sailing.dashboards.gwt.client;
package com.sap.sailing.dashboards.gwt.client.dataretriever;
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
@@ -1,8 +1,10 @@
package com.sap.sailing.dashboards.gwt.client;
package com.sap.sailing.dashboards.gwt.client.dataretriever;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
@@ -24,9 +26,13 @@ public class WindBotDataRetriever implements TimeListener, RaceSelectionChangeLi
private List<WindBotDataRetrieverListener> windBotDataRetrieverListeners;
private List<String> windBotIDsInLiveRace;
private static final int WIND_CHART_RESOLUTION_IN_MILLISECONDS = 5000;
public static final String LODA_WIND_CHART_DATA_CATEGORY = "loadWindChartData";
private final Set<String> windSourceTypeNames;
private final int WIND_CHART_RESOLUTION_IN_MILLISECONDS = 5000;
private final int ONE_HOUR_IN_MILLISECONDS = 1000*60*60;
private final String LODA_WIND_CHART_DATA_CATEGORY = "loadWindChartData";
private boolean didInitialLoading;
public WindBotDataRetriever(SailingServiceAsync sailingService) {
this.sailingService = sailingService;
@@ -36,15 +42,17 @@ public class WindBotDataRetriever implements TimeListener, RaceSelectionChangeLi
numberOfWindBotsChangeListeners = new ArrayList<NumberOfWindBotsChangeListener>();
windBotDataRetrieverListeners = new ArrayList<WindBotDataRetrieverListener>();
windBotIDsInLiveRace = new ArrayList<String>();
windSourceTypeNames = new HashSet<>();
windSourceTypeNames.add(WindSourceType.EXPEDITION.name());
}
private void loadWindBotData(Date from, Date to, RegattaAndRaceIdentifier selectedRaceIdentifier) {
if(!didInitialLoading){
didInitialLoading = true;
from = new Date(from.getTime()-1000*60*15);
from = new Date(from.getTime()-ONE_HOUR_IN_MILLISECONDS);
}
GetWindInfoAction getWindInfoAction = new GetWindInfoAction(sailingService, selectedRaceIdentifier, from, to,
WIND_CHART_RESOLUTION_IN_MILLISECONDS, null, /*
WIND_CHART_RESOLUTION_IN_MILLISECONDS, windSourceTypeNames, /*
* onlyUpToNewestEvent==true because we don't want to
* overshoot the evidence so far
*/true);
@@ -1,4 +1,4 @@
package com.sap.sailing.dashboards.gwt.client;
package com.sap.sailing.dashboards.gwt.client.dataretriever;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
@@ -1,4 +1,4 @@
package com.sap.sailing.dashboards.gwt.client;
package com.sap.sailing.dashboards.gwt.client.dataretriever;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
@@ -3,6 +3,8 @@ package com.sap.sailing.dashboards.gwt.client.device;
import java.util.ArrayList;
import java.util.List;
import com.sap.sse.common.Util.Pair;
/**
*
* @author Alexander Ries (D062114)
@@ -62,8 +64,38 @@ public class Orientation {
}
public void notifiyListenerAboutHeadingChange(double orientationHeading) {
Pair<OrientationType, Double> orienationPair = new Pair<OrientationType, Double>(getOrientationTypeForHeadingInSafari(orientationHeading), new Double(orientationHeading));
for (OrientationListener orientationListener : orientationListeners) {
orientationListener.orientationChanged(orientationHeading);
orientationListener.orientationChanged(orienationPair);
}
}
private OrientationType getOrientationTypeForHeadingInSafari(double heading){
OrientationType orientationType = null;
if (heading > -45 && heading <= 0 || heading > 0 && heading < 45){
orientationType = OrientationType.PORTRAIT_UP;
}else if (heading > 45 && heading < 135){
orientationType = OrientationType.LANDSCAPE_RIGHT;
}else if (heading > 135 && heading <= 180 || heading >=-180 && heading < -135){
orientationType = OrientationType.PORTRAIT_DOWN;
}else if (heading > -135 && heading < -45){
orientationType = OrientationType.LANDSCAPE_LEFT;
}
return orientationType;
}
private OrientationType getOrientationTypeForHeadingInChrome(double heading){
OrientationType orientationType = null;
if (heading > -45 && heading <= 0 || heading > 0 && heading < 45){
orientationType = OrientationType.LANDSCAPE_RIGHT;
}else if (heading > 45 && heading < 135){
orientationType = OrientationType.PORTRAIT_DOWN;
}else if (heading > 135 && heading <= 180 || heading >=-180 && heading < -135){
orientationType = OrientationType.LANDSCAPE_LEFT;
}else if (heading > -135 && heading < -45){
orientationType = OrientationType.PORTRAIT_UP;
}
return orientationType;
}
}
@@ -1,6 +1,11 @@
package com.sap.sailing.dashboards.gwt.client.device;
import com.sap.sse.common.Util.Pair;
public interface OrientationListener {
public void orientationChanged(double orientationHeading);
/**
* Returns a Pair containing the {@link OrientationType} and the exact angle.
* */
public void orientationChanged(Pair <OrientationType, Double> orientation);
}
@@ -0,0 +1,6 @@
package com.sap.sailing.dashboards.gwt.client.device;
public enum OrientationType {
PORTRAIT_UP, PORTRAIT_DOWN, LANDSCAPE_RIGHT, LANDSCAPE_LEFT;
}
@@ -1,4 +1,4 @@
package com.sap.sailing.dashboards.gwt.client;
package com.sap.sailing.dashboards.gwt.client.eventlogo;
import java.util.UUID;
@@ -0,0 +1,9 @@
package com.sap.sailing.dashboards.gwt.client.i18n;
import com.google.gwt.core.client.GWT;
public interface StringMessages extends com.sap.sailing.gwt.ui.client.StringMessages {
public static final StringMessages INSTANCE = GWT.create(StringMessages.class);
String sampleText();
}
@@ -1,4 +1,4 @@
package com.sap.sailing.dashboards.gwt.client.bottomnotification;
package com.sap.sailing.dashboards.gwt.client.notifications;
import java.util.ArrayList;
import java.util.List;
@@ -1,4 +1,4 @@
package com.sap.sailing.dashboards.gwt.client.bottomnotification;
package com.sap.sailing.dashboards.gwt.client.notifications;
public interface BottomNotificationClickListener {
@@ -1,4 +1,4 @@
package com.sap.sailing.dashboards.gwt.client.bottomnotification;
package com.sap.sailing.dashboards.gwt.client.notifications;
import com.sap.sailing.gwt.ui.client.StringMessages;
@@ -0,0 +1,67 @@
package com.sap.sailing.dashboards.gwt.client.notifications;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.sap.sailing.dashboards.gwt.client.RibDashboardImageResources;
import com.sap.sailing.dashboards.gwt.client.device.Orientation;
import com.sap.sailing.dashboards.gwt.client.device.OrientationListener;
import com.sap.sailing.dashboards.gwt.client.device.OrientationType;
import com.sap.sailing.dashboards.gwt.client.visualeffects.BlurEffect;
import com.sap.sse.common.Util.Pair;
public class WrongDeviceOrientationNotification extends AbsolutePanel implements OrientationListener {
private Label rotateDeviceLabel;
public WrongDeviceOrientationNotification() {
super();
this.addStyleName("wrongOrientationNotification");
this.addStyleName("wrongOrientationNotification_hidden");
Image rotateDeviceIcon = new Image();
rotateDeviceIcon.setResource(RibDashboardImageResources.INSTANCE.rotatedevice());
rotateDeviceIcon.getElement().addClassName("wrongOrientationNotification_logo");
add(rotateDeviceIcon);
rotateDeviceLabel = new Label();
rotateDeviceLabel.getElement().addClassName("wrongOrientationNotification_text");
rotateDeviceLabel.setText("Rotate Device");
add(rotateDeviceLabel);
Orientation.getInstance().addListener(this);
Orientation.getInstance().triggerDeviceOrientationRead();
}
public void show() {
this.removeStyleName("wrongOrientationNotification_hidden");
this.addStyleName("wrongOrientationNotification_shown");
BlurEffect.getInstance().addToView(RootLayoutPanel.get());
}
public void hide() {
this.removeStyleName("wrongOrientationNotification_shown");
this.addStyleName("wrongOrientationNotification_hidden");
BlurEffect.getInstance().removeFromView(RootLayoutPanel.get());
}
@Override
public void orientationChanged(Pair<OrientationType, Double> orientation) {
OrientationType orientationType = orientation.getA();
switch (orientationType) {
case PORTRAIT_UP:
show();
break;
case PORTRAIT_DOWN:
show();
break;
case LANDSCAPE_RIGHT:
hide();
break;
case LANDSCAPE_LEFT:
hide();
break;
}
}
}
@@ -75,13 +75,3 @@
transition: margin-top ease-in-out 500ms;
margin-top: -600pt;
}
.blurred {
-webkit-filter: blur(10pt) brightness(0.92);
filter: blur(10pt) brightness(0.92);
}
.not_blurred {
-webkit-filter: blur(0pt) brightness(1);
filter: blur(0pt) brightness(1);
}
@@ -17,6 +17,7 @@ import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.dashboards.gwt.client.visualeffects.BlurEffect;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
public class CompetitorSelectionPopup extends Composite implements HasWidgets, CompetitorTableRowSelectionListener {
@@ -27,10 +28,6 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C
String popuphide();
String buttonshow();
String blurred();
String not_blurred();
}
@UiField
@@ -68,16 +65,14 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C
this.button.setText("OK");
this.getElement().addClassName(style.popupshow());
this.getElement().removeClassName(style.popuphide());
RootLayoutPanel.get().addStyleName(style.blurred());
RootLayoutPanel.get().removeStyleName(style.not_blurred());
BlurEffect.getInstance().addToView(RootLayoutPanel.get());
isVisible = true;
}
public void hide() {
this.getElement().addClassName(style.popuphide());
this.getElement().removeClassName(style.popupshow());
RootLayoutPanel.get().addStyleName(style.not_blurred());
RootLayoutPanel.get().removeStyleName(style.blurred());
BlurEffect.getInstance().removeFromView(RootLayoutPanel.get());
RootPanel.get().remove(this);
isVisible = false;
}
@@ -10,11 +10,8 @@
}
.settings_button_image {
position: absolute;
height: 23.5pt;
width: 23.5pt;
right: 10pt;
top: 17.5pt;
}
.settings_indication_label {
@@ -5,8 +5,9 @@
type='com.sap.sailing.dashboards.gwt.client.popups.competitorselection.SettingsButtonWithSelectionIndicationLabel.SettingsButtonWithSelectionIndicationLabelStyle'
src='SettingsButtonWithSelectionIndicationLabel.css'></ui:style>
<g:HTMLPanel>
<g:FocusPanel ui:field="settingsButton" styleName="{style.settings_button}"></g:FocusPanel>
<g:Image ui:field="settingsButtonImage" styleName="{style.settings_button_image}"></g:Image>
<g:FocusPanel ui:field="settingsButton" styleName="{style.settings_button}">
<g:Image ui:field="settingsButtonImage" styleName="{style.settings_button_image}"></g:Image>
</g:FocusPanel>
<g:Label ui:field="settingsIndicationLabel" styleName="{style.settings_indication_label}"></g:Label>
</g:HTMLPanel>
</ui:UiBinder>
@@ -136,10 +136,10 @@ public class StartlineAnalysisCard extends Composite implements HasWidgets, Star
com.sap.sse.gwt.client.player.Timer timer = new com.sap.sse.gwt.client.player.Timer(PlayModes.Live, 1000l);
timer.pause();
ArrayList<ZoomTypes> zoomTypes = new ArrayList<ZoomTypes>();
if(startAnalysisDTO.racingProcedureType.equals(RacingProcedureType.GateStart)){
timer.setTime(startAnalysisDTO.timeOfStartInMilliSeconds+startAnalysisDTO.tailLenghtInMilliseconds);
if (startAnalysisDTO.racingProcedureType.equals(RacingProcedureType.GateStart)) {
timer.setTime(startAnalysisDTO.timeOfStartInMilliSeconds + startAnalysisDTO.tailLenghtInMilliseconds);
zoomTypes.add(ZoomTypes.BUOYS);
}else{
} else {
timer.setTime(startAnalysisDTO.timeOfStartInMilliSeconds);
zoomTypes.add(ZoomTypes.TAILS);
}
@@ -24,9 +24,9 @@ import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.dashboards.gwt.client.RibDashboardImageResources;
import com.sap.sailing.dashboards.gwt.client.RibDashboardServiceAsync;
import com.sap.sailing.dashboards.gwt.client.bottomnotification.BottomNotification;
import com.sap.sailing.dashboards.gwt.client.bottomnotification.BottomNotificationClickListener;
import com.sap.sailing.dashboards.gwt.client.bottomnotification.BottomNotificationType;
import com.sap.sailing.dashboards.gwt.client.notifications.BottomNotification;
import com.sap.sailing.dashboards.gwt.client.notifications.BottomNotificationClickListener;
import com.sap.sailing.dashboards.gwt.client.notifications.BottomNotificationType;
import com.sap.sailing.dashboards.gwt.client.popups.competitorselection.CompetitorSelectionListener;
import com.sap.sailing.dashboards.gwt.client.popups.competitorselection.CompetitorSelectionPopup;
import com.sap.sailing.dashboards.gwt.client.popups.competitorselection.SettingsButtonWithSelectionIndicationLabel;
@@ -1,8 +1,8 @@
package com.sap.sailing.dashboards.gwt.client.startlineadvantage;
import com.google.gwt.i18n.client.NumberFormat;
import com.sap.sailing.dashboards.gwt.client.RibDashboardDataRetriever;
import com.sap.sailing.dashboards.gwt.client.RibDashboardDataRetrieverListener;
import com.sap.sailing.dashboards.gwt.client.dataretriever.RibDashboardDataRetriever;
import com.sap.sailing.dashboards.gwt.client.dataretriever.RibDashboardDataRetrieverListener;
import com.sap.sailing.dashboards.gwt.client.startanalysis.StartlineAdvantageType;
import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO;
import com.sap.sailing.gwt.ui.client.StringMessages;
@@ -0,0 +1,11 @@
@CHARSET "UTF-8";
.blurred {
-webkit-filter: blur(10pt) brightness(0.92);
filter: blur(10pt) brightness(0.92);
}
.not_blurred {
-webkit-filter: blur(0pt) brightness(1);
filter: blur(0pt) brightness(1);
}
@@ -0,0 +1,34 @@
package com.sap.sailing.dashboards.gwt.client.visualeffects;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.user.client.ui.Widget;
public class BlurEffect {
private static BlurEffect INSTANCE = null;
private VisualEffectsResources visualEffectsResources = GWT.create(VisualEffectsResources.class);
private BlurEffect() {
visualEffectsResources.blurEffectStyle().ensureInjected();
}
public static BlurEffect getInstance() {
synchronized (BlurEffect.class) {
if (INSTANCE == null) {
INSTANCE = new BlurEffect();
}
}
return INSTANCE;
}
public void addToView(Widget widget){
widget.removeStyleName(visualEffectsResources.blurEffectStyle().not_blurred());
widget.addStyleName(visualEffectsResources.blurEffectStyle().blurred());
}
public void removeFromView(Widget widget){
widget.removeStyleName(visualEffectsResources.blurEffectStyle().blurred());
widget.addStyleName(visualEffectsResources.blurEffectStyle().not_blurred());
}
}
@@ -0,0 +1,13 @@
package com.sap.sailing.dashboards.gwt.client.visualeffects;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.CssResource.Shared;
@Shared
public interface BlurEffectStyle extends CssResource{
public String blurred();
public String not_blurred();
}
@@ -0,0 +1,9 @@
package com.sap.sailing.dashboards.gwt.client.visualeffects;
import com.google.gwt.resources.client.ClientBundle;
public interface VisualEffectsResources extends ClientBundle{
@Source("BlurEffect.css")
BlurEffectStyle blurEffectStyle();
}
@@ -26,6 +26,8 @@ import org.moxieapps.gwt.highcharts.client.plotOptions.BarPlotOptions;
import org.moxieapps.gwt.highcharts.client.plotOptions.Marker;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder;
@@ -90,8 +92,8 @@ public class VerticalWindChart extends Composite implements HasWidgets {
initWidget(uiBinder.createAndBindUi(this));
}
public @UiConstructor VerticalWindChart(String positiveFillColor, String negativeFillColor) {
initVerticalWindChartWithColors(positiveFillColor, negativeFillColor);
public @UiConstructor VerticalWindChart(String positiveFillColorAsHex, String negativeFillColorAsHex) {
initVerticalWindChartWithColors(positiveFillColorAsHex, negativeFillColorAsHex);
initWidget(uiBinder.createAndBindUi(this));
}
@@ -175,18 +177,24 @@ public class VerticalWindChart extends Composite implements HasWidgets {
* {@link #setXAxisExtremesForSeriesPointRangeIsSmallerThanChartDisplayIntervall()} and
* {@link #setXAxisExtremesForSeriesPointRangeIsBiggerThanChartDisplayIntervall()}.
* */
public void addPointsToSeriesWithAverage(Point[] points, double average) {
if (verticalWindChartSeries == null) {
initVerticalWindChartSeries();
verticalWindChartSeries.setPoints(points, true);
} else {
for (Point point : points) {
verticalWindChartSeries.addPoint(point, true, false, false);
public void addPointsToSeriesWithAverage(final Point[] points, final double average) {
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
if (verticalWindChartSeries == null) {
initVerticalWindChartSeries();
verticalWindChartSeries.setPoints(points, true);
} else {
for (Point point : points) {
verticalWindChartSeries.addPoint(point, true, false, false);
}
}
verticalWindChartSeries.updateThreshold("" + average);
adaptVerticalWindChartExtemes();
verticalWindChart.setSizeToMatchContainer();
}
}
verticalWindChartSeries.updateThreshold("" + average);
adaptVerticalWindChartExtemes();
verticalWindChart.setSizeToMatchContainer();
});
}
/**
@@ -194,23 +202,7 @@ public class VerticalWindChart extends Composite implements HasWidgets {
* interval or not. So there are two cases where the extreme points of the x-axis get calculated differently.
* */
private void adaptVerticalWindChartExtemes() {
if (getVerticalWindChartSeriesPointsTimeRangeInMilliseconds() < chartIntervallinMinutes * 60 * 1000) {
setXAxisExtremesForSeriesPointRangeIsSmallerThanChartDisplayIntervall();
} else {
setXAxisExtremesForSeriesPointRangeIsBiggerThanChartDisplayIntervall();
}
}
/**
* When the time range of the series points is smaller than the current selected display interval represented by
* either LARGE_DISPLAY_INTERVALL_IN_MINUTES or SMALL_DISPLAY_INTERVALL_IN_MINUTES the x-axis extremes min value is
* the the first points time and the maximum value the min value plus the selected display interval. The chart gets
* other extremes, because the values fit easily into the selected display interval.
* */
private void setXAxisExtremesForSeriesPointRangeIsSmallerThanChartDisplayIntervall() {
long minimumExtremeValueInMillis = getFirstPointOfVerticalWindChartSeries().getX().longValue();
long maximumExtremeValueInMillis = minimumExtremeValueInMillis + chartIntervallinMinutes * 60 * 1000;
verticalWindChart.getXAxis().setExtremes(minimumExtremeValueInMillis, maximumExtremeValueInMillis, true, true);
}
/**
@@ -220,29 +212,11 @@ public class VerticalWindChart extends Composite implements HasWidgets {
* gets other extremes, because the values do not fit anymore into the selected display interval.
* */
private void setXAxisExtremesForSeriesPointRangeIsBiggerThanChartDisplayIntervall() {
long maximumExtremeValueInMillis = getLastPointOfVerticalWindChartSeries().getX().longValue();
long minimumExtremeValueInMillis = maximumExtremeValueInMillis - chartIntervallinMinutes * 60 * 1000;
verticalWindChart.getXAxis().setExtremes(minimumExtremeValueInMillis, maximumExtremeValueInMillis, true, true);
long maximumExtremeValueInMillis = getLastPointOfVerticalWindChartSeries().getX().longValue();
long minimumExtremeValueInMillis = maximumExtremeValueInMillis - chartIntervallinMinutes * 60 * 1000;
verticalWindChart.getXAxis().setExtremes(minimumExtremeValueInMillis, maximumExtremeValueInMillis, true, true);
}
private long getVerticalWindChartSeriesPointsTimeRangeInMilliseconds() {
Point[] seriesPoints = verticalWindChartSeries.getPoints();
long pointRangeInMilliseconds;
int seriesPointsLenght = seriesPoints.length;
if (seriesPointsLenght > 0 && seriesPoints[0].getX() != null) {
long earliesPointAsTimestamp = seriesPoints[0].getX().longValue();
long latestPointAsTimestamp;
if (seriesPointsLenght > 1) {
latestPointAsTimestamp = seriesPoints[seriesPointsLenght - 1].getX().longValue();
} else {
latestPointAsTimestamp = earliesPointAsTimestamp;
}
pointRangeInMilliseconds = latestPointAsTimestamp - earliesPointAsTimestamp;
} else {
pointRangeInMilliseconds = 0;
}
return pointRangeInMilliseconds;
}
private Point getLastPointOfVerticalWindChartSeries() {
Point lastPointOfVerticalWindChartSeries = null;
@@ -256,16 +230,6 @@ public class VerticalWindChart extends Composite implements HasWidgets {
return lastPointOfVerticalWindChartSeries;
}
private Point getFirstPointOfVerticalWindChartSeries() {
Point firstPointOfVerticalWindChartSeries = null;
Point[] seriesPoints = verticalWindChartSeries.getPoints();
int seriesPointsLenght = seriesPoints.length;
if (seriesPointsLenght > 0) {
firstPointOfVerticalWindChartSeries = seriesPoints[0];
}
return firstPointOfVerticalWindChartSeries;
}
public void addVerticalWindChartClickListener(VerticalWindChartClickListener verticalWindChartClickListener) {
verticalWindChartClickListeners.add(verticalWindChartClickListener);
}
@@ -291,8 +255,13 @@ public class VerticalWindChart extends Composite implements HasWidgets {
} else {
chartIntervallinMinutes = SMALL_DISPLAY_INTERVALL_IN_MINUTES;
}
adaptVerticalWindChartExtemes();
notifyVerticalWindChartClickListeners(chartIntervallinMinutes);
Scheduler.get().scheduleFinally(new ScheduledCommand() {
@Override
public void execute() {
adaptVerticalWindChartExtemes();
notifyVerticalWindChartClickListeners(chartIntervallinMinutes);
}});
}
@Override
@@ -15,8 +15,8 @@ import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.dashboards.gwt.client.RibDashboardDataRetrieverListener;
import com.sap.sailing.dashboards.gwt.client.WindBotDataRetrieverListener;
import com.sap.sailing.dashboards.gwt.client.dataretriever.RibDashboardDataRetrieverListener;
import com.sap.sailing.dashboards.gwt.client.dataretriever.WindBotDataRetrieverListener;
import com.sap.sailing.dashboards.gwt.client.startlineadvantage.LiveAverageComponent;
import com.sap.sailing.dashboards.gwt.client.windchart.compass.LocationPointerCompass;
import com.sap.sailing.dashboards.gwt.shared.MovingAverage;
@@ -85,14 +85,14 @@ public class WindBotComponent extends Composite implements HasWidgets, WindBotDa
* One of two {@link VerticalWindChart}s that shows the wind fixes speed measured by the wind bot in a chart
* vertically.
* */
@UiField
@UiField(provided = true)
public VerticalWindChart trueWindSpeedVerticalWindChart;
/**
* One of two {@link VerticalWindChart}s that shows the wind fixes direction measured by the wind bot in a chart
* vertically.
* */
@UiField
@UiField(provided = true)
public VerticalWindChart trueWindDirectionVerticalWindChart;
/**
@@ -104,6 +104,7 @@ public class WindBotComponent extends Composite implements HasWidgets, WindBotDa
private String windBotId;
private StringMessages stringConstants;
private final static String UNIT_WIND_DIRECTION = "°";
public WindBotComponent(String windBotId) {
this.windBotId = windBotId;
@@ -119,7 +120,9 @@ public class WindBotComponent extends Composite implements HasWidgets, WindBotDa
movingAverageSpeed = new MovingAverage(500);
movingAverageDirection = new MovingAverage(500);
trueWindSpeedLiveAverageComponent = new LiveAverageComponent(stringConstants.dashboardTrueWindSpeed(), stringConstants.dashboardTrueWindSpeedUnit());
trueWindDirectionLiveAverageComponent = new LiveAverageComponent(stringConstants.dashboardTrueWindDirection(), stringConstants.dashboardTrueWindDirectionUnit());
trueWindDirectionLiveAverageComponent = new LiveAverageComponent(stringConstants.dashboardTrueWindDirection(), UNIT_WIND_DIRECTION);
trueWindSpeedVerticalWindChart = new VerticalWindChart("#008FFF", "#6ADBFF");
trueWindDirectionVerticalWindChart = new VerticalWindChart("#008FFF", "#6ADBFF");
initWidget(uiBinder.createAndBindUi(this));
windBotNamePanel.getElement().setInnerText(stringConstants.dashboardWindBot()+" "+ windBotId);
trueWindSpeedVerticalWindChart.addVerticalWindChartClickListener(trueWindSpeedLiveAverageComponent);
@@ -197,16 +200,16 @@ public class WindBotComponent extends Composite implements HasWidgets, WindBotDa
Point[] points = new Point[windFixes.size()];
int counter = 0;
if (windtype.equals(WindType.DIRECTION)) {
Point previouspoint = new Point(windFixes.get(0).requestTimepoint, windFixes.get(0).trueWindBearingDeg);
Point previouspoint = new Point(windFixes.get(0).requestTimepoint, windFixes.get(0).trueWindFromDeg);
for (WindDTO windDTO : windFixes) {
double nextSinusValue = 0;
if (inSimulationMode == true) {
nextSinusValue = directionSinWave.getNexNumber();
}
points[counter] = new Point(windDTO.requestTimepoint, windDTO.trueWindBearingDeg + nextSinusValue);
points[counter] = new Point(windDTO.requestTimepoint, windDTO.trueWindFromDeg + nextSinusValue);
points[counter] = adaptWindDirectionPointToStayCloseToLastPoint(previouspoint, points[counter]);
previouspoint = points[counter];
movingAverageDirection.add(windDTO.trueWindBearingDeg + nextSinusValue);
movingAverageDirection.add(windDTO.trueWindFromDeg + nextSinusValue);
counter++;
}
} else if (windtype.equals(WindType.SPEED)) {
@@ -23,14 +23,12 @@
<g:HTMLPanel
styleName="{style.wind_bot_component_windchart_container} {style.wind_bot_component_left}">
<windchart:VerticalWindChart ui:field="trueWindSpeedVerticalWindChart"
styleName="{style.wind_bot_component_windchart}" positiveFillColor="#008FFF"
negativeFillColor="#6ADBFF"></windchart:VerticalWindChart>
styleName="{style.wind_bot_component_windchart}"></windchart:VerticalWindChart>
</g:HTMLPanel>
<g:HTMLPanel
styleName="{style.wind_bot_component_windchart_container} {style.wind_bot_component_right}">
<windchart:VerticalWindChart ui:field="trueWindDirectionVerticalWindChart"
styleName="{style.wind_bot_component_windchart}" positiveFillColor="#008FFF"
negativeFillColor="#6ADBFF"></windchart:VerticalWindChart>
styleName="{style.wind_bot_component_windchart}"></windchart:VerticalWindChart>
</g:HTMLPanel>
<g:HTMLPanel styleName="{style.wind_bot_component_compass_container}">
<compass:LocationPointerCompass
@@ -9,8 +9,10 @@ import com.sap.sailing.dashboards.gwt.client.device.Location;
import com.sap.sailing.dashboards.gwt.client.device.LocationListener;
import com.sap.sailing.dashboards.gwt.client.device.Orientation;
import com.sap.sailing.dashboards.gwt.client.device.OrientationListener;
import com.sap.sailing.dashboards.gwt.client.device.OrientationType;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sse.common.Util.Pair;
/**
* The classes task is to notify its listeners about changes in distance and angle from the actual device to a pointed
@@ -137,7 +139,7 @@ public class LocationPointerCompassAngleDistance implements LocationListener, Co
}
@Override
public void orientationChanged(double orintationHeading) {
setAngleOffsetAtListeners(orintationHeading);
public void orientationChanged(Pair<OrientationType, Double> orientation) {
setAngleOffsetAtListeners(orientation.getB().doubleValue());
}
}
@@ -6,24 +6,49 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.common.TimePoint;
public abstract class AbstractStartAnalysisCreationValidator {
private static int MINIMUM_NUMBER_COMPETITORS_FOR_STARTANALYSIS = 3;
private static int MINIMUM_MARKPASSIINGS_AT_FIRST_MARK = 3;
private static long MINIMUM_RACE_PROGRESSION_IN_MILLISECONDS = 6*60*1000;
protected boolean threeCompetitorsPassedSecondWayPoint(TrackedRace trackedRace){
Waypoint secondWaypoint = trackedRace.getRace().getCourse().getFirstLeg().getTo();
Iterator<MarkPassing> markPassingsInOrder = trackedRace.getMarkPassingsInOrder(secondWaypoint).iterator();
int counter = 0;
while (markPassingsInOrder.hasNext()) {
int markPassingsCounter = 0;
while (markPassingsInOrder.hasNext() && markPassingsCounter < MINIMUM_MARKPASSIINGS_AT_FIRST_MARK) {
markPassingsInOrder.next();
counter ++;
markPassingsCounter ++;
}
return counter >= MINIMUM_NUMBER_COMPETITORS_FOR_STARTANALYSIS ? true : false;
return markPassingsCounter >= MINIMUM_MARKPASSIINGS_AT_FIRST_MARK ? true : false;
}
protected boolean competitorPassedSecondWayPoint(Competitor competitor, TrackedRace trackedRace){
private boolean competitorPassedSecondWayPoint(Competitor competitor, TrackedRace trackedRace){
Waypoint secondWaypoint = trackedRace.getRace().getCourse().getFirstLeg().getTo();
return trackedRace.getMarkPassing(competitor, secondWaypoint) == null ? false : true;
}
private boolean gateStartGolfFlagIsDown(TrackedRace trackedRace){
if(trackedRace.getGateStartGolfDownTime() != 0){
return true;
}else{
TimePoint timeStartOfRace = trackedRace.getStartOfRace();
TimePoint timeNewestEvent = trackedRace.getTimePointOfNewestEvent();
if(timeStartOfRace != null && timeNewestEvent != null){
if(timeStartOfRace.asMillis()+MINIMUM_RACE_PROGRESSION_IN_MILLISECONDS > timeNewestEvent.asMillis()){
return true;
}
}
}
return false;
}
protected boolean raceProgressedFarEnough(Competitor competitor, TrackedRace trackedRace){
if(trackedRace.isGateStart()){
return gateStartGolfFlagIsDown(trackedRace);
}else{
return competitorPassedSecondWayPoint(competitor, trackedRace);
}
}
}
@@ -21,7 +21,7 @@ public class StartAnalysisCreationController extends AbstractStartAnalysisCreati
public StartAnalysisDTO checkStartAnalysisForCompetitorInTrackedRace(Competitor competitor, TrackedRace trackedRace) {
StartAnalysisDTO startAnalysisDTO;
if (threeCompetitorsPassedSecondWayPoint(trackedRace) &&
competitorPassedSecondWayPoint(competitor, trackedRace))
raceProgressedFarEnough(competitor, trackedRace))
{
logger.log(Level.INFO, "Trigger StartAnalysisDTO creation");
startAnalysisDTO = startAnalysisDTOFactory.createStartAnalysisForCompetitorAndTrackedRace(competitor, trackedRace);
@@ -34,6 +34,7 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida
private static int MINIMUM_NUMBER_COMPETITORS_FOR_STARTANALYSIS = 3;
private static int DEFAULT_GATE_START_INTERVALL_IN_MILLISECONDS = 5*60*1000;
private static int ONE_MINUTE_INTERVALL_IN_MILLISECONDS = 60*1000;
private static final Logger logger = Logger.getLogger(StartAnalysisDTOFactory.class.getName());
@@ -72,7 +73,6 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida
if (trackedRace.isGateStart()) {
logger.log(Level.INFO, "IS GATESTART");
startAnalysisDTO.racingProcedureType = RacingProcedureType.GateStart;
// Waypoint startLineWaypoint = trackedRace.getStartLine(trackedRace.getStartOfRace()).getWaypoint();
long timePointOfGolfDownTime = trackedRace.getGateStartGolfDownTime();
startAnalysisDTO.timeOfStartInMilliSeconds = trackedRace.getStartOfRace().asMillis();
if(timePointOfGolfDownTime < trackedRace.getStartOfRace().asMillis() || timePointOfGolfDownTime == 0){
@@ -83,6 +83,7 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida
} else {
startAnalysisDTO.racingProcedureType = RacingProcedureType.ESS;
startAnalysisDTO.timeOfStartInMilliSeconds = trackedRace.getStartOfRace().asMillis();
startAnalysisDTO.tailLenghtInMilliseconds = ONE_MINUTE_INTERVALL_IN_MILLISECONDS;
}
startAnalysisDTO.regattaAndRaceIdentifier = trackedRace.getRaceIdentifier();
logger.log(Level.INFO, "Created StartAnalysis For Competitor " + competitor.getName() + " and "+ trackedRace.getRace().getName());
@@ -16,8 +16,7 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sse.datamining.shared,
com.sap.sse,
com.sap.sse.common,
org.eclipse.osgi,
com.sap.sailing.polars
org.eclipse.osgi
Bundle-ClassPath: .
Bundle-Activator: com.sap.sailing.datamining.Activator
Bundle-ActivationPolicy: lazy
@@ -1,7 +1,7 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.domain.polars.PolarDataService;
public interface HasLeaderboardContext {
@@ -1,7 +1,7 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.domain.polars.PolarDataService;
public interface HasLeaderboardGroupContext {
@@ -2,9 +2,9 @@ package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sse.datamining.shared.Unit;
import com.sap.sse.datamining.shared.annotations.Connector;
import com.sap.sse.datamining.shared.annotations.Statistic;
import com.sap.sse.datamining.shared.data.Unit;
public interface HasTrackedLegOfCompetitorContext {
@@ -5,7 +5,7 @@ import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
@@ -2,7 +2,7 @@ package com.sap.sailing.datamining.impl.data;
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.domain.polars.PolarDataService;
public class LeaderboardGroupWithContext implements HasLeaderboardGroupContext {
@@ -2,7 +2,7 @@ package com.sap.sailing.datamining.impl.data;
import com.sap.sailing.datamining.data.HasLeaderboardContext;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.domain.polars.PolarDataService;
public class LeaderboardWithContext implements HasLeaderboardContext {
@@ -20,11 +20,11 @@ import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableSpeed;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -0,0 +1,14 @@
apply plugin: "java"
sourceSets {
main {
java.srcDirs = ["src"]
}
}
dependencies {
/* local dependencies */
compile project(":java:com.sap.sse.common")
compile project(":java:com.sap.sse.security.common")
compile project(":java:com.sap.sse.datamining.shared")
}
@@ -190,4 +190,48 @@ public class AbstractPosition implements Position {
return "(" + getLatDeg() + "," + getLngDeg() + ")";
}
@Override
public Position getIntersection(Bearing thisBearing, Position to, Bearing toBearing) {
/*
* See http://www.movable-type.co.uk/scripts/latlong-vectors.html#intersection for explanation
*/
double radBearing1 = thisBearing.getRadians();
double radLatPos1 = getLatRad();
double radLngPos1 = getLngRad();
double[] greatCircle1 = createGreatCircleVector(radBearing1, radLatPos1, radLngPos1);
double radBearing2 = toBearing.getRadians();
double radLatPos2 = to.getLatRad();
double radLngPos2 = to.getLngRad();
double[] greatCircle2 = createGreatCircleVector(radBearing2, radLatPos2, radLngPos2);
double[] intersection1 = computeCrossProductOf3PartVectors(greatCircle1, greatCircle2);
double[] intersection2 = computeCrossProductOf3PartVectors(greatCircle2, greatCircle1);
Position intersectionPosition1 = cartesianVectorToPosition(intersection1);
Position intersectionPosition2 = cartesianVectorToPosition(intersection2);
Distance sumOfDistances1 = getDistance(intersectionPosition1).add(intersectionPosition1.getDistance(to));
Distance sumOfDistances2 = getDistance(intersectionPosition2).add(intersectionPosition2.getDistance(to));
return sumOfDistances1.compareTo(sumOfDistances2) < 0 ? intersectionPosition1 : intersectionPosition2;
}
private Position cartesianVectorToPosition(double[] vector) {
double lat = Math.atan2(vector[2], Math.sqrt(vector[0]*vector[0] + vector[1]*vector[1]));
double lng = Math.atan2(vector[1], vector[0]);
return new RadianPosition(lat, lng);
}
private double[] computeCrossProductOf3PartVectors(double[] vec1, double[] vec2) {
double[] crossProduct= new double[3];
crossProduct[0] = vec1[1]*vec2[2] - vec1[2]*vec2[1];
crossProduct[1] = vec1[2]*vec2[0] - vec1[0]*vec2[2];
crossProduct[2] = vec1[0]*vec2[1] - vec1[1]*vec2[0];
return crossProduct;
}
private double[] createGreatCircleVector(double radBearing, double radLatPos, double radLngPos) {
double[] greatCircle = new double[3];
greatCircle[0] = Math.sin(radLngPos) * Math.cos(radBearing) - Math.sin(radLatPos) * Math.cos(radLngPos) * Math.sin(radBearing);
greatCircle[1] = -Math.cos(radLngPos) * Math.cos(radBearing) - Math.sin(radLatPos) * Math.sin(radLngPos) * Math.sin(radBearing);
greatCircle[2] = Math.cos(radLatPos) * Math.sin(radBearing);
return greatCircle;
}
}
@@ -43,6 +43,7 @@ public enum BoatClassMasterdata {
NACRA_17 ("Nacra 17", true, 5.25, 2.59, BoatHullType.CATAMARAN, true, "N17", "Nacra-17"),
OK ("OK Dinghy", true, 5.25, 2.59, BoatHullType.MONOHULL, false, "OK-Dinghy", "OK-Jolle", "OK"),
OPTIMIST ("Optimist", true, 2.34, 1.07, BoatHullType.MONOHULL, false, "Opti", "Optimist Dinghy"),
PIRAT ("Pirat", true, 5.00, 1.61, BoatHullType.MONOHULL, false, "Pirate", "Piraten"),
PLATU_25 ("Platu 25", true, 7.53, 2.62, BoatHullType.MONOHULL, true, "Platu", "Platu-25", "PLA", "B25"),
RS_X ("RS:X", true, 2.86, 0.93, BoatHullType.SURFERBOARD, false, "RS-X", "RSX", "RS:X"),
SONAR ("Sonar", true, 7.01, 2.39, BoatHullType.MONOHULL, true),
@@ -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;
}
}
@@ -104,5 +104,16 @@ public interface Position extends Serializable {
* The method executes efficiently and requires only one call to the cosine method.
*/
double getQuickApproximateNauticalMileDistance(Position p);
/**
* Computes the intersection of two paths. The first path is defined by the underlying position and the parameter
* <code>thisBearing</code>. The second path is defined by parameters <code>to</code> and <code>toBearing</code>
*
* @param thisBearing defines first path with <code>this</code> position
* @param to defines second path with <code>toBearing</code>
* @param toBearing defines second path <code>to</code> position
* @return position of intersection. Since there are usually 2 intersections, we return the smaller intersection.
*/
Position getIntersection(Bearing thisBearing, Position to, Bearing toBearing);
}
@@ -4,8 +4,8 @@ import java.io.Serializable;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.datamining.shared.Unit;
import com.sap.sse.datamining.shared.annotations.Statistic;
import com.sap.sse.datamining.shared.data.Unit;
/**
* A speed, convertible in various units of measure. Can be negative.
@@ -13,7 +13,8 @@ public enum RacingProcedureType {
RRS26("Fix Line Start (RRS26)"),
GateStart("Gate Start"),
ESS("\"Extreme Sailing Series\"-Start"),
BASIC("Basic Countdown Start");
BASIC("Basic Countdown Start"),
LEAGUE("League Start");
private String displayName;
@@ -40,6 +40,7 @@ import com.sap.sse.common.TimeRange;
import com.sap.sse.common.TypeBasedServiceFinder;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
import com.sap.sse.common.Util;
import com.sap.sse.common.WithID;
import com.sap.sse.common.impl.TimeRangeImpl;
/**
@@ -109,7 +110,6 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, AbstractLog<?, ?> log, Competitor competitor)
throws NoCorrespondingServiceRegisteredException, TransformationException{
List<DeviceMapping<Competitor>> mappings = new DeviceCompetitorMappingFinder<>(log).analyze().get(competitor);
if (mappings != null) {
for (DeviceMapping<Competitor> mapping : mappings) {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/);
@@ -197,6 +197,12 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/);
}
@Override
public void loadTrack(DynamicGPSFixTrack<WithID, ?> track, DeviceMapping<WithID> mapping)
throws NoCorrespondingServiceRegisteredException, TransformationException {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true);
}
private DBObject getDeviceQuery(DeviceIdentifier device)
throws TransformationException, NoCorrespondingServiceRegisteredException {
Object dbDeviceId = MongoObjectFactoryImpl.storeDeviceId(deviceServiceFinder, device);
@@ -229,4 +235,5 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore {
}
return ((Number) result.get(FieldNames.NUM_FIXES.name())).longValue();
}
}
@@ -4,6 +4,8 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixImpl;
import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl;
import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl;
@@ -21,8 +23,10 @@ public class MockGPSFixMongoServiceFinder implements TypeBasedServiceFinder<GPSF
@Override
public GPSFixMongoHandler findService(String fixType) {
if (fixType.equals(GPSFixMovingImpl.class.getName())) return movingHandler;
if (fixType.equals(GPSFixImpl.class.getName())) return handler;
if (fixType.equals(GPSFixMovingImpl.class.getName()) ||
fixType.equals(CompactGPSFixMovingImpl.class.getName())) return movingHandler;
if (fixType.equals(GPSFixImpl.class.getName()) ||
fixType.equals(CompactGPSFixImpl.class.getName())) return handler;
return null;
}
@@ -33,6 +33,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.LastPublishedCourseDesignFinder;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogStartTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
@@ -205,26 +206,30 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
CourseBase course = new LastPublishedCourseDesignFinder(fromRaceLog).analyze();
final Set<Mark> marks = new HashSet<>();
course.getWaypoints().forEach(wp->Util.addAll(wp.getMarks(), marks));
Set<Competitor> competitors = new RegisteredCompetitorsAnalyzer<>(fromRaceLog).analyze();
final Set<Competitor> competitors = new RegisteredCompetitorsAnalyzer<>(fromRaceLog).analyze();
final List<RaceLogEvent> raceLogDeviceMarkMappingEvents = new AllEventsOfTypeFinder<>(fromRaceLog, /* only unrevoked */ true, RaceLogDeviceMarkMappingEvent.class).analyze();
for (RaceLog toRaceLog : toRaceLogs) {
if (course == null || !new RaceLogTrackingStateAnalyzer(toRaceLog).analyze().isForTracking()) {
continue;
}
CourseBase to = new CourseDataImpl("Copy of \"" + course.getName());
CourseBase newCourse = new CourseDataImpl("Copy of \"" + course.getName() + "\"");
TimePoint now = MillisecondsTimePoint.now();
int i = 0;
revokeAlreadyDefinedMarks(toRaceLog, service.getServerAuthor());
for (Waypoint oldWaypoint : course.getWaypoints()) {
to.addWaypoint(i++, oldWaypoint);
newCourse.addWaypoint(i++, oldWaypoint);
}
for (Mark mark : marks) {
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createDefineMarkEvent(now,
service.getServerAuthor(), toRaceLog.getCurrentPassId(), mark);
toRaceLog.add(event);
}
for (RaceLogEvent raceLogDeviceMarkMappingEvent : raceLogDeviceMarkMappingEvents) {
toRaceLog.add(raceLogDeviceMarkMappingEvent);
}
int passId = toRaceLog.getCurrentPassId();
RaceLogEvent newCourseEvent = RaceLogEventFactory.INSTANCE.createCourseDesignChangedEvent(now,
service.getServerAuthor(), passId, to);
service.getServerAuthor(), passId, newCourse);
toRaceLog.add(newCourseEvent);
registerCompetitors(service, toRaceLog, competitors);
}
@@ -35,6 +35,7 @@ Export-Package: com.sap.sailing.domain.abstractlog,
com.sap.sailing.domain.abstractlog.regatta.events,
com.sap.sailing.domain.abstractlog.regatta.events.impl,
com.sap.sailing.domain.abstractlog.regatta.impl,
com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl,
com.sap.sailing.domain.abstractlog.shared.analyzing,
com.sap.sailing.domain.abstractlog.shared.events,
com.sap.sailing.domain.base,
@@ -0,0 +1,15 @@
apply plugin: "java"
sourceSets {
main {
java.srcDirs = ["src"]
}
}
dependencies {
/* local dependencies */
compile project(":java:com.sap.sailing.domain.common")
compile project(":java:com.sap.sse.common")
compile project(":java:com.sap.sse.datamining.shared")
compile project(":java:com.sap.sse.shared.android")
}
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ReadonlyRac
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.basic.impl.BasicRacingProcedureImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ess.impl.ESSRacingProcedureImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.gate.impl.GateStartRacingProcedureImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league.impl.LeagueRacingProcedureImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.rrs26.impl.RRS26RacingProcedureImpl;
import com.sap.sailing.domain.base.configuration.ConfigurationLoader;
import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
@@ -48,6 +49,8 @@ public class ReadonlyRacingProcedureFactory implements RacingProcedureFactory {
return new RRS26RacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getRRS26Configuration());
case BASIC:
return new BasicRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getBasicConfiguration());
case LEAGUE:
return new LeagueRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getLeagueConfiguration());
default:
throw new UnsupportedOperationException("Unknown racing procedure " + type.toString());
}
@@ -0,0 +1,7 @@
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedure;
public interface LeagueRacingProcedure extends RacingProcedure {
}
@@ -0,0 +1,6 @@
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedureChangedListener;
public interface LeagueRacingProcedureChangedListener extends RacingProcedureChangedListener {
}
@@ -0,0 +1,22 @@
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league.impl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedurePrerequisite;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.impl.BaseRacingProcedurePrerequisite;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league.LeagueRacingProcedure;
import com.sap.sse.common.TimePoint;
/**
* Easy access to the {@link LeagueRacingProcedure}.
*/
public abstract class LeaguePrerequisite extends BaseRacingProcedurePrerequisite implements RacingProcedurePrerequisite {
public LeaguePrerequisite(FulfillmentFunction function, LeagueRacingProcedure procedure, TimePoint originalNow,
TimePoint originalStartTime) {
super(function, procedure, originalNow, originalStartTime);
}
protected LeagueRacingProcedure getProcedure() {
return (LeagueRacingProcedure) procedure;
}
}
@@ -0,0 +1,8 @@
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league.impl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.impl.RacingProcedureChangedListeners;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.league.LeagueRacingProcedureChangedListener;
public class LeagueRacingProcedureChangedListeners extends RacingProcedureChangedListeners<LeagueRacingProcedureChangedListener> implements
LeagueRacingProcedureChangedListener {
}
@@ -0,0 +1,154 @@
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.abstractlog.race.state.racingprocedure.league.LeagueRacingProcedure;
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 implements LeagueRacingProcedure {
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;
}
public boolean processStateEvent(RaceStateEvent event) {
switch (event.getEventName()) {
case RRS26_STARTMODE_UP:
case RRS26_CLASS_UP:
case RRS26_STARTMODE_DOWN:
getChangedListeners().onActiveFlagsChanged(this);
return true;
default:
return super.processStateEvent(event);
}
}
@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();
}
}
@@ -0,0 +1,31 @@
package com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl;
import java.io.Serializable;
import java.util.UUID;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogCloseOpenEndedDeviceMappingEventImpl;
import com.sap.sailing.domain.abstractlog.shared.analyzing.OpenEndedDeviceMappingCloser;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class RegattaLogOpenEndedDeviceMappingCloser extends
OpenEndedDeviceMappingCloser<RegattaLog, RegattaLogEvent, RegattaLogEventVisitor, RegattaLogCloseOpenEndedDeviceMappingEvent> {
public RegattaLogOpenEndedDeviceMappingCloser(RegattaLog log, DeviceMapping<?> mapping, AbstractLogEventAuthor author,
TimePoint closingTimePoint) {
super(log, mapping, author, closingTimePoint);
}
@Override
protected RegattaLogCloseOpenEndedDeviceMappingEvent createCloseEvent(TimePoint logicalTimePoint,
Serializable eventToCloseId) {
return new RegattaLogCloseOpenEndedDeviceMappingEventImpl(MillisecondsTimePoint.now(), author,
logicalTimePoint, UUID.randomUUID(), eventToCloseId, closingTimePoint);
}
}
@@ -21,7 +21,6 @@ public class DeviceCompetitorMappingFinder<LogT extends AbstractLog<EventT, Visi
public LogAnalyzer<Map<Competitor, List<DeviceMapping<Competitor>>>> createAnalyzer(AbstractLog<?, ?> log) {
return new DeviceCompetitorMappingFinder(log);
}
}
public DeviceCompetitorMappingFinder(LogT log) {
@@ -1,5 +1,7 @@
package com.sap.sailing.domain.base;
import java.net.URI;
import com.sap.sse.common.Color;
public interface CompetitorChangeListener extends BoatChangeListener, NationalityChangeListener {
@@ -8,4 +10,6 @@ public interface CompetitorChangeListener extends BoatChangeListener, Nationalit
void nameChanged(String oldName, String newName);
void emailChanged(String oldEmail, String newEmail);
void flagImageChanged(URI oldFlagImageURI, URI newFlagImageURI);
}
@@ -5,6 +5,7 @@ import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedure;
import com.sap.sailing.domain.base.configuration.procedures.ESSConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.GateStartConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.LeagueConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.RRS26Configuration;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
@@ -42,7 +43,13 @@ public interface RegattaConfiguration extends Serializable, Cloneable {
* @return <code>null</code> if there is no configuration.
*/
ESSConfiguration getESSConfiguration();
/**
* Gets the configuration for league races.
* @return <code>null</code> if there is no configuration.
*/
LeagueConfiguration getLeagueConfiguration();
/**
* Gets the configuration for Basic races.
* @return <code>null</code> if there is no configuration.
@@ -21,6 +21,7 @@ public class EmptyRegattaConfiguration extends RegattaConfigurationImpl implemen
setGateStartConfiguration(new GateStartConfigurationImpl());
setESSConfiguration(new ESSConfigurationImpl());
setBasicConfiguration(new RacingProcedureConfigurationImpl());
setLeagueConfiguration(new LeagueConfigurationImpl());
return clone();
}
@@ -0,0 +1,20 @@
package com.sap.sailing.domain.base.configuration.impl;
import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.LeagueConfiguration;
public class LeagueConfigurationImpl extends RacingProcedureConfigurationImpl implements LeagueConfiguration {
private static final long serialVersionUID = 3625803505541394766L;
protected LeagueConfigurationImpl copy() {
LeagueConfigurationImpl copy = (LeagueConfigurationImpl) super.copy(new LeagueConfigurationImpl());
return copy;
}
@Override
public RacingProcedureConfiguration merge(RacingProcedureConfiguration update) {
LeagueConfigurationImpl target = (LeagueConfigurationImpl) super.merge(update);
return target;
}
}
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration;
import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.ESSConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.GateStartConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.LeagueConfiguration;
import com.sap.sailing.domain.base.configuration.procedures.RRS26Configuration;
import com.sap.sailing.domain.common.CourseDesignerMode;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
@@ -18,6 +19,7 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
private RRS26Configuration rrs26Configuration;
private GateStartConfiguration gateStartConfiguration;
private ESSConfiguration essConfiguration;
private LeagueConfiguration leagueConfiguration;
private RacingProcedureConfiguration basicConfiguration;
@Override
@@ -65,6 +67,15 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
this.essConfiguration = essConfiguration;
}
@Override
public LeagueConfiguration getLeagueConfiguration() {
return leagueConfiguration;
}
public void setLeagueConfiguration(LeagueConfiguration leagueConfiguration) {
this.leagueConfiguration = leagueConfiguration;
}
@Override
public RacingProcedureConfiguration getBasicConfiguration() {
return basicConfiguration;
@@ -83,6 +94,7 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
copy.setGateStartConfiguration(gateStartConfiguration);
copy.setESSConfiguration(essConfiguration);
copy.setBasicConfiguration(basicConfiguration);
copy.setLeagueConfiguration(leagueConfiguration);
return copy;
}
@@ -112,6 +124,10 @@ public class RegattaConfigurationImpl implements RegattaConfiguration {
target.setBasicConfiguration(
(RacingProcedureConfiguration) target.getBasicConfiguration().merge(update.getBasicConfiguration()));
}
if (update.getLeagueConfiguration() != null) {
target.setLeagueConfiguration(
(LeagueConfiguration) target.getLeagueConfiguration().merge(update.getLeagueConfiguration()));
}
return target;
}
@@ -0,0 +1,7 @@
package com.sap.sailing.domain.base.configuration.procedures;
import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration;
public interface LeagueConfiguration extends RacingProcedureConfiguration {
}
@@ -145,6 +145,12 @@ public class CompetitorImpl implements DynamicCompetitor {
@Override
public void setFlagImage(URI flagImage) {
final URI oldFlagImage = this.flagImage;
this.flagImage = flagImage;
if (!Util.equalsWithNull(oldFlagImage, flagImage)) {
for (CompetitorChangeListener listener : getListeners()) {
listener.flagImageChanged(oldFlagImage, flagImage);
}
}
}
}
@@ -179,10 +179,14 @@ public class SharedDomainFactoryImpl implements SharedDomainFactory {
@Override
public ControlPointWithTwoMarks getOrCreateControlPointWithTwoMarks(Serializable id, String name, Mark left, Mark right) {
if (controlPointWithTwoMarksCache.containsKey(id)) {
return controlPointWithTwoMarksCache.get(id);
final ControlPointWithTwoMarks result;
final ControlPointWithTwoMarks fromCache = controlPointWithTwoMarksCache.get(id);
if (fromCache != null) {
result = fromCache;
} else {
result = createControlPointWithTwoMarks(id, left, right, name);
}
return createControlPointWithTwoMarks(id, left, right, name);
return result;
}
@Override
@@ -47,4 +47,10 @@ public interface RaceGroup extends Named {
* Gets configuration objects for {@link RacingProcedure}s of this {@link RaceGroup}'s races.
*/
public RegattaConfiguration getRegattaConfiguration();
/**
* An optional (may be <code>null</code>0 non-identifying name that may, e.g., be a short name
* for the necessarily unique and therefore potentially longer, maybe clumsy full {@link #getName()}.
*/
String getDisplayName();
}
@@ -10,29 +10,39 @@ import com.sap.sse.common.impl.NamedImpl;
public class RaceGroupImpl extends NamedImpl implements RaceGroup {
private static final long serialVersionUID = 7760879536339600827L;
private final String displayName;
private final BoatClass boatClass;
private final CourseArea courseArea;
private final Iterable<SeriesWithRows> series;
private final RegattaConfiguration regattaConfiguration;
public RaceGroupImpl(String name, BoatClass boatClass, CourseArea courseArea, Iterable<SeriesWithRows> series,
RegattaConfiguration regattaConfiguration) {
public RaceGroupImpl(String name, String displayName, BoatClass boatClass, CourseArea courseArea,
Iterable<SeriesWithRows> series, RegattaConfiguration regattaConfiguration) {
super(name);
this.displayName = displayName;
this.boatClass = boatClass;
this.courseArea = courseArea;
this.series = series;
this.regattaConfiguration = regattaConfiguration;
}
@Override
public String getDisplayName() {
return displayName;
}
@Override
public CourseArea getDefaultCourseArea() {
return courseArea;
}
@Override
public Iterable<SeriesWithRows> getSeries() {
return series;
}
@Override
public BoatClass getBoatClass() {
return boatClass;
}
@@ -319,7 +319,7 @@ public class DomainFactoryImpl implements DomainFactory {
for (Mark mark : marks) {
// TODO bug 1043: propagate the mark names to the waypoint names
com.sap.sailing.domain.base.ControlPoint domainControlPoint = getOrCreateControlPoint(mark.getDevices());
newDomainControlPoints.add(new com.sap.sse.common.Util.Pair<com.sap.sailing.domain.base.ControlPoint, PassingInstruction>(domainControlPoint, null));
newDomainControlPoints.add(new com.sap.sse.common.Util.Pair<>(domainControlPoint, PassingInstruction.None));
}
courseToUpdate.update(newDomainControlPoints, baseDomainFactory);
}
@@ -53,6 +53,7 @@ import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
import com.sap.sailing.domain.tracking.impl.TrackedRaceStatusImpl;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import difflib.PatchFailedException;
@@ -294,9 +295,9 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
Course course = race.getCourse();
try {
// TODO: Does SwissTiming also deliver the passing side for course marks?
List<com.sap.sse.common.Util.Pair<ControlPoint, PassingInstruction>> courseToUpdate = new ArrayList<com.sap.sse.common.Util.Pair<ControlPoint, PassingInstruction>>();
List<Pair<ControlPoint, PassingInstruction>> courseToUpdate = new ArrayList<>();
for (ControlPoint cp : currentCourseDefinition) {
courseToUpdate.add(new com.sap.sse.common.Util.Pair<ControlPoint, PassingInstruction>(cp, null));
courseToUpdate.add(new Pair<ControlPoint, PassingInstruction>(cp, PassingInstruction.None));
}
course.update(courseToUpdate, domainFactory.getBaseDomainFactory());
} catch (PatchFailedException e) {
@@ -149,9 +149,9 @@ public abstract class AbstractTracTracLiveTest extends StoredTrackBasedTest {
}
public static Iterable<Pair<TracTracControlPoint, PassingInstruction>> getTracTracControlPointsWithPassingInstructions(Iterable<IControl> controlPoints) {
List<Pair<TracTracControlPoint, PassingInstruction>> ttControlPoints = new ArrayList<Pair<TracTracControlPoint, PassingInstruction>>();
List<Pair<TracTracControlPoint, PassingInstruction>> ttControlPoints = new ArrayList<>();
for (IControl cp : controlPoints) {
ttControlPoints.add(new Pair<TracTracControlPoint, PassingInstruction>(new ControlPointAdapter(cp), null));
ttControlPoints.add(new Pair<TracTracControlPoint, PassingInstruction>(new ControlPointAdapter(cp), PassingInstruction.None));
}
return ttControlPoints;
}
@@ -7,6 +7,8 @@ import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.junit.Before;
import org.junit.Test;
@@ -45,6 +47,12 @@ public class CompetitorListenerTest extends AbstractSerializationTest {
private Color newColor;
private DynamicCompetitor competitor;
private DomainFactoryImpl baseDomainFactory;
private boolean emailChanged;
private String oldEmail;
private String newEmail;
private boolean flagImageChanged;
private URI oldFlagImageURL;
private URI newFlagImageURL;
@Before
public void setUp() {
@@ -63,6 +71,12 @@ public class CompetitorListenerTest extends AbstractSerializationTest {
colorChanged = false;
oldColor = null;
newColor = null;
emailChanged = false;
oldEmail = null;
newEmail = null;
flagImageChanged = false;
oldFlagImageURL = null;
newFlagImageURL = null;
listener = new CompetitorChangeListener() {
private static final long serialVersionUID = 4581029778988240209L;
@@ -97,7 +111,16 @@ public class CompetitorListenerTest extends AbstractSerializationTest {
@Override
public void emailChanged(String oldEmail, String newEmail) {
//TODO
emailChanged = true;
CompetitorListenerTest.this.oldEmail = oldEmail;
CompetitorListenerTest.this.newEmail = newEmail;
}
@Override
public void flagImageChanged(URI oldFlagImageURL, URI newFlagImageURL) {
flagImageChanged = true;
CompetitorListenerTest.this.oldFlagImageURL = oldFlagImageURL;
CompetitorListenerTest.this.newFlagImageURL = newFlagImageURL;
}
};
competitor.addCompetitorChangeListener(listener);
@@ -126,6 +149,22 @@ public class CompetitorListenerTest extends AbstractSerializationTest {
assertFalse(nationalityChanged);
}
@Test
public void testFlagChange() throws URISyntaxException {
competitor.setFlagImage(new URI("http://www.something.de/pic.png"));
assertTrue(flagImageChanged);
assertNull(oldFlagImageURL);
assertEquals(new URI("http://www.something.de/pic.png"), newFlagImageURL);
}
@Test
public void testEmailChange() throws URISyntaxException {
competitor.setEmail("hasso.plattner@sap.com");
assertTrue(emailChanged);
assertNull(oldEmail);
assertEquals("hasso.plattner@sap.com", newEmail);
}
@Test
public void testSimpleCompetitorListenerPatternForSailId() {
final String myOldSailId = competitor.getBoat().getSailID();
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -31,6 +32,7 @@ import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.MarkImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
@@ -47,6 +49,7 @@ import com.sap.sailing.domain.tractracadapter.impl.ControlPointAdapter;
import com.sap.sailing.domain.tractracadapter.impl.DomainFactoryImpl;
import com.sap.sailing.domain.tractracadapter.impl.RaceCourseReceiver;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.Util.Triple;
import com.tractrac.model.lib.api.event.CreateModelException;
import com.tractrac.model.lib.api.event.IRace;
@@ -166,6 +169,35 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest {
assertEquals(wp2, deletedWaypoints.iterator().next());
}
/**
* A test failing before bug 2858 was fixed: updating only the {@link PassingInstructions} of a {@link Waypoint#getPassingInstructions() waypoint}
* would have left the waypoint in place, not updating the course properly.
*/
@Test
public void testWaypointListDiffWithDifferentPassingInstructionsOnly() throws PatchFailedException {
Waypoint wp1 = new WaypointImpl(new MarkImpl("b1"), PassingInstruction.Port);
Waypoint wp2 = new WaypointImpl(new MarkImpl("b2"), PassingInstruction.Port);
Waypoint wp3 = new WaypointImpl(new MarkImpl("b3"), PassingInstruction.Port);
Waypoint wp4 = new WaypointImpl(new MarkImpl("b4"), PassingInstruction.Port);
List<Waypoint> waypoints = new ArrayList<Waypoint>(4);
waypoints.add(wp1);
waypoints.add(wp2);
waypoints.add(wp3);
waypoints.add(wp4);
Course course = new CourseImpl("Test Course", waypoints);
List<Pair<ControlPoint, PassingInstruction>> changedControlPoints = new ArrayList<>();
changedControlPoints.add(new Pair<>(wp1.getControlPoint(), PassingInstruction.Starboard));
changedControlPoints.add(new Pair<>(wp2.getControlPoint(), wp2.getPassingInstructions()));
changedControlPoints.add(new Pair<>(wp3.getControlPoint(), wp3.getPassingInstructions()));
changedControlPoints.add(new Pair<>(wp4.getControlPoint(), wp4.getPassingInstructions()));
course.update(changedControlPoints, com.sap.sailing.domain.base.DomainFactory.INSTANCE);
assertNotSame(wp1, Util.get(course.getWaypoints(), 0));
assertSame(wp2, Util.get(course.getWaypoints(), 1));
assertSame(wp3, Util.get(course.getWaypoints(), 2));
assertSame(wp4, Util.get(course.getWaypoints(), 3));
}
@Test
public void testLastWaypointRemoved() throws PatchFailedException, InterruptedException {
final boolean[] result = new boolean[1];
@@ -0,0 +1,199 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.SpeedWithBearingWithConfidenceImpl;
import com.sap.sailing.domain.base.impl.SpeedWithConfidenceImpl;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.impl.WindImpl;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.TrackedLegImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class TargetTimeEstimationTest {
@Test
public void simpleReachTargetTimeEstimation() throws NotEnoughDataHasBeenAddedException, NoWindException {
// Setup mock objects
PolarDataService mockedPolars = mock(PolarDataService.class);
BoatClass mockedBoatClass = mock(BoatClass.class);
Position centerOfCourse = new DegreePosition(54.432800, 10.193655);
TimePoint timepoint = new MillisecondsTimePoint(1431426491696l);
Bearing windBearing = new DegreeBearingImpl(90);
SpeedWithBearing windSpeedWithBearing = new KnotSpeedWithBearingImpl(10, windBearing);
Wind wind = new WindImpl(centerOfCourse, timepoint, windSpeedWithBearing);
Position startOfLeg = new DegreePosition(54.434648, 10.193312);
Position endOfLeg = new DegreePosition(54.430454, 10.193226);
Bearing legBearing = startOfLeg.getBearingGreatCircle(endOfLeg);
SpeedWithConfidence<Void> boatSpeedWithConfidence = new SpeedWithConfidenceImpl<Void>(new KnotSpeedImpl(12), 1, null);
DynamicTrackedRaceImpl trackedRace = mock(DynamicTrackedRaceImpl.class);
when(trackedRace.getCenterOfCourse(timepoint)).thenReturn(centerOfCourse);
WindSource source = mock(WindSource.class);
Set<WindSource> sources = Collections.singleton(source);
when(trackedRace.getWindSources(WindSourceType.TRACK_BASED_ESTIMATION)).thenReturn(sources);
when(trackedRace.getWind(any(Position.class), eq(timepoint), eq(sources))).thenReturn(wind);
RaceDefinition race = mock(RaceDefinition.class);
when(race.getBoatClass()).thenReturn(mockedBoatClass);
when(trackedRace.getRace()).thenReturn(race);
Leg leg = mock(Leg.class);
Waypoint from = mock(Waypoint.class);
Waypoint to = mock(Waypoint.class);
when(leg.getFrom()).thenReturn(from);
when(leg.getTo()).thenReturn(to);
when(trackedRace.getApproximatePosition(from, timepoint)).thenReturn(startOfLeg);
when(trackedRace.getApproximatePosition(to, timepoint)).thenReturn(endOfLeg);
when(mockedPolars.getSpeed(mockedBoatClass, wind, windBearing.getDifferenceTo(legBearing))).thenReturn(boatSpeedWithConfidence);
HashSet<Competitor> competitors = new HashSet<Competitor>();
TrackedLeg trackedLeg = new TrackedLegImpl(trackedRace, leg, competitors);
//Actual test of functionality
Duration duration = trackedLeg.getEstimatedTimeToComplete(mockedPolars, timepoint);
assertEquals(75494, duration.asMillis(), 100);
}
@Test
public void simpleUpwindTargetTimeEstimation() throws NotEnoughDataHasBeenAddedException, NoWindException {
// Setup mock objects
PolarDataService mockedPolars = mock(PolarDataService.class);
BoatClass mockedBoatClass = mock(BoatClass.class);
Position centerOfCourse = new DegreePosition(54.432800, 10.193655);
TimePoint timepoint = new MillisecondsTimePoint(1431426491696l);
Bearing windBearing = new DegreeBearingImpl(-175);
SpeedWithBearing windSpeedWithBearing = new KnotSpeedWithBearingImpl(10, windBearing);
Wind wind = new WindImpl(centerOfCourse, timepoint, windSpeedWithBearing);
Position endOfLeg = new DegreePosition(54.434648, 10.193312);
Position startOfLeg = new DegreePosition(54.430454, 10.193226);
DynamicTrackedRaceImpl trackedRace = mock(DynamicTrackedRaceImpl.class);
when(trackedRace.getCenterOfCourse(timepoint)).thenReturn(centerOfCourse);
WindSource source = mock(WindSource.class);
Set<WindSource> sources = Collections.singleton(source);
when(trackedRace.getWindSources(WindSourceType.TRACK_BASED_ESTIMATION)).thenReturn(sources);
when(trackedRace.getWind(any(Position.class), eq(timepoint), eq(sources))).thenReturn(wind);
RaceDefinition race = mock(RaceDefinition.class);
when(race.getBoatClass()).thenReturn(mockedBoatClass);
when(trackedRace.getRace()).thenReturn(race);
Leg leg = mock(Leg.class);
Waypoint from = mock(Waypoint.class);
Waypoint to = mock(Waypoint.class);
when(leg.getFrom()).thenReturn(from);
when(leg.getTo()).thenReturn(to);
when(trackedRace.getApproximatePosition(from, timepoint)).thenReturn(startOfLeg);
when(trackedRace.getApproximatePosition(to, timepoint)).thenReturn(endOfLeg);
SpeedWithBearing speedWithBearingPort = new KnotSpeedWithBearingImpl(6, new DegreeBearingImpl(-45));
SpeedWithBearingWithConfidence<Void> boatSpeedWithBearingWithConfidencePort = new SpeedWithBearingWithConfidenceImpl<Void>(speedWithBearingPort, 1, null);
when(mockedPolars.getAverageSpeedWithBearing(mockedBoatClass, wind, LegType.UPWIND, Tack.PORT)).thenReturn(boatSpeedWithBearingWithConfidencePort);
SpeedWithBearing speedWithBearingStarboard = new KnotSpeedWithBearingImpl(6, new DegreeBearingImpl(45));
SpeedWithBearingWithConfidence<Void> boatSpeedWithBearingWithConfidenceStarboard = new SpeedWithBearingWithConfidenceImpl<Void>(speedWithBearingStarboard, 1, null);
when(mockedPolars.getAverageSpeedWithBearing(mockedBoatClass, wind, LegType.UPWIND, Tack.STARBOARD)).thenReturn(boatSpeedWithBearingWithConfidenceStarboard);
HashSet<Competitor> competitors = new HashSet<Competitor>();
TrackedLeg trackedLeg = new TrackedLegImpl(trackedRace, leg, competitors);
//Actual test of functionality
Duration duration = trackedLeg.getEstimatedTimeToComplete(mockedPolars, timepoint);
assertEquals(213513, duration.asMillis(), 100);
}
@Test
public void simpleDownwindTargetTimeEstimation() throws NotEnoughDataHasBeenAddedException, NoWindException {
// Setup mock objects
PolarDataService mockedPolars = mock(PolarDataService.class);
BoatClass mockedBoatClass = mock(BoatClass.class);
Position centerOfCourse = new DegreePosition(54.432800, 10.193655);
TimePoint timepoint = new MillisecondsTimePoint(1431426491696l);
Bearing windBearing = new DegreeBearingImpl(5);
SpeedWithBearing windSpeedWithBearing = new KnotSpeedWithBearingImpl(10, windBearing);
Wind wind = new WindImpl(centerOfCourse, timepoint, windSpeedWithBearing);
Position endOfLeg = new DegreePosition(54.434648, 10.193312);
Position startOfLeg = new DegreePosition(54.430454, 10.193226);
DynamicTrackedRaceImpl trackedRace = mock(DynamicTrackedRaceImpl.class);
when(trackedRace.getCenterOfCourse(timepoint)).thenReturn(centerOfCourse);
WindSource source = mock(WindSource.class);
Set<WindSource> sources = Collections.singleton(source);
when(trackedRace.getWindSources(WindSourceType.TRACK_BASED_ESTIMATION)).thenReturn(sources);
when(trackedRace.getWind(any(Position.class), eq(timepoint), eq(sources))).thenReturn(wind);
RaceDefinition race = mock(RaceDefinition.class);
when(race.getBoatClass()).thenReturn(mockedBoatClass);
when(trackedRace.getRace()).thenReturn(race);
Leg leg = mock(Leg.class);
Waypoint from = mock(Waypoint.class);
Waypoint to = mock(Waypoint.class);
when(leg.getFrom()).thenReturn(from);
when(leg.getTo()).thenReturn(to);
when(trackedRace.getApproximatePosition(from, timepoint)).thenReturn(startOfLeg);
when(trackedRace.getApproximatePosition(to, timepoint)).thenReturn(endOfLeg);
SpeedWithBearing speedWithBearingPort = new KnotSpeedWithBearingImpl(11, new DegreeBearingImpl(150));
SpeedWithBearingWithConfidence<Void> boatSpeedWithBearingWithConfidencePort = new SpeedWithBearingWithConfidenceImpl<Void>(speedWithBearingPort, 1, null);
when(mockedPolars.getAverageSpeedWithBearing(mockedBoatClass, wind, LegType.DOWNWIND, Tack.PORT)).thenReturn(boatSpeedWithBearingWithConfidencePort);
SpeedWithBearing speedWithBearingStarboard = new KnotSpeedWithBearingImpl(11, new DegreeBearingImpl(-150));
SpeedWithBearingWithConfidence<Void> boatSpeedWithBearingWithConfidenceStarboard = new SpeedWithBearingWithConfidenceImpl<Void>(speedWithBearingStarboard, 1, null);
when(mockedPolars.getAverageSpeedWithBearing(mockedBoatClass, wind, LegType.DOWNWIND, Tack.STARBOARD)).thenReturn(boatSpeedWithBearingWithConfidenceStarboard);
HashSet<Competitor> competitors = new HashSet<Competitor>();
TrackedLeg trackedLeg = new TrackedLegImpl(trackedRace, leg, competitors);
//Actual test of functionality
Duration duration = trackedLeg.getEstimatedTimeToComplete(mockedPolars, timepoint);
assertEquals(95090, duration.asMillis(), 100);
}
}
@@ -149,7 +149,9 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
Wind combinedWindDirection = combinedTrack.getAveragedWind(/* position */ null, now);
// The course layout makes a wind estimation around 7deg. The confidence of the cluster based wind estimation is a lot
// higher that that of the course layout wind (currently at approximately 10E-13), we will end up quite near 180 deg.
assertEquals(180.0, combinedWindDirection.getBearing().getDegrees(), 0.2);
// Update 04/24/15: Since polar data service is not available here, the confidence will not be as good as it once was.
// So we have quite a big delta in the assert
assertEquals(180.0, combinedWindDirection.getBearing().getDegrees(), 0.9);
}
/**
Loaded 100 of 1785 files, more files were not shown because too many files have changed in this diff. Show more