diff --git a/configuration/RunFortifyBuild b/configuration/RunFortifyBuild new file mode 100755 index 00000000000..b63a0122a6b --- /dev/null +++ b/configuration/RunFortifyBuild @@ -0,0 +1,3 @@ +#!/bin/bash +sourceanalyzer -b com.sap.sailing.domain -Xmx4000m -debug -logfile FortifyScan.log -extdirs /home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins -cp "/home/sailing/code/java/com.google.gwt.osgi/lib/gwt-user.jar:/home/sailing/gwt-2.7.0/validation-api-1.0.0.GA.jar:/home/sailing/gwt-2.7.0/gwt-codeserver.jar:/home/sailing/gwt-2.7.0/validation-api-1.0.0.GA-sources.jar:/home/sailing/gwt-2.7.0/gwt-user.jar:/home/sailing/gwt-2.7.0/gwt-dev.jar:/home/sailing/code/java/com.google.gwt.dev/lib/gwt-dev.jar:/home/sailing/code/java/com.tractrac.clientmodule/lib/TracAPI.jar:/home/sailing/code/java/com.sap.sailing.dashboards.gwt/WEB-INF/lib/gwt-ajaxloader.jar:/home/sailing/code/java/com.sap.sailing.dashboards.gwt/WEB-INF/lib/gwt-maps-api-3.9.0-build-17.jar:/home/sailing/code/java/com.googlecode.mgwt/lib/mgwt-2.0.0.jar:/home/sailing/code/java/com.sap.sailing.gwt.ui/WEB-INF/lib/gwt-bootstrap-2.3.2.0.jar:/home/sailing/code/java/com.sap.sailing.gwt.ui/WEB-INF/lib/gwt-maps-api-3.9.0-build-17.jar:/home/sailing/code/java/com.sap.sailing.gwt.ui/WEB-INF/lib/gwt-ajaxloader.jar" -source 1.8 "/home/sailing/code/java/com.sap.sailing.ess40.resultimport" "/home/sailing/code/java/com.sap.sailing.manage2sail" "/home/sailing/code/java/com.sap.sailing.manage2sail.resultimport" "/home/sailing/code/java/com.tractrac.clientmodule" "/home/sailing/code/java/com.sap.sse.filestorage" "/home/sailing/code/java/com.sap.sailing.domain.swisstimingreplayadapter" "/home/sailing/code/java/com.sap.sse.mongodb" "/home/sailing/code/java/com.sap.sailing.udpconnector" "/home/sailing/code/java/com.sap.sailing.server.gateway" "/home/sailing/code/java/com.sap.sse" "/home/sailing/code/java/com.sap.sse.datamining" "/home/sailing/code/java/com.sap.sailing.domain.racelogtrackingadapter" "/home/sailing/code/java/com.sap.sailing.datamining.shared" "/home/sailing/code/java/com.sap.sailing.domain.igtimiadapter.persistence" "/home/sailing/code/java/com.sap.sailing.monitoring" "/home/sailing/code/java/com.sap.sailing.domain" "/home/sailing/code/java/com.sap.sse.datamining.annotations" "/home/sailing/code/java/com.sap.sailing.domain.swisstimingadapter.persistence" "/home/sailing/code/java/com.sap.sse.threadmanager" "/home/sailing/code/java/com.sap.sailing.xrr.structureimport" "/home/sailing/code/java/com.sap.sailing.freg.resultimport" "/home/sailing/code/java/com.sap.sailing.domain.igtimiadapter" "/home/sailing/code/java/com.sap.sailing.server.gateway.ess40" "/home/sailing/code/java/com.sap.sailing.xrr.schema" "/home/sailing/code/java/com.sap.sse.common" "/home/sailing/code/java/com.sap.sailing.expeditionconnector" "/home/sailing/code/java/com.sap.sailing.declination" "/home/sailing/code/java/com.sap.sailing.geocoding" "/home/sailing/code/java/com.sap.sailing.server.gateway.serialization" "/home/sailing/code/java/com.sap.sailing.kiworesultimport" "/home/sailing/code/java/com.sap.sailing.polars.datamining" "/home/sailing/code/java/com.sap.sailing.simulator" "/home/sailing/code/java/com.sap.sse.replication" "/home/sailing/code/java/com.sap.sailing.www" "/home/sailing/code/java/com.sap.sse.gwt.adminconsole" "/home/sailing/code/java/com.sap.sailing.dashboards.gwt" "/home/sailing/code/java/com.sap.sailing.news" "/home/sailing/code/java/com.sap.sailing.polars.datamining.shared" "/home/sailing/code/java/com.sap.sailing.barbados.resultimport" "/home/sailing/code/java/com.sap.sse.security.common" "/home/sailing/code/java/com.sap.sse.security.ui" "/home/sailing/code/java/com.sap.sse.shared.android" "/home/sailing/code/java/org.json.simple" "/home/sailing/code/java/com.sap.sailing.resultimport" "/home/sailing/code/java/com.sap.sse.security" "/home/sailing/code/java/com.sap.sailing.gwt.ui" "/home/sailing/code/java/com.sap.sailing.domain.tractracadapter" "/home/sailing/code/java/com.sap.sailing.server.trackfiles" "/home/sailing/code/java/com.googlecode.java-diff-utils" "/home/sailing/code/java/com.sap.sse.operationaltransformation" "/home/sailing/code/java/com.sap.sailing.domain.swisstimingadapter" "/home/sailing/code/java/com.sap.sse.gwt.theme" "/home/sailing/code/java/com.sap.sailing.domain.persistence" "/home/sailing/code/java/com.sap.sailing.sailwave.resultimport" "/home/sailing/code/java/com.sap.sailing.xmlexport" "/home/sailing/code/java/com.sap.sse.mail" "/home/sailing/code/java/com.sap.sailing.velum.resultimport" "/home/sailing/code/java/com.sap.sse.security.userstore.mongodb" "/home/sailing/code/java/com.sap.sailing.server.gateway.serialization.shared.android" "/home/sailing/code/java/com.sap.sse.datamining.shared" "/home/sailing/code/java/org.moxieapps.gwt.highcharts" "/home/sailing/code/java/com.sap.sailing.autoload" "/home/sailing/code/java/com.googlecode.mgwt" "/home/sailing/code/java/com.sap.sailing.datamining" "/home/sailing/code/java/com.sap.sailing.polars" "/home/sailing/code/java/com.sap.sailing.www.events" "/home/sailing/code/java/com.sap.sailing.domain.common" "/home/sailing/code/java/com.sap.sailing.domain.shared.android" "/home/sailing/code/java/com.sap.sailing.domain.deckmanadapter" "/home/sailing/code/java/com.sap.sailing.server" "/home/sailing/code/java/com.sap.sse.gwt" "/home/sailing/code/java/com.sap.sailing.xrr.resultimport" "/home/sailing/code/java/com.sap.sailing.domain.tractracadapter.persistence" +#sourceanalyzer -b com.sap.sailing -Xmx10g -debug -logfile FortifyScan.log "-show-build-warnings" "-machine-output" "-cp" "/home/sailing/code/java/com.sap.sse.gwt.theme/WEB-INF/classes:/home/sailing/code/java/com.sap.sailing.dashboards.gwt/WEB-INF/classes:/home/sailing/code/java/com.sap.sailing.gwt.ui/WEB-INF/classes:/home/sailing/code/java/com.sap.sse.security.ui/WEB-INF/classes:/home/sailing/code/java/com.sap.sailing.www.events/WEB-INF/classes:/home/sailing/code/java/com.google.gwt.osgi/lib/gwt-user.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.eclipse.osgi_3.10.2.v20150203-1939.jar:/home/sailing/gwt-2.7.0/validation-api-1.0.0.GA.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.eclipse.jetty.osgi.npn.fragment_9.2.2.v20140723.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/javax.servlet_3.1.0.v20140303-1611.jar:/home/sailing/gwt-2.7.0/gwt-codeserver.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.servicemix.bundles.zxing_3.1.0.1.jar:/home/sailing/gwt-2.7.0/validation-api-1.0.0.GA-sources.jar:/home/sailing/gwt-2.7.0/gwt-user.jar:/home/sailing/gwt-2.7.0/gwt-dev.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.commons.math_2.1.0.v201105210652.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/com.fasterxml.jackson.core.jackson-databind_2.5.0.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.hamcrest.core_1.1.0.v20090501071000.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.junit4_4.8.2.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/com.fasterxml.jackson.core.jackson-annotations_2.5.0.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/com.rabbitmq.client_2.8.4.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/lz4-java_1.3.0.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.servicemix.bundles.aws-java-sdk_1.9.8.1.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.commons.logging_1.1.3.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/javax.validation_1.0.0.GA_v201205091237.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.eclipse.jetty.webapp_9.2.2.v20140723.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/com.fasterxml.jackson.core.jackson-core_2.5.0.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.eclipse.jetty.server_9.2.2.v20140723.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.mongodb.mongo-java-driver_2.13.0.RELEASE.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.httpcomponents.httpclient_4.2.6.v201311072007.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.commons.io_2.2.0.v201405211200.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/com.sun.mail.javax.mail_1.4.5.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.eclipse.jetty.io_9.2.2.v20140723.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/javax.ws.rs_1.1.1.v20130318-1750.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.jvnet.mimepull_1.9.4.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.shiro.ehcache_1.2.3.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.commons.lang_2.6.0.v201404270220.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.shiro.core_1.2.2.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.eclipse.jetty.websocket.servlet_9.2.2.v20140723.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.commons.beanutils_1.9.0.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/com.sun.jersey.contribs.jersey-multipart_1.17.0.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.eclipse.jetty.websocket.client_9.2.2.v20140723.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.objectweb.asm_5.0.1.v201404251740.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.jdom_1.1.1.v201101151400.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/routeconverter_2.12.2.201406032322.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/jackson-jaxrs_1.9.13.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.httpcomponents.httpcore_4.2.5.v201311072007.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.shiro.web_1.2.2.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.commons.fileupload_1.2.2.v20111214-1400.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.servicemix.bundles.ehcache_2.6.9.1.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.eclipse.jetty.util_9.2.2.v20140723.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.servicemix.bundles.scribe_1.3.3.1.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.eclipse.jetty.websocket.server_9.2.2.v20140723.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/slf4j.api_1.6.4.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/com.sun.jersey_1.17.0.v20130314-2020.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.eclipse.jetty.websocket.api_9.2.2.v20140723.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.eclipse.jetty.websocket.common_9.2.2.v20140723.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.hyperic.sigar_1.6.4.1.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/jcl.over.slf4j_1.6.4.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.poi_3.9.0.v201405241750.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.dom4j_1.6.1.v201312101416.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.xmlbeans_2.3.0.v201405241900.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.poi.ooxml.schemas_3.9.0.v201405241750.jar:/home/sailing/workspace/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins/org.apache.poi.ooxml_3.9.0.v201405241905.jar:/home/sailing/code/java/com.google.gwt.dev/lib/gwt-dev.jar:/home/sailing/code/java/com.tractrac.clientmodule/lib/TracAPI.jar:/home/sailing/code/java/com.sap.sailing.dashboards.gwt/WEB-INF/lib/gwt-ajaxloader.jar:/home/sailing/code/java/com.sap.sailing.dashboards.gwt/WEB-INF/lib/gwt-maps-api-3.9.0-build-17.jar:/home/sailing/code/java/com.googlecode.mgwt/lib/mgwt-2.0.0.jar:/home/sailing/code/java/com.sap.sailing.gwt.ui/WEB-INF/lib/gwt-bootstrap-2.3.2.0.jar:/home/sailing/code/java/com.sap.sailing.gwt.ui/WEB-INF/lib/gwt-maps-api-3.9.0-build-17.jar:/home/sailing/code/java/com.sap.sailing.gwt.ui/WEB-INF/lib/gwt-ajaxloader.jar" "-source" "1.8" "/home/sailing/code/java/com.sap.sailing.ess40.resultimport" "/home/sailing/code/java/com.sap.sailing.manage2sail" "/home/sailing/code/java/com.sap.sailing.manage2sail.resultimport" "/home/sailing/code/java/com.tractrac.clientmodule" "/home/sailing/code/java/com.sap.sse.filestorage" "/home/sailing/code/java/com.sap.sailing.domain.swisstimingreplayadapter" "/home/sailing/code/java/com.sap.sse.mongodb" "/home/sailing/code/java/com.sap.sailing.udpconnector" "/home/sailing/code/java/com.sap.sailing.server.gateway" "/home/sailing/code/java/com.sap.sse" "/home/sailing/code/java/com.sap.sse.datamining" "/home/sailing/code/java/com.sap.sailing.domain.racelogtrackingadapter" "/home/sailing/code/java/com.sap.sailing.datamining.shared" "/home/sailing/code/java/com.sap.sailing.domain.igtimiadapter.persistence" "/home/sailing/code/java/com.sap.sailing.monitoring" "/home/sailing/code/java/com.sap.sailing.domain" "/home/sailing/code/java/com.sap.sse.datamining.annotations" "/home/sailing/code/java/com.sap.sailing.domain.swisstimingadapter.persistence" "/home/sailing/code/java/com.sap.sse.threadmanager" "/home/sailing/code/java/com.sap.sailing.xrr.structureimport" "/home/sailing/code/java/com.sap.sailing.freg.resultimport" "/home/sailing/code/java/com.sap.sailing.domain.igtimiadapter" "/home/sailing/code/java/com.sap.sailing.server.gateway.ess40" "/home/sailing/code/java/com.sap.sailing.xrr.schema" "/home/sailing/code/java/com.sap.sse.common" "/home/sailing/code/java/com.sap.sailing.expeditionconnector" "/home/sailing/code/java/com.sap.sailing.declination" "/home/sailing/code/java/com.sap.sailing.geocoding" "/home/sailing/code/java/com.sap.sailing.server.gateway.serialization" "/home/sailing/code/java/com.sap.sailing.kiworesultimport" "/home/sailing/code/java/com.sap.sailing.polars.datamining" "/home/sailing/code/java/com.sap.sailing.simulator" "/home/sailing/code/java/com.sap.sse.replication" "/home/sailing/code/java/com.sap.sailing.www" "/home/sailing/code/java/com.sap.sse.gwt.adminconsole" "/home/sailing/code/java/com.sap.sailing.dashboards.gwt" "/home/sailing/code/java/com.sap.sailing.news" "/home/sailing/code/java/com.sap.sailing.polars.datamining.shared" "/home/sailing/code/java/com.sap.sailing.barbados.resultimport" "/home/sailing/code/java/com.sap.sse.security.common" "/home/sailing/code/java/com.sap.sse.security.ui" "/home/sailing/code/java/com.sap.sse.shared.android" "/home/sailing/code/java/org.json.simple" "/home/sailing/code/java/com.sap.sailing.resultimport" "/home/sailing/code/java/com.sap.sse.security" "/home/sailing/code/java/com.sap.sailing.gwt.ui" "/home/sailing/code/java/com.sap.sailing.domain.tractracadapter" "/home/sailing/code/java/com.sap.sailing.server.trackfiles" "/home/sailing/code/java/com.googlecode.java-diff-utils" "/home/sailing/code/java/com.sap.sse.operationaltransformation" "/home/sailing/code/java/com.sap.sailing.domain.swisstimingadapter" "/home/sailing/code/java/com.sap.sse.gwt.theme" "/home/sailing/code/java/com.sap.sailing.domain.persistence" "/home/sailing/code/java/com.sap.sailing.sailwave.resultimport" "/home/sailing/code/java/com.sap.sailing.xmlexport" "/home/sailing/code/java/com.sap.sse.mail" "/home/sailing/code/java/com.sap.sailing.velum.resultimport" "/home/sailing/code/java/com.sap.sse.security.userstore.mongodb" "/home/sailing/code/java/com.sap.sailing.server.gateway.serialization.shared.android" "/home/sailing/code/java/com.sap.sse.datamining.shared" "/home/sailing/code/java/org.moxieapps.gwt.highcharts" "/home/sailing/code/java/com.sap.sailing.autoload" "/home/sailing/code/java/com.googlecode.mgwt" "/home/sailing/code/java/com.sap.sailing.datamining" "/home/sailing/code/java/com.sap.sailing.polars" "/home/sailing/code/java/com.sap.sailing.www.events" "/home/sailing/code/java/com.sap.sailing.domain.common" "/home/sailing/code/java/com.sap.sailing.domain.shared.android" "/home/sailing/code/java/com.sap.sailing.domain.deckmanadapter" "/home/sailing/code/java/com.sap.sailing.server" "/home/sailing/code/java/com.sap.sse.gwt" "/home/sailing/code/java/com.sap.sailing.xrr.resultimport" "/home/sailing/code/java/com.sap.sailing.domain.tractracadapter.persistence" diff --git a/configuration/RunFortifyClean b/configuration/RunFortifyClean new file mode 100755 index 00000000000..e41a19501bd --- /dev/null +++ b/configuration/RunFortifyClean @@ -0,0 +1,2 @@ +#!/bin/bash +sourceanalyzer -b com.sap.sailing.domain -clean diff --git a/configuration/RunFortifyScan b/configuration/RunFortifyScan new file mode 100755 index 00000000000..cc09b144cbe --- /dev/null +++ b/configuration/RunFortifyScan @@ -0,0 +1,3 @@ +#!/bin/bash +#sourceanalyzer -b com.sap.sailing.domain -scan +sourceanalyzer -b com.sap.sailing.domain -Xmx6000m -scan "-f" "/home/sailing/code/java/com.sap.sailing_scan.fpr" diff --git a/home.md b/home.md index 51cc280a2bd..221a0562402 100644 --- a/home.md +++ b/home.md @@ -52,6 +52,7 @@ SAP is at the center of today’s technology revolution, developing innovations * [[Working with GWT Super Dev Mode|wiki/super-dev-mode]] * [[Mobile Development|wiki/mobile-development]] * [[Security|wiki/security]] + * [[Fortify Security Scans|wiki/fortify]] * [[Java De(Serialization) and Circular Dependencies|wiki/java-de-serialization-and-circular-dependencies]] * Information for Webdesigners * [[Layout repository|wiki/webdesign]] diff --git a/java/com.sap.sailing.dashboards.gwt/META-INF/MANIFEST.MF b/java/com.sap.sailing.dashboards.gwt/META-INF/MANIFEST.MF index 15b3a813597..7af263e912b 100644 --- a/java/com.sap.sailing.dashboards.gwt/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.dashboards.gwt/META-INF/MANIFEST.MF @@ -25,7 +25,11 @@ Require-Bundle: com.sap.sailing.domain, com.sap.sse.gwt.adminconsole, org.apache.commons.math;bundle-version="2.1.0" Bundle-ActivationPolicy: lazy -Import-Package: org.osgi.framework;version="1.5.0", +Import-Package: com.sap.sse.util, + javax.servlet;version="3.1.0", + javax.servlet.descriptor;version="3.1.0", + javax.servlet.http;version="3.1.0", + org.osgi.framework;version="1.5.0", org.osgi.util.tracker Web-ContextPath: /dashboards Bundle-ClassPath: WEB-INF/classes/, diff --git a/java/com.sap.sailing.dashboards.gwt/WEB-INF/web.xml b/java/com.sap.sailing.dashboards.gwt/WEB-INF/web.xml index 46e9142f142..c6c14b60dbb 100644 --- a/java/com.sap.sailing.dashboards.gwt/WEB-INF/web.xml +++ b/java/com.sap.sailing.dashboards.gwt/WEB-INF/web.xml @@ -18,18 +18,6 @@ - - Rib Dashboard Service - RibDashboardService - com.sap.sailing.dashboards.gwt.server.RibDashboardServiceImpl - - - - RibDashboardService - /service/ribdashboard - - - Sailing Service SailingService @@ -39,6 +27,16 @@ SailingService /service/sailing + + + Dispatch Service + DispatchService + com.sap.sailing.dashboards.gwt.server.DashboardDispatchRPCServletImpl + + + DispatchService + /service/dispatch + diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/DashboardClientFactory.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/DashboardClientFactory.java new file mode 100644 index 00000000000..5475b7f583b --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/DashboardClientFactory.java @@ -0,0 +1,18 @@ +package com.sap.sailing.dashboards.gwt.client; + +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchSystem; +import com.sap.sailing.gwt.ui.client.SailingServiceAsync; +import com.sap.sse.gwt.client.player.Timer; + +/** + * @author Alexander Ries (D062114) + * + */ +public interface DashboardClientFactory{ + + DashboardDispatchSystem getDispatch(); + + SailingServiceAsync getSailingService(); + + Timer getDashboardFiveSecondsTimer(); +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/DashboardClientFactoryImpl.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/DashboardClientFactoryImpl.java new file mode 100644 index 00000000000..9ca74a9fbdf --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/DashboardClientFactoryImpl.java @@ -0,0 +1,49 @@ +package com.sap.sailing.dashboards.gwt.client; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.rpc.ServiceDefTarget; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchSystem; +import com.sap.sailing.dashboards.gwt.shared.dispatch.impl.DashboardDispatchSystemImpl; +import com.sap.sailing.gwt.ui.client.SailingService; +import com.sap.sailing.gwt.ui.client.SailingServiceAsync; +import com.sap.sse.gwt.client.EntryPointHelper; +import com.sap.sse.gwt.client.player.Timer; +import com.sap.sse.gwt.client.player.Timer.PlayModes; + +/** + * @author Alexander Ries (D062114) + * + */ +public class DashboardClientFactoryImpl implements DashboardClientFactory{ + + private final DashboardDispatchSystem dispatch; + private final SailingServiceAsync sailingService; + private final Timer dashboardFiveSecondsTimer; + + private static final int DASHBOARD_RERFRESH_INTERVAL = 5000; + + public DashboardClientFactoryImpl() { + dispatch = new DashboardDispatchSystemImpl(); + sailingService = GWT.create(SailingService.class); + EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService, RemoteServiceMappingConstants.WEB_CONTEXT_PATH, RemoteServiceMappingConstants.sailingServiceRemotePath); + dashboardFiveSecondsTimer = new Timer(PlayModes.Live); + dashboardFiveSecondsTimer.setRefreshInterval(DASHBOARD_RERFRESH_INTERVAL); + + } + + @Override + public DashboardDispatchSystem getDispatch() { + return dispatch; + } + + @Override + public SailingServiceAsync getSailingService() { + return sailingService; + } + + @Override + public Timer getDashboardFiveSecondsTimer() { + return dashboardFiveSecondsTimer; + } + +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RemoteServiceMappingConstants.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RemoteServiceMappingConstants.java index 3e3f281bbc6..154243707d6 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RemoteServiceMappingConstants.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RemoteServiceMappingConstants.java @@ -17,5 +17,5 @@ public interface RemoteServiceMappingConstants { public static final String WEB_CONTEXT_PATH = "dashboards"; public static final String sailingServiceRemotePath = "service/sailing"; - public static final String ribdashboardServiceRemotePath = "service/ribdashboard"; + public static final String ribdashboardDispatchServiceRemotePath = "service/dispatch"; } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardEntryPoint.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardEntryPoint.java index 8b143644190..d1ca55aa36a 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardEntryPoint.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardEntryPoint.java @@ -1,22 +1,15 @@ package com.sap.sailing.dashboards.gwt.client; -import com.google.gwt.core.client.GWT; -import com.google.gwt.user.client.rpc.ServiceDefTarget; import com.google.gwt.user.client.ui.RootLayoutPanel; import com.googlecode.mgwt.ui.client.MGWT; 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.dashboardpanel.DashboardPanel; 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; import com.sap.sse.gwt.client.AbstractEntryPoint; -import com.sap.sse.gwt.client.EntryPointHelper; -import com.sap.sse.gwt.client.player.Timer; -import com.sap.sse.gwt.client.player.Timer.PlayModes; /** * @@ -25,28 +18,14 @@ import com.sap.sse.gwt.client.player.Timer.PlayModes; */ public class RibDashboardEntryPoint extends AbstractEntryPoint { - private static final int DASHBOARD_RERFRESH_INTERVAL = 5000; - @Override public void doOnModuleLoad() { - - SailingServiceAsync sailingService = GWT.create(SailingService.class); - EntryPointHelper.registerASyncService((ServiceDefTarget) sailingService, RemoteServiceMappingConstants.WEB_CONTEXT_PATH, RemoteServiceMappingConstants.sailingServiceRemotePath); - - RibDashboardServiceAsync ribdashboardService = GWT.create(RibDashboardService.class); - EntryPointHelper.registerASyncService((ServiceDefTarget) ribdashboardService, RemoteServiceMappingConstants.WEB_CONTEXT_PATH, RemoteServiceMappingConstants.ribdashboardServiceRemotePath); - - RibDashboardDataRetriever dataRetriever = new RibDashboardDataRetriever(ribdashboardService); - applyMGWTSettings(); - RibDashboardPanel ribDashboardPanel = new RibDashboardPanel(ribdashboardService, sailingService, dataRetriever); - RootLayoutPanel.get().add(ribDashboardPanel); - WindBotDataRetriever windBotDataRetriever = new WindBotDataRetriever(ribdashboardService, sailingService); - windBotDataRetriever.addNumberOfWindBotsChangeListeners(ribDashboardPanel); - Timer dashboardTimer = new Timer(PlayModes.Live); - dashboardTimer.setRefreshInterval(DASHBOARD_RERFRESH_INTERVAL); - dashboardTimer.addTimeListener(windBotDataRetriever); - dashboardTimer.addTimeListener(dataRetriever); + DashboardClientFactory dashboardClientFactory = new DashboardClientFactoryImpl(); + DashboardPanel rootPanel = new DashboardPanel(dashboardClientFactory); + RootLayoutPanel.get().add(rootPanel); + WindBotDataRetriever windBotDataRetriever = new WindBotDataRetriever(dashboardClientFactory); + windBotDataRetriever.addNumberOfWindBotsChangeListeners(rootPanel); } private void applyMGWTSettings() { diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardImageResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardImageResources.java deleted file mode 100644 index 9962fb67cfb..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardImageResources.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * - */ -package com.sap.sailing.dashboards.gwt.client; - -import com.google.gwt.core.shared.GWT; -import com.google.gwt.resources.client.ClientBundle; -import com.google.gwt.resources.client.ImageResource; - -/** - * @author Alexander Ries - * - */ -public interface RibDashboardImageResources extends ClientBundle { - - public static final RibDashboardImageResources INSTANCE = GWT.create(RibDashboardImageResources.class); - - @Source("images/logo_sap.png") - ImageResource logo_sap(); - - @Source("images/logoess.png") - ImageResource logoess(); - - @Source("images/leftarrow.png") - ImageResource left(); - - @Source("images/rightarrow.png") - ImageResource right(); - - @Source("images/leftarrow_disabled.png") - ImageResource leftdisabled(); - - @Source("images/rightarrow_disabled.png") - ImageResource rightdisabled(); - - @Source("images/compass.png") - ImageResource compass(); - - @Source("images/watch.png") - ImageResource watch(); - - @Source("images/settings.png") - ImageResource settings(); - - @Source("images/rotatedevice.png") - ImageResource rotatedevice(); -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardPanel.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardPanel.ui.xml deleted file mode 100644 index 6b88deca4c0..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardPanel.ui.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - -
-
-
-
- -
-
-
-
- -
- - - - - - - - - - - - - -
-
- - - - -
- -
\ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardPanelStyle.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardPanelStyle.java deleted file mode 100644 index 8eb2b7760c4..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardPanelStyle.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client; - -import com.google.gwt.resources.client.CssResource; - -public interface RibDashboardPanelStyle extends CssResource { - String logo(); - String start(); -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardService.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardService.java deleted file mode 100644 index b7dc461ca98..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardService.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client; - -import java.util.List; - -import com.google.gwt.user.client.rpc.RemoteService; -import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO; -import com.sap.sailing.dashboards.gwt.shared.dto.StartlineAdvantagesWithMaxAndAverageDTO; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO; -import com.sap.sailing.domain.common.NoWindException; -import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; -import com.sap.sailing.domain.common.dto.CompetitorDTO; - -public interface RibDashboardService extends RemoteService { - RibDashboardRaceInfoDTO getLiveRaceInfo(String leaderboardName) throws NoWindException; - - RegattaAndRaceIdentifier getIDFromRaceThatTakesWindFixesNow(String leaderboardName); - - List getStartAnalysisListForCompetitorIDAndLeaderboardName(String competitorIdAsString, String leaderboardName); - - List getCompetitorsInLeaderboard(String leaderboardName); - - StartlineAdvantagesWithMaxAndAverageDTO getAdvantagesOnStartline(String leaderboardName); -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardServiceAsync.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardServiceAsync.java deleted file mode 100644 index 11dd9508bcf..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardServiceAsync.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client; - -import java.util.List; - -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO; -import com.sap.sailing.dashboards.gwt.shared.dto.StartlineAdvantagesWithMaxAndAverageDTO; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO; -import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; -import com.sap.sailing.domain.common.dto.CompetitorDTO; - -public interface RibDashboardServiceAsync { - - void getLiveRaceInfo(String leaderboardName, AsyncCallback callback); - - void getStartAnalysisListForCompetitorIDAndLeaderboardName(String competitorIdAsString, String leaderboardName, AsyncCallback> callback); - - void getCompetitorsInLeaderboard(String leaderboardName, AsyncCallback> callback); - - void getAdvantagesOnStartline(String leaderboardName, AsyncCallback callback); - - void getIDFromRaceThatTakesWindFixesNow(String leaderboardName, AsyncCallback callback); - -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetCompetitorInLeaderboardAction.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetCompetitorInLeaderboardAction.java new file mode 100644 index 00000000000..433536bec7e --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetCompetitorInLeaderboardAction.java @@ -0,0 +1,35 @@ +package com.sap.sailing.dashboards.gwt.client.actions; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardAction; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext; +import com.sap.sailing.dashboards.gwt.shared.dto.LeaderboardCompetitorsDTO; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.gwt.dispatch.client.exceptions.DispatchException; +import com.sap.sse.common.impl.MillisecondsTimePoint; + +/** + * @author Alexander Ries (D062114) + * + */ +public class GetCompetitorInLeaderboardAction implements DashboardAction { + + private String leaderboarName; + + @SuppressWarnings("unused") + private GetCompetitorInLeaderboardAction() { + } + + public GetCompetitorInLeaderboardAction(String leaderboardName) { + this.leaderboarName = leaderboardName; + } + + @Override + @GwtIncompatible + public LeaderboardCompetitorsDTO execute(DashboardDispatchContext dashboardDispatchContext) throws DispatchException { + LeaderboardCompetitorsDTO result = new LeaderboardCompetitorsDTO(); + Leaderboard lb = dashboardDispatchContext.getRacingEventService().getLeaderboardByName(this.leaderboarName); + result.setCompetitors(dashboardDispatchContext.getRacingEventService().getBaseDomainFactory().getCompetitorDTOList(lb.getCompetitorsFromBestToWorst(MillisecondsTimePoint.now()))); + return result; + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetIDFromRaceThatIsLiveAction.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetIDFromRaceThatIsLiveAction.java new file mode 100644 index 00000000000..c26ab8c6d0c --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetIDFromRaceThatIsLiveAction.java @@ -0,0 +1,32 @@ +package com.sap.sailing.dashboards.gwt.client.actions; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.dashboards.gwt.shared.dispatch.RequiresLiveRaceAction; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext; +import com.sap.sailing.dashboards.gwt.shared.dto.RaceIdDTO; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.gwt.dispatch.client.exceptions.DispatchException; + +/** + * @author Alexander Ries (D062114) + * + */ +public class GetIDFromRaceThatIsLiveAction extends RequiresLiveRaceAction { + + public GetIDFromRaceThatIsLiveAction() {} + + public GetIDFromRaceThatIsLiveAction(String leaderboardName) { + super(leaderboardName); + } + + @Override + @GwtIncompatible + public RaceIdDTO execute(DashboardDispatchContext dashboardDispatchContext) throws DispatchException { + RaceIdDTO result = new RaceIdDTO(); + TrackedRace liveRace = super.getLiveRace(dashboardDispatchContext); + if (liveRace != null) { + result.setRaceId(liveRace.getRaceIdentifier()); + } + return result; + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetIDFromRaceThatTakesWindFixesNowAction.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetIDFromRaceThatTakesWindFixesNowAction.java index 4405378671b..25491706bb6 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetIDFromRaceThatTakesWindFixesNowAction.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetIDFromRaceThatTakesWindFixesNowAction.java @@ -1,26 +1,47 @@ package com.sap.sailing.dashboards.gwt.client.actions; -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.sap.sailing.dashboards.gwt.client.RibDashboardServiceAsync; -import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; -import com.sap.sse.gwt.client.async.AsyncAction; +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardAction; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext; +import com.sap.sailing.dashboards.gwt.shared.dto.RaceIdDTO; +import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.gwt.dispatch.client.exceptions.DispatchException; +import com.sap.sse.common.impl.MillisecondsTimePoint; /** * @author Alexander Ries (D062114) * */ -public class GetIDFromRaceThatTakesWindFixesNowAction implements AsyncAction { +public class GetIDFromRaceThatTakesWindFixesNowAction implements DashboardAction { - private final RibDashboardServiceAsync ribDashboardService; - private final String leaderboardName; + private String leaderboardName; - public GetIDFromRaceThatTakesWindFixesNowAction(RibDashboardServiceAsync ribDashboardService, String leaderboardName) { - this.ribDashboardService = ribDashboardService; + @SuppressWarnings("unused") + private GetIDFromRaceThatTakesWindFixesNowAction() { + } + + public GetIDFromRaceThatTakesWindFixesNowAction(String leaderboardName) { this.leaderboardName = leaderboardName; } @Override - public void execute(AsyncCallback callback) { - ribDashboardService.getIDFromRaceThatTakesWindFixesNow(leaderboardName, callback); + @GwtIncompatible + public RaceIdDTO execute(DashboardDispatchContext dashboardDispatchContext) throws DispatchException { + RaceIdDTO result = new RaceIdDTO(); + Leaderboard leaderboard = dashboardDispatchContext.getRacingEventService().getLeaderboardByName(this.leaderboardName); + if (leaderboard != null) { + for (RaceColumn column : leaderboard.getRaceColumns()) { + for (Fleet fleet : column.getFleets()) { + TrackedRace race = column.getTrackedRace(fleet); + if (race != null && race.takesWindFixWithTimePoint(MillisecondsTimePoint.now())) { + result.setRaceId(race.getRaceIdentifier()); + } + } + } + } + return result; } } \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetRibDashboardRaceInfoAction.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetRibDashboardRaceInfoAction.java deleted file mode 100644 index 78fda2421be..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetRibDashboardRaceInfoAction.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client.actions; - -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.sap.sailing.dashboards.gwt.client.RibDashboardServiceAsync; -import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO; -import com.sap.sse.gwt.client.async.AsyncAction; - -public class GetRibDashboardRaceInfoAction implements AsyncAction { - - private final RibDashboardServiceAsync ribDashboardService; - private final String leaderboardName; - - public GetRibDashboardRaceInfoAction(RibDashboardServiceAsync ribDashboardService, String leaderboardName) { - this.ribDashboardService = ribDashboardService; - this.leaderboardName = leaderboardName; - } - - @Override - public void execute(AsyncCallback callback) { - ribDashboardService.getLiveRaceInfo(leaderboardName, callback); - } -} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetStartAnalysesAction.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetStartAnalysesAction.java new file mode 100644 index 00000000000..d0446002a28 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetStartAnalysesAction.java @@ -0,0 +1,68 @@ +package com.sap.sailing.dashboards.gwt.client.actions; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.dashboards.gwt.server.util.actions.startanalysis.StartAnalysisCreationController; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardAction; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext; +import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysesDTO; +import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisDTO; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.gwt.dispatch.client.exceptions.DispatchException; + +/** + * @author Alexander Ries (D062114) + * + */ +public class GetStartAnalysesAction implements DashboardAction { + + private String leaderboarName; + private String competitorIdAsString; + + @SuppressWarnings("unused") + private GetStartAnalysesAction() { + } + + public GetStartAnalysesAction(String leaderboardName, String competitorIdAsString) { + this.leaderboarName = leaderboardName; + this.competitorIdAsString = competitorIdAsString; + } + + @Override + @GwtIncompatible + public StartAnalysesDTO execute(DashboardDispatchContext dashboardDispatchContext) throws DispatchException { + StartAnalysesDTO result = new StartAnalysesDTO(); + List startanalyses = new ArrayList(); + if (competitorIdAsString != null && leaderboarName != null) { + try { + Competitor competitor = dashboardDispatchContext.getRacingEventService().getBaseDomainFactory().getCompetitorStore().getExistingCompetitorByIdAsString( + competitorIdAsString); + Leaderboard leaderboard = dashboardDispatchContext.getRacingEventService().getLeaderboardByName(this.leaderboarName); + if (leaderboard != null) { + for (RaceColumn column : leaderboard.getRaceColumns()) { + for (Fleet fleet : column.getFleets()) { + TrackedRace race = column.getTrackedRace(fleet); + if (race != null) { + StartAnalysisDTO startAnalysisDTO = StartAnalysisCreationController.checkStartAnalysisForCompetitorInTrackedRace(dashboardDispatchContext, competitor, race); + if (startAnalysisDTO != null) { + startanalyses.add(startAnalysisDTO); + } + } + } + } + + } + } catch (NullPointerException e) { + // logger.log(Level.INFO, "", e); + } + } + result.setStartAnalyses(startanalyses); + return result; + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetStartlineAdvantageByGeometryAction.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetStartlineAdvantageByGeometryAction.java new file mode 100644 index 00000000000..7b79ef3205d --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetStartlineAdvantageByGeometryAction.java @@ -0,0 +1,48 @@ +package com.sap.sailing.dashboards.gwt.client.actions; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage.StartlineAdvantageByGeometryCalculator; +import com.sap.sailing.dashboards.gwt.shared.StartlineAdvantageType; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext; +import com.sap.sailing.dashboards.gwt.shared.dispatch.RequiresLiveRaceAndCachesMovingAverageAction; +import com.sap.sailing.dashboards.gwt.shared.dto.StartLineAdvantageDTO; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.gwt.dispatch.client.exceptions.DispatchException; + +/** + * @author Alexander Ries (D062114) + * + */ +public class GetStartlineAdvantageByGeometryAction extends RequiresLiveRaceAndCachesMovingAverageAction { + + public GetStartlineAdvantageByGeometryAction() {} + + public GetStartlineAdvantageByGeometryAction(String leaderboardName) { + super(leaderboardName); + } + + @Override + @GwtIncompatible + public StartLineAdvantageDTO execute(DashboardDispatchContext dashboardDispatchContext) throws DispatchException { + StartLineAdvantageDTO result = new StartLineAdvantageDTO(); + Double startlineAdvantageByGeometry = null; + TrackedRace liveRace = super.getLiveRace(dashboardDispatchContext); + if (liveRace != null) { + startlineAdvantageByGeometry = StartlineAdvantageByGeometryCalculator.calculateStartlineAdvantageByGeometry(liveRace); + } + result.startLineAdvatageType = StartlineAdvantageType.GEOMETRIC; + result.startLineAdvantage = startlineAdvantageByGeometry; + Double average = null; + if (startlineAdvantageByGeometry != null) { + super.addValueToMovingAverage(startlineAdvantageByGeometry.doubleValue(), dashboardDispatchContext.getMovingAveragesCache()); + average = dashboardDispatchContext.getMovingAveragesCache().getValueForKey(getKeyForMovingAverage()); + } + result.average = average; + return result; + } + + @Override + protected String getKeyForMovingAverage() { + return super.getLeaderboardName(); + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetStartlineAdvantagesAction.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetStartlineAdvantagesAction.java deleted file mode 100644 index 1cf2be86c81..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetStartlineAdvantagesAction.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client.actions; - -/** - * @author Alexander Ries (D062114) - * - */ - -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.sap.sailing.dashboards.gwt.client.RibDashboardServiceAsync; -import com.sap.sailing.dashboards.gwt.shared.dto.StartlineAdvantagesWithMaxAndAverageDTO; -import com.sap.sse.gwt.client.async.AsyncAction; - -public class GetStartlineAdvantagesAction implements AsyncAction { - - private final RibDashboardServiceAsync ribDashboardService; - private final String leaderboardName; - - public GetStartlineAdvantagesAction(RibDashboardServiceAsync ribDashboardService, String leaderboardName) { - this.ribDashboardService = ribDashboardService; - this.leaderboardName = leaderboardName; - } - - @Override - public void execute(AsyncCallback callback) { - ribDashboardService.getAdvantagesOnStartline(leaderboardName, callback); - }} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetStartlineAdvantagesByWindAction.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetStartlineAdvantagesByWindAction.java new file mode 100644 index 00000000000..4d4d0ee8d67 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/actions/GetStartlineAdvantagesByWindAction.java @@ -0,0 +1,45 @@ +package com.sap.sailing.dashboards.gwt.client.actions; + +/** + * @author Alexander Ries (D062114) + * + */ + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage.StartlineAdvantagesByWindCalculator; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext; +import com.sap.sailing.dashboards.gwt.shared.dispatch.RequiresLiveRaceAndCachesMovingAverageAction; +import com.sap.sailing.dashboards.gwt.shared.dto.StartlineAdvantagesWithMaxAndAverageDTO; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.gwt.dispatch.client.exceptions.DispatchException; +import com.sap.sse.common.impl.MillisecondsTimePoint; + +public class GetStartlineAdvantagesByWindAction extends RequiresLiveRaceAndCachesMovingAverageAction { + + public GetStartlineAdvantagesByWindAction() {} + + public GetStartlineAdvantagesByWindAction(String leaderboardName) { + super(leaderboardName); + } + + @Override + @GwtIncompatible + public StartlineAdvantagesWithMaxAndAverageDTO execute(DashboardDispatchContext dashboardDispatchContext) throws DispatchException { + StartlineAdvantagesWithMaxAndAverageDTO result = new StartlineAdvantagesWithMaxAndAverageDTO(); + TrackedRace liveRace = super.getLiveRace(dashboardDispatchContext); + if (liveRace != null) { + StartlineAdvantagesByWindCalculator startlineAdvantagesByWindCalculator = new StartlineAdvantagesByWindCalculator(dashboardDispatchContext); + result = startlineAdvantagesByWindCalculator.getStartLineAdvantagesAccrossLineFromTrackedRaceAtTimePoint(liveRace, MillisecondsTimePoint.now()); + } + if(result != null && result.maximum != null) { + super.addValueToMovingAverage(result.maximum, dashboardDispatchContext.getMovingAveragesCache()); + result.average = dashboardDispatchContext.getMovingAveragesCache().getValueForKey(getKeyForMovingAverage()); + } + return result; + } + + @Override + protected String getKeyForMovingAverage() { + return super.getLeaderboardName(); + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dashboardpanel/DashboardPanel.gss b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dashboardpanel/DashboardPanel.gss new file mode 100644 index 00000000000..14b3eef2b2f --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dashboardpanel/DashboardPanel.gss @@ -0,0 +1,118 @@ +@require 'theme'; + +.bar { + height: 100%; + margin-top: 20pt; + line-height: 15pt; + vertical-align: middle; + font-size: 15pt; + font-family: DASHBOARD_FONT_FAMILY; + width: 100%; + text-align: center; + font-weight: bold; + overflow: visible; +} + +.page { + position: absolute; + border: none; + border-radius: 0; + left: 0; + right: 0; + top: 0; + bottom: 30pt; + margin: 5pt; +} + +.logo { + position: absolute; + width: 48pt; + height: 23.5pt; + margin-top: 17.5pt; + margin-left: 10pt; + z-index: 1; +} + +.collumn { + position: absolute; + top: 5pt; + bottom: 15pt; + margin: 5pt; +} + +.startanalysiscollumn { + right: 33.3%; + left: 0%; +} + +.collumnthree { + left: 66.8%; + right: 0pt; +} + +.left { + left: 0pt; + right: 50%; +} + +.right { + left: 50%; + right: 0pt; +} + +.startline_advantage_by_wind_container { + position: absolute; + background-color: white; + top: 27%; + right: 0pt; + left: 0pt; + bottom: 0%; +} + +.startline_advantage_by_geometry_container { + position: absolute; + background-color: white; + top: 0%; + right: 0pt; + left: 0pt; + bottom: 73%; + margin-bottom: 10pt; +} + +.windcharthint { + position: absolute; + bottom: 0pt; + height: 15pt; + line-height: 15pt; + margin-top: 0pt; + vertical-align: middle; + font-size: 12pt; + font-family: DASHBOARD_FONT_FAMILY; + width: 100%; + text-align: center; +} + +.windloadinghint { + position: absolute; + background-color: white; + opacity: 0.4; + width: 100%; + height: 100%; + vertical-align: middle; + text-align: center; + z-index: 0; +} + +.windloadinghinttext { + position: absolute; + bottom: 0pt; + height: 15pt; + line-height: 15pt; + margin-top: 0pt; + vertical-align: middle; + font-size: 12pt; + font-family: DASHBOARD_FONT_FAMILY; + width: 100%; + text-align: center; + top: 50%; +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardPanel.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dashboardpanel/DashboardPanel.java similarity index 59% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardPanel.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dashboardpanel/DashboardPanel.java index 6073c35555e..bde0b1d2608 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/RibDashboardPanel.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dashboardpanel/DashboardPanel.java @@ -1,6 +1,7 @@ -package com.sap.sailing.dashboards.gwt.client; +package com.sap.sailing.dashboards.gwt.client.dashboardpanel; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -10,24 +11,26 @@ import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Document; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; -import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTMLPanel; 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.DashboardClientFactory; +import com.sap.sailing.dashboards.gwt.client.actions.GetIDFromRaceThatIsLiveAction; 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.StartLineAdvantageByGeometryComponent; -import com.sap.sailing.dashboards.gwt.client.startlineadvantage.StartlineAdvantagesByWindComponent; -import com.sap.sailing.dashboards.gwt.client.windchart.WindBotComponent; -import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO; +import com.sap.sailing.dashboards.gwt.client.notifications.orientation.WrongDeviceOrientationNotification; +import com.sap.sailing.dashboards.gwt.client.widgets.PollsLiveDataEvery5Seconds; +import com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.StartAnalysisWidget; +import com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.course.StartLineAdvantageByGeometryWidget; +import com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.wind.StartlineAdvantagesByWindWidget; +import com.sap.sailing.dashboards.gwt.client.widgets.windbot.WindBotWidget; +import com.sap.sailing.dashboards.gwt.shared.DashboardURLParameters; +import com.sap.sailing.dashboards.gwt.shared.dto.RaceIdDTO; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; @@ -38,17 +41,12 @@ import com.sap.sailing.gwt.ui.client.StringMessages; * @author Alexander Ries * */ -public class RibDashboardPanel extends Composite implements RibDashboardDataRetrieverListener, - NumberOfWindBotsChangeListener { +public class DashboardPanel extends Composite implements NumberOfWindBotsChangeListener, PollsLiveDataEvery5Seconds { - interface RootUiBinder extends UiBinder { - } + interface RootUiBinder extends UiBinder {} private static RootUiBinder uiBinder = GWT.create(RootUiBinder.class); - @UiField - RibDashboardPanelStyle style; - @UiField LayoutPanel root; @@ -65,7 +63,7 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr HTMLPanel rightwindbotcontainer; @UiField(provided = true) - StartlineAdvantagesByWindComponent startlineAdvantagesByWindComponent; + StartlineAdvantagesByWindWidget startlineAdvantagesByWindComponent; @UiField public DivElement windloadinghintleft; @@ -80,41 +78,43 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr public HTMLPanel windcharthint; @UiField(provided = true) - public StartlineAnalysisComponent startanalysisComponent; + public StartAnalysisWidget startanalysisComponent; @UiField(provided = true) - public StartLineAdvantageByGeometryComponent startlineAdvantageByGeometryComponent; + public StartLineAdvantageByGeometryWidget startlineAdvantageByGeometryComponent; - private List windBotComponents; + private List windBotComponents; private StringMessages stringConstants; - private final String EVENT_ID_PARAMETER = "eventId"; - private static final Logger logger = Logger.getLogger(RibDashboardPanel.class.getName()); + DashboardClientFactory dashboardClientFactory; + private static final Logger logger = Logger.getLogger(DashboardPanel.class.getName()); - public RibDashboardPanel(RibDashboardServiceAsync ribDashboardService, SailingServiceAsync sailingServiceAsync, RibDashboardDataRetriever ribDashboardDataRetriever) { - windBotComponents = new ArrayList(); - ribDashboardDataRetriever.addDataObserver(this); - startanalysisComponent = new StartlineAnalysisComponent(ribDashboardService, sailingServiceAsync); - startlineAdvantagesByWindComponent = new StartlineAdvantagesByWindComponent(ribDashboardService); - startlineAdvantageByGeometryComponent = new StartLineAdvantageByGeometryComponent(ribDashboardDataRetriever); + public DashboardPanel(DashboardClientFactory dashboardClientFactory) { + DashboardPanelResources.INSTANCE.style().ensureInjected(); + this.dashboardClientFactory = dashboardClientFactory; + windBotComponents = new ArrayList(); + startanalysisComponent = new StartAnalysisWidget(this.dashboardClientFactory); + startlineAdvantagesByWindComponent = new StartlineAdvantagesByWindWidget(this.dashboardClientFactory); + startlineAdvantageByGeometryComponent = new StartLineAdvantageByGeometryWidget(this.dashboardClientFactory); stringConstants = StringMessages.INSTANCE; initWidget(uiBinder.createAndBindUi(this)); initLogos(); windcharthint.getElement().setInnerText(stringConstants.dashboardWindChartHint()); windloadinghintleft.setInnerHTML(stringConstants.dashboardWindBotLoadingText()+"
"+stringConstants.dashboardWindBotLoadingMessage()); windloadinghintright.setInnerHTML(stringConstants.dashboardWindBotLoadingText()+"
"+stringConstants.dashboardWindBotLoadingMessage()); - loadAndAddEventLogo(sailingServiceAsync); + loadAndAddEventLogo(dashboardClientFactory.getSailingService()); initAndAddWrongOrientationNotification(); + registerForDashboardFiveSecondsTimer(dashboardClientFactory); } private void initLogos() { Image logo = new Image(); - logo.setResource(RibDashboardImageResources.INSTANCE.logo_sap()); - logo.getElement().addClassName(style.logo()); + logo.setResource(DashboardPanelResources.INSTANCE.logo_sap()); + logo.getElement().addClassName(DashboardPanelResources.INSTANCE.style().logo()); Document.get().getBody().appendChild(logo.getElement()); } private void loadAndAddEventLogo(SailingServiceAsync sailingServiceAsync){ - String eventId = Window.Location.getParameter(EVENT_ID_PARAMETER); + String eventId = DashboardURLParameters.EVENT_ID.getValue(); if (eventId != null) { EventLogo eventLogo = EventLogo.getEventLogoFromEventId(sailingServiceAsync, eventId); if (eventLogo != null) { @@ -136,12 +136,12 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr windBotComponents.clear(); for (String windBotID : windBotIDs) { if (windBotAddedCounterTOConsiderForPanels == 0) { - WindBotComponent leftwindBotComponent = new WindBotComponent(windBotID); + WindBotWidget leftwindBotComponent = new WindBotWidget(windBotID); leftwindbotcontainer.add(leftwindBotComponent); windBotComponents.add(leftwindBotComponent); windloadinghintleft.getStyle().setOpacity(0.0); } else if (windBotAddedCounterTOConsiderForPanels == 1) { - WindBotComponent rightwindBotComponent = new WindBotComponent(windBotID); + WindBotWidget rightwindBotComponent = new WindBotWidget(windBotID); rightwindbotcontainer.add(rightwindBotComponent); windBotComponents.add(rightwindBotComponent); windloadinghintright.getStyle().setOpacity(0.0); @@ -157,7 +157,7 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr } private void addWindBotComponentsAsDataRetrieverListener(WindBotDataRetrieverProvider windBotDataRetrieverProvider) { - for (WindBotComponent windBotComponent : windBotComponents) { + for (WindBotWidget windBotComponent : windBotComponents) { logger.log(Level.INFO, "Registering WindBotDataRetrieverListener"); windBotDataRetrieverProvider.addWindBotDataRetrieverListener(windBotComponent); } @@ -165,19 +165,47 @@ public class RibDashboardPanel extends Composite implements RibDashboardDataRetr private void removeWindBotComponentsAsDataRetrieverListener( WindBotDataRetrieverProvider windBotDataRetrieverProvider) { - for (WindBotComponent windBotComponent : windBotComponents) { + for (WindBotWidget windBotComponent : windBotComponents) { windBotDataRetrieverProvider.removeWindBotDataRetrieverListener(windBotComponent); } } + private void setHeaderText(String raceName) { + this.header.getElement().setInnerText(raceName); + } + @Override - public void updateUIWithNewLiveRaceInfo(RibDashboardRaceInfoDTO liveRaceInfoDTO) { - if (liveRaceInfoDTO != null && liveRaceInfoDTO.idOfLastTrackedRace != null) { - logger.log(Level.INFO, "Updating UI with RibDashboardRaceInfoDTO race name"); - this.header.getElement().setInnerText(liveRaceInfoDTO.idOfLastTrackedRace.getRaceName()); + public void timeChanged(Date newTime, Date oldTime) { + String leaderboardNameParameterValue = DashboardURLParameters.LEADERBOARD_NAME.getValue(); + if (leaderboardNameParameterValue != null) { + dashboardClientFactory.getDispatch().execute( + new GetIDFromRaceThatIsLiveAction(leaderboardNameParameterValue), new AsyncCallback() { + + @Override + public void onSuccess(RaceIdDTO result) { + if (result != null && result.getRaceId() != null) { + logger.log(Level.INFO, "Updating UI with live race id"); + setHeaderText(result.getRaceId().getRaceName()); + } else { + logger.log(Level.INFO, "Received null for live race id"); + } + } + + @Override + public void onFailure(Throwable caught) { + logger.log(Level.INFO, "Failed to received live race id" + caught.getMessage()); + } + }); } } + @Override + public void registerForDashboardFiveSecondsTimer(DashboardClientFactory dashboardClientFactory) { + if (dashboardClientFactory != null) { + dashboardClientFactory.getDashboardFiveSecondsTimer().addTimeListener(this); + } + } + @Override public void numberOfWindBotsReceivedChanged(List windBotIDs, WindBotDataRetrieverProvider windBotDataRetrieverProvider) { diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dashboardpanel/DashboardPanel.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dashboardpanel/DashboardPanel.ui.xml new file mode 100644 index 00000000000..9016ead477b --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dashboardpanel/DashboardPanel.ui.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+
+ +
+ + + + + + + + + + + + + +
+
+ + + + +
+ +
\ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dashboardpanel/DashboardPanelResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dashboardpanel/DashboardPanelResources.java new file mode 100644 index 00000000000..e3b7a8dddc4 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dashboardpanel/DashboardPanelResources.java @@ -0,0 +1,40 @@ +package com.sap.sailing.dashboards.gwt.client.dashboardpanel; + +/** + * @author Alexander Ries (D062114) + * + */ +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; +import com.google.gwt.resources.client.ImageResource; + +public interface DashboardPanelResources extends ClientBundle { + + public static final DashboardPanelResources INSTANCE = GWT.create(DashboardPanelResources.class); + + @Source("com/sap/sailing/dashboards/gwt/client/images/logo_sap.png") + ImageResource logo_sap(); + + @Source("com/sap/sailing/dashboards/gwt/client/images/settings.png") + ImageResource settings(); + + @Source({"com/sap/sailing/dashboards/gwt/client/theme/theme.gss", "DashboardPanel.gss"}) + DashboardGSS style(); + + public interface DashboardGSS extends CssResource { + String bar(); + String page(); + String collumn(); + String startanalysiscollumn(); + String collumnthree(); + String logo(); + String right(); + String left(); + String startline_advantage_by_wind_container(); + String startline_advantage_by_geometry_container(); + String windcharthint(); + String windloadinghint(); + String windloadinghinttext(); + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dataretriever/RibDashboardDataRetriever.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dataretriever/RibDashboardDataRetriever.java deleted file mode 100644 index fe206005f0a..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dataretriever/RibDashboardDataRetriever.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client.dataretriever; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -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.sse.gwt.client.async.AsyncActionsExecutor; -import com.sap.sse.gwt.client.player.TimeListener; - -/** - * Class calls method {@link #requestLiveRaceInfoFromRibDashboadService()) to retrieve new - * data for the dashboard widgets on a regularly basis. - * The request interval is 5 seconds. - * - * @author Alexander Ries - * - */ -public class RibDashboardDataRetriever implements TimeListener { - - private String leaderboardName; - private ArrayList dataRetrieverListener; - - private AsyncActionsExecutor asyncActionsExecutor; - - private final RibDashboardServiceAsync ribDashboardService; - - private final Object MUTEX; - - private static final String PARAM_LEADERBOARD_NAME = "leaderboardName"; - private static final Logger logger = Logger.getLogger(RibDashboardDataRetriever.class.getName()); - - public RibDashboardDataRetriever(RibDashboardServiceAsync ribDashboardService) { - initNonFinalMemberVariablesWithNoArgumentConstructor(); - MUTEX = new Object(); - this.ribDashboardService = ribDashboardService; - this.leaderboardName = Window.Location.getParameter(PARAM_LEADERBOARD_NAME); - asyncActionsExecutor = new AsyncActionsExecutor(); - } - - private void initNonFinalMemberVariablesWithNoArgumentConstructor() { - dataRetrieverListener = new ArrayList(); - } - - private void loadLiveRaceInfoFromRibDashboadService() { - - GetRibDashboardRaceInfoAction getRibDashboardRaceInfoAction = new GetRibDashboardRaceInfoAction(ribDashboardService, leaderboardName); - logger.log(Level.INFO, "Executing GetRibDashboardRaceInfoAction"); - asyncActionsExecutor.execute(getRibDashboardRaceInfoAction, new AsyncCallback() { - @Override - public void onSuccess(RibDashboardRaceInfoDTO result) { - logger.log(Level.INFO, "Received RibDashboardRaceInfoDTO"); - if (result != null) { - switch (result.responseMessage) { - case RACE_LIVE: - logger.log(Level.INFO, "RibDashboardRaceInfoDTO.responseMessage is RACE_LIVE"); - if (result.idOfLastTrackedRace != null) { - logger.log(Level.INFO, "RibDashboardRaceInfoDTO idOfLastTrackedRace is "+result.idOfLastTrackedRace); - } else { - logger.log(Level.INFO, "RibDashboardRaceInfoDTO.idOfLastTrackedRace is null"); - } - notifyDataObservers(result); - break; - case NO_RACE_LIVE: - logger.log(Level.INFO, "RibDashboardRaceInfoDTO.responseMessage is NO_RACE_LIVE"); - break; - default: - logger.log(Level.INFO, "RibDashboardRaceInfoDTO.responseMessage is null"); - break; - } - } else { - logger.log(Level.INFO, "RibDashboardRaceInfoDTO is null"); - } - } - - @Override - public void onFailure(Throwable caught) { - logger.log(Level.INFO, "Failed to received RibDashboardRaceInfoDTO, "+caught.getMessage()); - } - }); - } - - public void addDataObserver(RibDashboardDataRetrieverListener o) { - synchronized (MUTEX) { - if (o != null) { - dataRetrieverListener.add(o); - } - } - } - - public void removeDataObserver(RibDashboardDataRetrieverListener o) { - synchronized (MUTEX) { - this.dataRetrieverListener.remove(o); - } - } - - public void notifyDataObservers(RibDashboardRaceInfoDTO liveRaceInfoDTO) { - logger.log(Level.INFO, "Notifing RibDashboardDataRetrieverListener about new RibDashboardRaceInfoDTO"); - List dataObserverCopy; - synchronized (MUTEX) { - dataObserverCopy = new ArrayList(dataRetrieverListener); - } - for (RibDashboardDataRetrieverListener o : dataObserverCopy) { - o.updateUIWithNewLiveRaceInfo(liveRaceInfoDTO); - } - } - - @Override - public void timeChanged(Date newTime, Date oldTime) { - loadLiveRaceInfoFromRibDashboadService(); - } -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dataretriever/RibDashboardDataRetrieverListener.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dataretriever/RibDashboardDataRetrieverListener.java deleted file mode 100644 index ee2e95944c1..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dataretriever/RibDashboardDataRetrieverListener.java +++ /dev/null @@ -1,16 +0,0 @@ -/** - * - */ -package com.sap.sailing.dashboards.gwt.client.dataretriever; - -import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO; - -/** - * - * @author Alexander Ries - * - */ -public interface RibDashboardDataRetrieverListener { - - public void updateUIWithNewLiveRaceInfo(RibDashboardRaceInfoDTO liveRaceInfoDTO); -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dataretriever/WindBotDataRetriever.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dataretriever/WindBotDataRetriever.java index 6f69bbca8c7..440951f64b8 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dataretriever/WindBotDataRetriever.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/dataretriever/WindBotDataRetriever.java @@ -8,49 +8,46 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; -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.DashboardClientFactory; import com.sap.sailing.dashboards.gwt.client.actions.GetIDFromRaceThatTakesWindFixesNowAction; +import com.sap.sailing.dashboards.gwt.client.widgets.PollsLiveDataEvery5Seconds; +import com.sap.sailing.dashboards.gwt.shared.DashboardURLParameters; +import com.sap.sailing.dashboards.gwt.shared.dto.RaceIdDTO; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.WindSource; import com.sap.sailing.domain.common.WindSourceType; import com.sap.sailing.gwt.ui.actions.GetWindInfoAction; -import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO; import com.sap.sse.gwt.client.async.AsyncActionsExecutor; -import com.sap.sse.gwt.client.player.TimeListener; -public class WindBotDataRetriever implements TimeListener, WindBotDataRetrieverProvider { +public class WindBotDataRetriever implements PollsLiveDataEvery5Seconds, WindBotDataRetrieverProvider { private AsyncActionsExecutor asyncActionsExecutor; - private final RibDashboardServiceAsync ribDashboardService; - private final SailingServiceAsync sailingService; private List numberOfWindBotsChangeListeners; private List windBotDataRetrieverListeners; private List windBotIDsInLiveRace; - private String leaderboardName; private final Set 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 static final String PARAM_LEADERBOARD_NAME = "leaderboardName"; private boolean didInitialLoading; + private DashboardClientFactory dashboardClientFactory; + private static final Logger logger = Logger.getLogger(WindBotDataRetriever.class.getName()); - public WindBotDataRetriever(RibDashboardServiceAsync ribDashboardService, SailingServiceAsync sailingService) { - this.ribDashboardService = ribDashboardService; - this.sailingService = sailingService; + public WindBotDataRetriever(DashboardClientFactory dashboardClientFactory) { + this.dashboardClientFactory = dashboardClientFactory; didInitialLoading = false; asyncActionsExecutor = new AsyncActionsExecutor(); numberOfWindBotsChangeListeners = new ArrayList(); windBotDataRetrieverListeners = new ArrayList(); windBotIDsInLiveRace = new ArrayList(); windSourceTypeNames = new HashSet<>(); - this.leaderboardName = Window.Location.getParameter(PARAM_LEADERBOARD_NAME); windSourceTypeNames.add(WindSourceType.EXPEDITION.name()); + registerForDashboardFiveSecondsTimer(dashboardClientFactory); } private void loadWindBotData(Date from, Date to, RegattaAndRaceIdentifier selectedRaceIdentifier) { @@ -59,7 +56,7 @@ public class WindBotDataRetriever implements TimeListener, WindBotDataRetrieverP from = new Date(from.getTime()-ONE_HOUR_IN_MILLISECONDS); } logger.log(Level.INFO, "Executing GetWindInfoAction with from "+from+" and to "+to); - GetWindInfoAction getWindInfoAction = new GetWindInfoAction(sailingService, selectedRaceIdentifier, from, to, + GetWindInfoAction getWindInfoAction = new GetWindInfoAction(dashboardClientFactory.getSailingService(), selectedRaceIdentifier, from, to, WIND_CHART_RESOLUTION_IN_MILLISECONDS, windSourceTypeNames, /* * onlyUpToNewestEvent==true because we don't want to * overshoot the evidence so far @@ -146,26 +143,38 @@ public class WindBotDataRetriever implements TimeListener, WindBotDataRetrieverP public void timeChanged(Date newTime, Date oldTime) { final Date finalNewTime = newTime; final Date finaloldTime = oldTime; - GetIDFromRaceThatTakesWindFixesNowAction getIDFromRaceThatTakesWindFixesNowAction = new GetIDFromRaceThatTakesWindFixesNowAction(ribDashboardService, leaderboardName); logger.log(Level.INFO, "Executing GetIDFromRaceThatTakesWindFixesNowAction"); - asyncActionsExecutor.execute(getIDFromRaceThatTakesWindFixesNowAction, new AsyncCallback() { - @Override - public void onSuccess(RegattaAndRaceIdentifier result) { - logger.log(Level.INFO, "Received RegattaAndRaceIdentifier from race that takes wind fixes now"); - if(result != null) { - loadWindBotData(finaloldTime, finalNewTime, result); - } else { - notifyListenersAboutNumberOfWindBotsReceivedIsZero(); - logger.log(Level.INFO, "Can´t load wind data because RegattaAndRaceIdentifier for race which takes wind is null"); - } - } + dashboardClientFactory.getDispatch().execute( + new GetIDFromRaceThatTakesWindFixesNowAction(DashboardURLParameters.LEADERBOARD_NAME.getValue()), + new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - notifyListenersAboutNumberOfWindBotsReceivedIsZero(); - logger.log(Level.INFO, " Failed to received RegattaAndRaceIdentifier from race that takes wind fixes now"); - logger.log(Level.INFO, caught.getMessage()); - } - }); + @Override + public void onSuccess(RaceIdDTO result) { + if (result != null) { + RegattaAndRaceIdentifier raceId = result.getRaceId(); + if (raceId != null) { + logger.log(Level.INFO, "Received RegattaAndRaceIdentifier from race that takes wind fixes now"); + loadWindBotData(finaloldTime, finalNewTime, raceId); + } else { + notifyListenersAboutNumberOfWindBotsReceivedIsZero(); + logger.log(Level.INFO, "Can´t load wind data because RegattaAndRaceIdentifier for race which takes wind is null"); + } + } + } + + @Override + public void onFailure(Throwable caught) { + notifyListenersAboutNumberOfWindBotsReceivedIsZero(); + logger.log(Level.INFO, "Failed to received RegattaAndRaceIdentifier from race that takes wind fixes now"); + logger.log(Level.INFO, caught.getMessage()); + } + }); + } + + @Override + public void registerForDashboardFiveSecondsTimer(DashboardClientFactory dashboardClientFactory) { + if (dashboardClientFactory != null) { + dashboardClientFactory.getDashboardFiveSecondsTimer().addTimeListener(this); + } } } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/eventlogo/EventLogo.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/eventlogo/EventLogo.java index e9fe51f6920..bf051376afb 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/eventlogo/EventLogo.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/eventlogo/EventLogo.java @@ -5,6 +5,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import com.google.gwt.dom.client.Style.Visibility; +import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Image; @@ -33,7 +34,7 @@ public class EventLogo extends Image { if (event != null) { final ImageDTO logo = event.getLogoImage(); if (logo != null) { - eventLogo.getElement().setAttribute("src", logo.getSourceRef()); + eventLogo.getElement().setAttribute("src", UriUtils.fromString(logo.getSourceRef()).asString()); } else { eventLogo.getElement().getStyle().setVisibility(Visibility.HIDDEN); } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/Notifications.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/Notifications.css deleted file mode 100644 index c8b15068faa..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/Notifications.css +++ /dev/null @@ -1,100 +0,0 @@ -@CHARSET "UTF-8"; - -.bottomnotification { - position: absolute !important; - opacity: 0.9; - background-color: #F0AB00; - height: 0pt; - line-height: 0pt; - width: 100%; - bottom: 0pt; - text-align: center; - font-size: 15pt; - line-height: 30pt; - color: black; - font-family: 'Open Sans', Arial, Verdana, sans-serif; - z-index: 2; -} - -.bottomnotification_shown { - -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, 2.650); - -moz-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 2.650); - -o-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 2.650); - transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 2.650); - /* custom */ - height: 30pt; - line-height: 30pt; -} - -.bottomnotification_hidden { - -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.650); - -moz-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 1.650); - -o-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 1.650); - transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 1.650); - /* custom */ - height: 0pt; - line-height: 0pt; -} - -.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: 'Open Sans', Arial, Verdana, sans-serif; -} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/NotificationsResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/NotificationsResources.java deleted file mode 100644 index 2e8700466d3..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/NotificationsResources.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client.notifications; - -import com.google.gwt.resources.client.ClientBundle; -import com.google.gwt.resources.client.CssResource; - -/** - * @author Alexander Ries (D062114) - * - */ -public interface NotificationsResources extends ClientBundle { - - @Source("Notifications.css") - NotificationsStyle notificationsStyle(); - - public interface NotificationsStyle extends CssResource { - public String bottomnotification(); - public String bottomnotification_shown(); - public String bottomnotification_hidden(); - public String wrongorientationnotification(); - public String wrongorientationnotification_shown(); - public String wrongorientationnotification_hidden(); - public String wrongorientationnotification_logo(); - public String wrongorientationnotification_text(); - } -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotification.gss b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotification.gss new file mode 100644 index 00000000000..627f472867f --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotification.gss @@ -0,0 +1,34 @@ +@require 'theme'; + +.notification { + position: absolute !important; + opacity: 0.9; + background-color: #F0AB00; + height: 0pt; + width: 100%; + bottom: 0pt; + text-align: center; + font-size: 15pt; + line-height: 30pt; + color: black; + font-family: DASHBOARD_FONT_FAMILY; + z-index: 2; +} + +.shown { + -webkit-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 2.650); + -moz-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 2.650); + -o-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 2.650); + transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 2.650); + height: 30pt; + line-height: 30pt; +} + +.hidden { + -webkit-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 1.650); + -moz-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 1.650); + -o-transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 1.650); + transition: all 700ms cubic-bezier(0.480, -0.035, 0.000, 1.650); + height: 0pt; + line-height: 0pt; +} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/BottomNotification.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotification.java similarity index 79% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/BottomNotification.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotification.java index 815a157afd0..3c301fa1d11 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/BottomNotification.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotification.java @@ -1,9 +1,8 @@ -package com.sap.sailing.dashboards.gwt.client.notifications; +package com.sap.sailing.dashboards.gwt.client.notifications.bottom; import java.util.ArrayList; import java.util.List; -import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.Timer; @@ -22,11 +21,9 @@ public class BottomNotification extends FocusPanel { private Timer timer; private List bottomNotificationClickListeners; - private static NotificationsResources resources = GWT.create(NotificationsResources.class); - public BottomNotification() { - resources.notificationsStyle().ensureInjected(); - this.addStyleName(resources.notificationsStyle().bottomnotification()); + BottomNotificationResources.INSTANCE.gss().ensureInjected(); + this.addStyleName(BottomNotificationResources.INSTANCE.gss().notification()); this.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { @@ -42,8 +39,8 @@ public class BottomNotification extends FocusPanel { public void show(BottomNotificationType bottomNotificationType) { if (shown == false) { - this.removeStyleName(resources.notificationsStyle().bottomnotification_hidden()); - this.addStyleName(resources.notificationsStyle().bottomnotification_shown()); + this.removeStyleName(BottomNotificationResources.INSTANCE.gss().hidden()); + this.addStyleName(BottomNotificationResources.INSTANCE.gss().shown()); this.getElement().setInnerHTML(bottomNotificationType.getMessage()); this.getElement().getStyle().setBackgroundColor(bottomNotificationType.getBackgroundColorAsHex()); this.getElement().getStyle().setColor(bottomNotificationType.getTextColorAsHex()); @@ -61,8 +58,8 @@ public class BottomNotification extends FocusPanel { if (timer != null) { timer.cancel(); } - this.removeStyleName(resources.notificationsStyle().bottomnotification_shown()); - this.addStyleName(resources.notificationsStyle().bottomnotification_hidden()); + this.removeStyleName(BottomNotificationResources.INSTANCE.gss().shown()); + this.addStyleName(BottomNotificationResources.INSTANCE.gss().hidden()); this.getElement().setInnerHTML(""); shown = false; } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/BottomNotificationClickListener.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotificationClickListener.java similarity index 60% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/BottomNotificationClickListener.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotificationClickListener.java index bc63fd8d55b..772207ed02d 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/BottomNotificationClickListener.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotificationClickListener.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.notifications; +package com.sap.sailing.dashboards.gwt.client.notifications.bottom; public interface BottomNotificationClickListener { diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotificationResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotificationResources.java new file mode 100644 index 00000000000..df2040f1687 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotificationResources.java @@ -0,0 +1,23 @@ +package com.sap.sailing.dashboards.gwt.client.notifications.bottom; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; + +/** + * @author Alexander Ries (D062114) + * + */ +public interface BottomNotificationResources extends ClientBundle{ + + public static final BottomNotificationResources INSTANCE = GWT.create(BottomNotificationResources.class); + + @Source({"com/sap/sailing/dashboards/gwt/client/theme/theme.gss", "BottomNotification.gss"}) + NotificationsGSS gss(); + + public interface NotificationsGSS extends CssResource { + public String notification(); + public String shown(); + public String hidden(); + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/BottomNotificationType.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotificationType.java similarity index 94% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/BottomNotificationType.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotificationType.java index fe6bc5c31df..dd316175f34 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/BottomNotificationType.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/bottom/BottomNotificationType.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.notifications; +package com.sap.sailing.dashboards.gwt.client.notifications.bottom; import com.sap.sailing.gwt.ui.client.StringMessages; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/orientation/WrongDeviceOrientationNotification.gss b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/orientation/WrongDeviceOrientationNotification.gss new file mode 100644 index 00000000000..948368c90ee --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/orientation/WrongDeviceOrientationNotification.gss @@ -0,0 +1,56 @@ +@require 'theme'; + +.notification { + position: absolute !important; + top: 50%; + right: 50%; + background-color: white; + z-index: 2; +} + +.shown { + width: 200px; + height: 200px; + margin-right: -100px; + margin-top: -100px; + border-radius: 100px; + -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; +} + +.hidden { + width: 0px; + height: 0px; + marin-right: 0px; + margin-top: 0px; + border-radius: 0px; + overflow: hidden; + -webkit-transition: all 300ms; + -moz-transition: all 300ms; + -o-transition: all 300ms; + transition: all 300ms; + opacity: 0.0; +} + +.logo { + max-width: 40%; + max-height: 40%; + margin: 30%; + margin-top: 23% +} + +.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: DASHBOARD_FONT_FAMILY; +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/WrongDeviceOrientationNotification.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/orientation/WrongDeviceOrientationNotification.java similarity index 58% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/WrongDeviceOrientationNotification.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/orientation/WrongDeviceOrientationNotification.java index 1c0ad96d9fb..6ae4e7f05d4 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/WrongDeviceOrientationNotification.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/orientation/WrongDeviceOrientationNotification.java @@ -1,11 +1,9 @@ -package com.sap.sailing.dashboards.gwt.client.notifications; +package com.sap.sailing.dashboards.gwt.client.notifications.orientation; -import com.google.gwt.core.client.GWT; 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; @@ -16,21 +14,19 @@ public class WrongDeviceOrientationNotification extends AbsolutePanel implements private Label rotateDeviceLabel; - private static NotificationsResources resources = GWT.create(NotificationsResources.class); - public WrongDeviceOrientationNotification() { super(); - resources.notificationsStyle().ensureInjected(); - this.addStyleName(resources.notificationsStyle().wrongorientationnotification()); - this.addStyleName(resources.notificationsStyle().wrongorientationnotification_hidden()); + WrongDeviceOrientationNotificationResources.INSTANCE.gss().ensureInjected(); + this.addStyleName(WrongDeviceOrientationNotificationResources.INSTANCE.gss().notification()); + this.addStyleName(WrongDeviceOrientationNotificationResources.INSTANCE.gss().hidden()); Image rotateDeviceIcon = new Image(); - rotateDeviceIcon.setResource(RibDashboardImageResources.INSTANCE.rotatedevice()); - rotateDeviceIcon.getElement().addClassName(resources.notificationsStyle().wrongorientationnotification_logo()); + rotateDeviceIcon.setResource(WrongDeviceOrientationNotificationResources.INSTANCE.rotatedevice()); + rotateDeviceIcon.getElement().addClassName(WrongDeviceOrientationNotificationResources.INSTANCE.gss().logo()); add(rotateDeviceIcon); rotateDeviceLabel = new Label(); - rotateDeviceLabel.getElement().addClassName(resources.notificationsStyle().wrongorientationnotification_text()); + rotateDeviceLabel.getElement().addClassName(WrongDeviceOrientationNotificationResources.INSTANCE.gss().text()); rotateDeviceLabel.setText("Rotate Device"); add(rotateDeviceLabel); @@ -39,14 +35,14 @@ public class WrongDeviceOrientationNotification extends AbsolutePanel implements } public void show() { - this.removeStyleName(resources.notificationsStyle().wrongorientationnotification_hidden()); - this.addStyleName(resources.notificationsStyle().wrongorientationnotification_shown()); + this.removeStyleName(WrongDeviceOrientationNotificationResources.INSTANCE.gss().hidden()); + this.addStyleName(WrongDeviceOrientationNotificationResources.INSTANCE.gss().shown()); BlurEffect.getInstance().addToView(RootLayoutPanel.get()); } public void hide() { - this.removeStyleName(resources.notificationsStyle().wrongorientationnotification_shown()); - this.addStyleName(resources.notificationsStyle().wrongorientationnotification_hidden()); + this.removeStyleName(WrongDeviceOrientationNotificationResources.INSTANCE.gss().shown()); + this.addStyleName(WrongDeviceOrientationNotificationResources.INSTANCE.gss().hidden()); BlurEffect.getInstance().removeFromView(RootLayoutPanel.get()); } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/orientation/WrongDeviceOrientationNotificationResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/orientation/WrongDeviceOrientationNotificationResources.java new file mode 100644 index 00000000000..43b88ebcfed --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/notifications/orientation/WrongDeviceOrientationNotificationResources.java @@ -0,0 +1,29 @@ +package com.sap.sailing.dashboards.gwt.client.notifications.orientation; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; +import com.google.gwt.resources.client.ImageResource; + +/** + * @author Alexander Ries (D062114) + * + */ +public interface WrongDeviceOrientationNotificationResources extends ClientBundle { + + public static final WrongDeviceOrientationNotificationResources INSTANCE = GWT.create(WrongDeviceOrientationNotificationResources.class); + + @Source("com/sap/sailing/dashboards/gwt/client/images/rotatedevice.png") + ImageResource rotatedevice(); + + @Source({ "com/sap/sailing/dashboards/gwt/client/theme/theme.gss", "WrongDeviceOrientationNotification.gss"}) + WrongDeviceNotificationGSS gss(); + + public interface WrongDeviceNotificationGSS extends CssResource { + public String notification(); + public String shown(); + public String hidden(); + public String logo(); + public String text(); + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/PopupWithMessageAndImage.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/PopupWithMessageAndImage.css index a84dd94f1bf..ba08372c605 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/PopupWithMessageAndImage.css +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/PopupWithMessageAndImage.css @@ -61,7 +61,7 @@ padding: 0px; margin-top: 5pt; margin-left: 0px; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; } .popup_button:active { @@ -77,7 +77,7 @@ font-weight: bold; font-size: 15px; color: grey; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; } .blurred { diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorSelectionPopup.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorSelectionPopup.css index a2ba055f0f5..665596c0f8d 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorSelectionPopup.css +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorSelectionPopup.css @@ -1,5 +1,13 @@ @CHARSET "UTF-8"; +.competitorselectionbackground { + position: absolute; + background-color: rgba(0, 0, 0, 0.6); + width: 100%; + height: 100%; + z-index: 1; +} + .competitorselectionpopup { position: absolute; left: 50%; @@ -8,7 +16,7 @@ height: 200pt; margin-top: -600pt; margin-left: -100pt; - background-color: white; + background-color: rgba(255, 255, 255, 1); border-radius: 0px; z-index: 2; } @@ -23,7 +31,7 @@ vertical-align: middle; text-align: center; font-weight: bold; - text-shadow: 0 1px 1px rgba(255, 255, 255, .7); + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.7); width: 100%; z-index: 3; } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorSelectionPopup.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorSelectionPopup.java index 0adc18b350c..a41d2825551 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorSelectionPopup.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorSelectionPopup.java @@ -15,24 +15,27 @@ 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.RootLayoutPanel; -import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.VerticalPanel; 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 { interface CompetitorSelectionPopupStyle extends CssResource { String popupshow(); - String popuphide(); - String buttonshow(); } @UiField CompetitorSelectionPopupStyle style; + @UiField + HTMLPanel competitorselectionbackground; + + @UiField + VerticalPanel competitorselectionpopup; + @UiField HTMLPanel header; @@ -61,19 +64,17 @@ public class CompetitorSelectionPopup extends Composite implements HasWidgets, C public void show(List competitorList) { competitortable.setTableContent(competitorList); - RootPanel.get().add(this); + RootLayoutPanel.get().add(this); this.button.setText("OK"); - this.getElement().addClassName(style.popupshow()); - this.getElement().removeClassName(style.popuphide()); - BlurEffect.getInstance().addToView(RootLayoutPanel.get()); + competitorselectionpopup.addStyleName(style.popupshow()); + competitorselectionpopup.removeStyleName(style.popuphide()); isVisible = true; } public void hide() { - this.getElement().addClassName(style.popuphide()); - this.getElement().removeClassName(style.popupshow()); - BlurEffect.getInstance().removeFromView(RootLayoutPanel.get()); - RootPanel.get().remove(this); + competitorselectionpopup.addStyleName(style.popuphide()); + competitorselectionpopup.removeStyleName(style.popupshow()); + RootLayoutPanel.get().remove(this); isVisible = false; } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorSelectionPopup.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorSelectionPopup.ui.xml index bb2812d51ed..9c762ce1e0e 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorSelectionPopup.ui.xml +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorSelectionPopup.ui.xml @@ -1,22 +1,25 @@ - - - Select your Team - - - - - - - + + + Select your Team + + + + + + + + \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorTableStyleResource.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorTableStyleResource.java index 25c0d800909..e9cb0af6c7b 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorTableStyleResource.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/CompetitorTableStyleResource.java @@ -3,7 +3,8 @@ package com.sap.sailing.dashboards.gwt.client.popups.competitorselection; import com.google.gwt.user.cellview.client.CellTable; public interface CompetitorTableStyleResource extends CellTable.Resources { - @Source({ CellTable.Style.DEFAULT_CSS, "CompetitorTableStyle.css"}) + + @Source({CellTable.Style.DEFAULT_CSS, "CompetitorTableStyle.css"}) TableStyle cellTableStyle(); diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/SettingsButtonWithSelectionIndicationLabel.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/SettingsButtonWithSelectionIndicationLabel.java index 3cf3294ccae..05a92598d1c 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/SettingsButtonWithSelectionIndicationLabel.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/popups/competitorselection/SettingsButtonWithSelectionIndicationLabel.java @@ -10,7 +10,7 @@ import com.google.gwt.user.client.ui.FocusPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.dashboards.gwt.client.RibDashboardImageResources; +import com.sap.sailing.dashboards.gwt.client.dashboardpanel.DashboardPanelResources; public class SettingsButtonWithSelectionIndicationLabel extends Composite { @@ -38,7 +38,7 @@ public class SettingsButtonWithSelectionIndicationLabel extends Composite { public SettingsButtonWithSelectionIndicationLabel() { initWidget(uiBinder.createAndBindUi(this)); - settingsButtonImage.setResource(RibDashboardImageResources.INSTANCE.settings()); + settingsButtonImage.setResource(DashboardPanelResources.INSTANCE.settings()); } public void addClickHandlerToSettingsButton(ClickHandler clickHandler){ diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/resources/Colors.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/resources/Colors.java deleted file mode 100644 index d6fa0e42285..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/resources/Colors.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client.resources; - -/** - * @author Alexander Ries (D062114) - * - */ -public class Colors { - /* -> App colors -- */ - public static final String C_PRIMARY = "#000000"; - public static final String C_SECONDARY = "#000000"; - /* -> Default colors -- */ - public static final String C_BACKGROUND = "#000000"; - public static final String C_TEXT = "#000000"; - public static final String C_TEXT_LIGHT = "#000000"; -} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/resources/DashboardResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/resources/DashboardResources.java deleted file mode 100644 index fb1a18942ff..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/resources/DashboardResources.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client.resources; - -/** - * @author Alexander Ries (D062114) - * - */ -import com.google.gwt.resources.client.ClientBundle; -import com.google.gwt.resources.client.CssResource; - -public interface DashboardResources extends ClientBundle { - - interface Style extends CssResource { - // Your classes here - } - - // We only need to source the theme file - @Source({"colors.gss", "Ribstyle.css"}) - Style style(); -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/resources/Ribstyle.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/resources/Ribstyle.css deleted file mode 100644 index 33cb76ab06a..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/resources/Ribstyle.css +++ /dev/null @@ -1,295 +0,0 @@ -@require "colors"; - -.bar { - height: 100%; - margin-top: 20pt; - line-height: 15pt; - vertical-align: middle; - font-size: 15pt; - font-family: 'Open Sans', Arial, Verdana, sans-serif; - width: 100%; - text-align: center; - font-weight: bold; - overflow: visible; -} - -.page { - position: absolute; - border: none; - border-radius: 0; - background-color: C_PRIMARY; - left: 0; - right: 0; - top: 0; - bottom: 30pt; - margin: 5pt; -} - -.logo { - position: absolute; - width: 48pt; - height: 23.5pt; - margin-top: 17.5pt; - margin-left: 10pt; - z-index: 1; -} - -.collumn { - position: absolute; - top: 5pt; - bottom: 15pt; - margin: 5pt; -} - -.startanalysiscollumn { - right: 33.3%; - left: 0%; -} - -/*deprecated*/ -.collumn1 { - width: 33.3%; -} -/*deprecated*/ -.collumn2 { - width: 33.3%; - left: 33.3%; -} -/*deprecated*/ -.collumn3 { - left: 66.8%; - right: 0pt; -} - -.left { - left: 0pt; - right: 50%; -} - -.right { - left: 50%; - right: 0pt; -} - -/*+++++++++++++++++++++++++++++++++++++++++*/ -/* .content { */ -/* width: 100%; */ -/* height: 50pt; */ -/* margin: 0pt; */ -/* } */ -.stripe { - background-color: black; - maring: 0pt; - padding: 0pt; - width: 1%; - height: 90%; - float: left; -} - -.chart { - width: 100%; - height: 100%; -} - -.rootpanel { - background-color: C_PRIMARY; - width: 100%; - height: 200%; -} - -.startline_advantage_by_wind_container { - position: absolute; - background-color: white; - top: 27%; - right: 0pt; - left: 0pt; - bottom: 0%; -} - -.startline_advantage_by_geometry_container { - position: absolute; - background-color: white; - top: 0%; - right: 0pt; - left: 0pt; - bottom: 73%; - margin-bottom: 10pt; -} - -.hintpanel { - position: absolute; - background-color: white; - height: 25pt; - right: 0pt; - left: 0pt; - bottom: 0pt; -} - -.leaderboardpanel { - position: absolute; - top: 30%; - right: 0pt; - left: 0pt; - bottom: 0pt; - margin-top: 5pt; -} - -.hint { - height: 100%; - line-height: 25pt; - margin-top: 0pt; - vertical-align: middle; - font-size: 12pt; - font-family: 'Open Sans', Arial, Verdana, sans-serif; - width: 100%; - text-align: center; -} - -.windcharthint { - position: absolute; - bottom: 0pt; - height: 15pt; - line-height: 15pt; - margin-top: 0pt; - vertical-align: middle; - font-size: 12pt; - font-family: 'Open Sans', Arial, Verdana, sans-serif; - width: 100%; - text-align: center; -} - -.scrollLayoutPanel { - height: 100%; - width: 100%; -} - -windchartcontainer { - position: absolute; - left: 0pt; - right: 0pt; - top: 0pt; - bottom: 0pt; -} - -.windchartwrapper { - position: absolute; - top: 0pt; - bottom: 0pt; - left: 0pt; - right: 0pt; -} - -/*??????*/ -.windchart { - position: absolute; - left: 0pt; - right: 0pt; - top: 0pt; - bottom: 0pt; -} - -.startlineanalysis { - position: absolute; - top: 0pt; - right: 0pt; - left: 0pt; - bottom: 10pt; - background-color: #0DBFFF; -} - -.collumncontent { - height: 100%; - width: 100%; - background-color: white; -} - -/*Test*/ -.scrollHorizontal { - overflow-y: hidden !important; - overflow-x: hidden !important; - position: absolute !important; - top: 0pt; - right: 0pt; - left: 0pt; - bottom: 0pt; -} - -.scrollAbsPanel { - overflow-y: hidden !important; - overflow-x: hidden !important; - position: absolute !important; - top: 0pt; - right: 0pt; - left: 0pt; - bottom: 0pt; -} - -.scrollcontainer { - position: absolute; - top: 15pt; - right: 15pt; - width: 300%; - bottom: 15pt; - background-color: white; -} - -.start { - position: absolute; - top: 0pt; - right: 0pt; - left: 0pt; - bottom: 0pt; - height: 100%; - /* height: 300pt; */ /* width: 400pt; */ /* margin: 10pt; */ - background-color: #0DBFFF; -} - -.scrollPage1 { - position: absolute; - height: 80%; - width: 80%; - margin: 10%; - background-color: #0DBFFF; -} - -.scrollPage2 { - position: absolute; - height: 80%; - width: 80%; - left: 170%; - background-color: #0DBFFF; -} - -.scrollPage3 { - position: absolute; - height: 80%; - width: 80%; - left: 260%; - background-color: #0DBFFF; -} - -.windloadinghint { - position: absolute; - background-color: white; - opacity: 0.4; - width: 100%; - height: 100%; - vertical-align: middle; - text-align: center; - z-index: 0; -} - -.windloadinghinttext { - position: absolute; - bottom: 0pt; - height: 15pt; - line-height: 15pt; - margin-top: 0pt; - vertical-align: middle; - font-size: 12pt; - font-family: 'Open Sans', Arial, Verdana, sans-serif; - width: 100%; - text-align: center; - top: 50%; - margin-top: -7pt; -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/resources/colors.gss b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/resources/colors.gss deleted file mode 100644 index e279b9c801c..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/resources/colors.gss +++ /dev/null @@ -1,7 +0,0 @@ -@provide 'colors'; - -@def C_PRIMARY eval("com.company.project.client.resources.Colors.C_PRIMARY"); -@def C_SECONDARY eval("com.company.project.client.resources.Colors.C_SECONDARY"); -@def C_BACKGROUND eval("com.company.project.client.resources.Colors.C_BACKGROUND"); -@def C_TEXT eval("com.company.project.client.resources.Colors.C_TEXT"); -@def C_TEXT_LIGHT eval("com.company.project.client.resources.Colors.C_TEXT_LIGHT"); \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartAnalysisResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartAnalysisResources.java deleted file mode 100644 index 6bca74985f4..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartAnalysisResources.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client.startanalysis; - -import com.google.gwt.resources.client.ClientBundle; -import com.google.gwt.resources.client.ImageResource; -import com.sap.sailing.gwt.ui.client.shared.racemap.CombinedWindPanelStyle; - -interface StartAnalysisResources extends ClientBundle { - - @Source("com/sap/sailing/dashboards/gwt/client/images/windarrow.png") - ImageResource combinedWindIcon(); - - @Source("StartAnalysisCombinedWindPanel.css") - CombinedWindPanelStyle combinedWindPanelStyle(); -} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysisCard.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysisCard.ui.xml deleted file mode 100644 index 7133cdeb7d0..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysisCard.ui.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - -
-
-
-
Time: 00:05:00
- -
-
\ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysisComponent.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysisComponent.ui.xml deleted file mode 100644 index 8368a8b2933..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysisComponent.ui.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - No Starts Available - - - - - - - - - - \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/LiveAverageComponent.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/LiveAverageComponent.ui.xml deleted file mode 100644 index 49cb75c6be2..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/LiveAverageComponent.ui.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - -
-
- - -
- - -
-
- - - - - - -
- - -
-
- - -
-
- - -
-
- -
- -
\ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartLineAdvantageByGeometryComponent.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartLineAdvantageByGeometryComponent.java deleted file mode 100644 index fe16319c68e..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartLineAdvantageByGeometryComponent.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client.startlineadvantage; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.google.gwt.i18n.client.NumberFormat; -import com.sap.sailing.dashboards.gwt.client.dataretriever.RibDashboardDataRetriever; -import com.sap.sailing.dashboards.gwt.client.dataretriever.RibDashboardDataRetrieverListener; -import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO; -import com.sap.sailing.gwt.ui.client.StringMessages; - -/** - * The purpose of the class is to display the live and average start line advantage either by wind or by geometry. There - * is only one advantage display at once, so the user can switch between these following two - * {@link StartLineAdvantageComponentState}s {@link StartLineAdvantageComponentStateShowsAdvantageByWind} and - * {@link StartLineAdvantageComponentStateShowsAdvantageByGeometry} by tabing somewhere at the widget. The class extends - * from {@link LiveAverageComponent} to get necessary Ui Elements but customizes these with own CSS. - * - * @author Alexander Ries (D062114) - * - */ -public class StartLineAdvantageByGeometryComponent extends LiveAverageComponent implements RibDashboardDataRetrieverListener { - - private static StringMessages stringConstants = StringMessages.INSTANCE; - private static final Logger logger = Logger.getLogger(StartLineAdvantageByGeometryComponent.class.getName()); - - public StartLineAdvantageByGeometryComponent(RibDashboardDataRetriever ribDashboardDataRetriever) { - super(stringConstants.dashboardStartlineAdvantageByGeometry(), "m"); - StartLineAdvantageComponentRessources.INSTANCE.css().ensureInjected(); - this.header.setInnerText(stringConstants.dashboardStartlineAdvantageByGeometry()); - this.header.addClassName(StartLineAdvantageComponentRessources.INSTANCE.css().startLineAdvantageComponent_header()); - liveAveragePanel.getElement().addClassName(StartLineAdvantageComponentRessources.INSTANCE.css().startLineAdvantageComponent_liveAveragePanel()); - livePanel.getElement().addClassName(StartLineAdvantageComponentRessources.INSTANCE.css().startLineAdvantageComponent_livePanel()); - middleLine.getElement().addClassName(StartLineAdvantageComponentRessources.INSTANCE.css().startLineAdvantageComponent_middleLine()); - averagePanel.getElement().addClassName(StartLineAdvantageComponentRessources.INSTANCE.css().startLineAdvantageComponent_averagePanel()); - this.liveLabel.setInnerHTML(stringConstants.dashboardLiveWind()); - this.averageLabel.setInnerHTML(stringConstants.dashboardAverageWind()+"
"+stringConstants.dashboardAverageWindMinutes(15)); - ribDashboardDataRetriever.addDataObserver(this); - } - - public void setStartLineAdvantageValues(RibDashboardRaceInfoDTO liveRaceInfoDTO) { - if (liveRaceInfoDTO.startLineAdvantageDTO != null) { - logger.log(Level.INFO, "Updating UI with RibDashboardRaceInfoDTO.startLineAdvantageDTO"); - setLiveValue(NumberFormat.getFormat("#0.0").format(liveRaceInfoDTO.startLineAdvantageDTO.startLineAdvantage)); - setAverageValue(NumberFormat.getFormat("#0.0").format(liveRaceInfoDTO.startLineAdvantageDTO.average)); - } else { - logger.log(Level.INFO, "RibDashboardRaceInfoDTO.startLineAdvantageDTO is null"); - } - } - - @Override - public void updateUIWithNewLiveRaceInfo(RibDashboardRaceInfoDTO liveRaceInfoDTO) { - setStartLineAdvantageValues(liveRaceInfoDTO); - } -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesByWindComponent.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesByWindComponent.java deleted file mode 100644 index d29bf87d175..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesByWindComponent.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client.startlineadvantage; - -import java.util.Date; -import java.util.Iterator; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.dom.client.Style.Unit; -import com.google.gwt.resources.client.CssResource; -import com.google.gwt.uibinder.client.UiBinder; -import com.google.gwt.uibinder.client.UiField; -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.google.gwt.user.client.ui.Composite; -import com.google.gwt.user.client.ui.HasWidgets; -import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.dashboards.gwt.client.RibDashboardServiceAsync; -import com.sap.sailing.dashboards.gwt.client.actions.GetStartlineAdvantagesAction; -import com.sap.sailing.dashboards.gwt.client.dataretriever.WindBotDataRetriever; -import com.sap.sailing.dashboards.gwt.shared.dto.StartlineAdvantagesWithMaxAndAverageDTO; -import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sse.gwt.client.async.AsyncActionsExecutor; -import com.sap.sse.gwt.client.player.TimeListener; -import com.sap.sse.gwt.client.player.Timer; -import com.sap.sse.gwt.client.player.Timer.PlayModes; - -/** - * @author Alexander Ries (D062114) - * - */ -public class StartlineAdvantagesByWindComponent extends Composite implements HasWidgets, TimeListener { - - private static StartlineAdvantagesByWindComponentUiBinder uiBinder = GWT - .create(StartlineAdvantagesByWindComponentUiBinder.class); - - interface StartlineAdvantagesByWindComponentUiBinder extends UiBinder { - } - - interface StartlineAdvantagesByWindComponentStyle extends CssResource { - - } - - @UiField(provided = true) - LiveAverageComponent advantageMaximumLiveAverage; - - @UiField(provided = true) - StartlineAdvantagesOnLineChart startlineAdvantagesOnLineChart; - - @UiField - StartlineAdvantagesByWindComponentStyle style; - - private RibDashboardServiceAsync ribDashboardService; - private AsyncActionsExecutor asyncActionsExecutor; - private static final Logger logger = Logger.getLogger(WindBotDataRetriever.class.getName()); - - public StartlineAdvantagesByWindComponent(RibDashboardServiceAsync ribDashboardService) { - startlineAdvantagesOnLineChart = new StartlineAdvantagesOnLineChart(); - advantageMaximumLiveAverage = new LiveAverageComponent(StringMessages.INSTANCE.dashboardStartlineAdvantagesByWind(), "m"); - advantageMaximumLiveAverage.header.getStyle().setFontSize(14, Unit.PT); - advantageMaximumLiveAverage.liveLabel.setInnerHTML("advantage max."); - advantageMaximumLiveAverage.averageLabel.setInnerHTML("advantage max. average "+StringMessages.INSTANCE.dashboardAverageWindMinutes(15)); - initWidget(uiBinder.createAndBindUi(this)); - this.ribDashboardService = ribDashboardService; - this.asyncActionsExecutor = new AsyncActionsExecutor(); - initSampleTimer(); - } - - private void loadData() { - GetStartlineAdvantagesAction getRibDashboardRaceInfoAction = new GetStartlineAdvantagesAction(ribDashboardService, ""); - logger.log(Level.INFO, "Executing GetStartlineAdvantagesAction"); - asyncActionsExecutor.execute(getRibDashboardRaceInfoAction, - new AsyncCallback() { - - @Override - public void onSuccess(StartlineAdvantagesWithMaxAndAverageDTO result) { - logger.log(Level.INFO, "Received StartlineAdvantagesWithMaxAndAverageDTO"); - if (result != null) { - logger.log(Level.INFO, "Updating UI with StartlineAdvantagesWithMaxAndAverageDTO"); - startlineAdvantagesOnLineChart.setStartlineAdvantages(result.advantages); - advantageMaximumLiveAverage.setLiveValue("" + result.maximum); - advantageMaximumLiveAverage.setAverageValue("" + result.average); - } else { - logger.log(Level.INFO, "StartlineAdvantagesWithMaxAndAverageDTO is null"); - } - } - - @Override - public void onFailure(Throwable caught) { - logger.log(Level.INFO, "Failed to received StartlineAdvantagesWithMaxAndAverageDTO, "+caught.getMessage()); - } - }); - } - - private void initSampleTimer(){ - Timer timer = new Timer(PlayModes.Live); - timer.setRefreshInterval(5000); - timer.addTimeListener(this); - timer.play(); - } - - @Override - public void add(Widget w) { - throw new UnsupportedOperationException("The method add(Widget w) is not supported."); - } - - @Override - public void clear() { - throw new UnsupportedOperationException("The method clear() is not supported."); - } - - @Override - public Iterator iterator() { - return null; - } - - @Override - public boolean remove(Widget w) { - return false; - } - - @Override - public void timeChanged(Date newTime, Date oldTime) { - loadData(); - } - -} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesByWindComponent.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesByWindComponent.ui.xml deleted file mode 100644 index 6bd79c479e9..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesByWindComponent.ui.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesOnLineChart.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesOnLineChart.ui.xml deleted file mode 100644 index 4ad17a938af..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesOnLineChart.ui.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - -
-
-
-
-
-
-
-
\ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/theme/Colors.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/theme/Colors.java new file mode 100644 index 00000000000..e74d80c2ed6 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/theme/Colors.java @@ -0,0 +1,16 @@ +package com.sap.sailing.dashboards.gwt.client.theme; + +/** + * @author Alexander Ries (D062114) + * + */ +public class Colors { + public static final String WHITE = "#FFFFFF"; + public static final String LIGHT_GREY = "#FFFFFF"; + public static final String DARK_GREY = "#FFFFFF"; + public static final String LIGHT_TEXT_COLOR = "#FFFFFF"; + public static final String DARK_TEXT_COLOR = "#FFFFFF"; + public static final String DARK_BLUE = "#FFFFFF"; + public static final String LIGHT_BLUE = "#FFFFFF"; + public static final String YELLOW = "#FFFFFF"; +} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/theme/Fonts.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/theme/Fonts.java new file mode 100644 index 00000000000..1783e95bbc6 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/theme/Fonts.java @@ -0,0 +1,9 @@ +package com.sap.sailing.dashboards.gwt.client.theme; + +/** + * @author Alexander Ries (D062114) + * + */ +public class Fonts { + public static final String DASHBOARD_FONT_FAMILY = "'Open Sans', Arial, Verdana, sans-serif"; +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/theme/Sizes.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/theme/Sizes.java new file mode 100644 index 00000000000..a539e9021a4 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/theme/Sizes.java @@ -0,0 +1,13 @@ +package com.sap.sailing.dashboards.gwt.client.theme; + +/** + * @author Alexander Ries (D062114) + * + */ +public class Sizes { + public static final String DASHBOARD_FONT_SIZE_VERY_SMALL = "12px"; + public static final String DASHBOARD_FONT_SIZE_SMALL = "12px"; + public static final String DASHBOARD_FONT_SIZE_MEDIUM = "12px"; + public static final String DASHBOARD_FONT_SIZE_BIG = "12px"; + public static final String DASHBOARD_FONT_SIZE_VERY_BIG = "12px"; +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/theme/theme.gss b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/theme/theme.gss new file mode 100644 index 00000000000..168c9ab59aa --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/theme/theme.gss @@ -0,0 +1,7 @@ +@provide 'theme'; + +/*Colors*/ +@def WHITE eval("com.sap.sailing.dashboards.gwt.client.theme.Colors.WHITE"); + +/*Fonts*/ +@def DASHBOARD_FONT_FAMILY eval("com.sap.sailing.dashboards.gwt.client.theme.Fonts.DASHBOARD_FONT_FAMILY"); diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/util/HighchartsUtil.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/util/HighchartsUtil.java new file mode 100644 index 00000000000..d1bbd46a05c --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/util/HighchartsUtil.java @@ -0,0 +1,37 @@ +package com.sap.sailing.dashboards.gwt.client.util; + +import org.moxieapps.gwt.highcharts.client.Chart; + +import com.google.gwt.user.client.Timer; + +/** + * @author Alexander Ries (D062114) + * + */ +public class HighchartsUtil { + + /** + * The {@link Chart} spacing is not consistent + * so there is a need to correct the top, bottom and right spacing + * of the chart to make it look visually right. + * */ + public static void correctSpacingOfChart(Chart chart) { + chart.setSpacingTop(17) + .setSpacingBottom(13) + .setSpacingRight(35); + } + + /** + * In cases where it is necessary to initialize a {@link Chart} with dynamic size during the same browser loop, where it´s dynamic container is initialized, + * the {@link Chart.setSizeToMatchContainer()} method will not work. The solution to that problem is to call {@link Chart#setSizeToMatchContainer()} later, + * when the container of the chart is completely initialized and its size is available to the {@link Chart}. + * */ + public static void setSizeToMatchContainerDelayed(final Chart chart) { + Timer elapsedTimer = new Timer() { + public void run() { + chart.setSizeToMatchContainer(); + } + }; + elapsedTimer.schedule(500); + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/visualeffects/BlurEffect.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/visualeffects/BlurEffect.css index 6d533471683..7e1020ab331 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/visualeffects/BlurEffect.css +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/visualeffects/BlurEffect.css @@ -1,11 +1,11 @@ @CHARSET "UTF-8"; .blurred { - -webkit-filter: blur(10pt) brightness(0.92); - filter: blur(10pt) brightness(0.92); + -webkit-filter: brightness(0.7); + filter: brightness(0.7); } .not_blurred { - -webkit-filter: blur(0pt) brightness(1); - filter: blur(0pt) brightness(1); + -webkit-filter: brightness(1); + filter: brightness(1); } \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/PollsLiveDataEvery5Seconds.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/PollsLiveDataEvery5Seconds.java new file mode 100644 index 00000000000..c400402924c --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/PollsLiveDataEvery5Seconds.java @@ -0,0 +1,13 @@ +package com.sap.sailing.dashboards.gwt.client.widgets; +import com.sap.sailing.dashboards.gwt.client.DashboardClientFactory; +import com.sap.sse.gwt.client.player.TimeListener; + + +/** + * @author Alexander Ries (D062114) + * + */ +public interface PollsLiveDataEvery5Seconds extends TimeListener { + + public void registerForDashboardFiveSecondsTimer(DashboardClientFactory dashboardClientFactory); +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartAnalysisCombinedWindPanel.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisCombinedWindPanel.gss similarity index 88% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartAnalysisCombinedWindPanel.css rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisCombinedWindPanel.gss index dc195777bbf..d4843d25e1b 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartAnalysisCombinedWindPanel.css +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisCombinedWindPanel.gss @@ -1,4 +1,4 @@ -@CHARSET "UTF-8"; +@require 'theme'; .combinedWindPanel { margin-top: 10pt; @@ -18,7 +18,7 @@ line-height: 25pt; vertical-align: middle; font-size: 11pt; - font-family: "Arial"; + font-family: DASHBOARD_FONT_FAMILY; text-align: center; } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartAnalysisPageChangeListener.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisPageChangeListener.java similarity index 56% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartAnalysisPageChangeListener.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisPageChangeListener.java index 98e4400e243..11cd4d3d0bd 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartAnalysisPageChangeListener.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisPageChangeListener.java @@ -1,6 +1,6 @@ -package com.sap.sailing.dashboards.gwt.client.startanalysis; +package com.sap.sailing.dashboards.gwt.client.widgets.startanalysis; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO; +import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisDTO; public interface StartAnalysisPageChangeListener { diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysis.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisWidget.gss similarity index 75% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysis.css rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisWidget.gss index bb188a8b41b..4e60c3bae9d 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysis.css +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisWidget.gss @@ -1,4 +1,4 @@ -@CHARSET "UTF-8"; +@require 'theme'; .startanalysis { position: absolute; @@ -10,13 +10,13 @@ bottom: 0pt; } -.panelHeader { +.panel_header { height: 100%; margin-top: 0; line-height: 30pt; vertical-align: middle; font-size: 14pt; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; width: 100%; text-align: center; font-weight: bold; @@ -24,22 +24,22 @@ background-color: white; } -.startanalysis_controll_header_button { +.controll_header_button { position: absolute; top: 10pt; height: 17.5pt; width: 17.5pt; } -.startanalysis_controll_header_button_left { +.controll_header_button_left { left: 10%; } -.startanalysis_controll_header_button_right { +.controll_header_button_right { right: 10%; } -.startanalysis_card_container { +.card_container { position: absolute; overflow: visible; top: 33.5pt; @@ -51,7 +51,7 @@ transition: left 0.7s ease-in-out; } -.startanalysis_card { +.card { position: absolute; display: inline; width: 80%; @@ -62,7 +62,7 @@ overflow: hidden; } -.startanalysis_card_table { +.card_table { position: absolute; bottom: 0pt; right: 0pt; @@ -74,7 +74,7 @@ z-index: 2; } -.startanalysis_card_wind_line_data_container { +.card_wind_line_data_container { position: absolute; top: 10pt; left: 10pt; @@ -83,7 +83,7 @@ z-index: 1; } -.startanalysis_card_data { +.card_data { position: absolute; right: 0pt; width: 45pt; @@ -91,11 +91,11 @@ line-height: 25pt; vertical-align: middle; font-size: 11pt; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; text-align: center; } -.startanalysis_card_line_advantage { +.card_line_advantage { top: 0pt; left: 55pt; width: 215pt; @@ -104,7 +104,7 @@ background-color: white; } -.startanalysis_card_race_time{ +.card_race_time{ position: absolute; top: 10pt; right: 10pt; @@ -113,11 +113,11 @@ color: white; line-height: 25pt; font-size: 11pt; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; z-index: 1; } -.startanalysis_card_line_data_geo { +.card_line_data_geo { top: 0pt; left: 220pt; width: 100pt; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysisComponent.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisWidget.java similarity index 65% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysisComponent.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisWidget.java index 9645a09aab4..0c25f94b611 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysisComponent.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisWidget.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.startanalysis; +package com.sap.sailing.dashboards.gwt.client.widgets.startanalysis; import java.util.ArrayList; import java.util.Date; @@ -15,7 +15,6 @@ import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.Cookies; -import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FocusPanel; @@ -24,44 +23,43 @@ import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.Image; 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.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.DashboardClientFactory; +import com.sap.sailing.dashboards.gwt.client.actions.GetCompetitorInLeaderboardAction; +import com.sap.sailing.dashboards.gwt.client.actions.GetStartAnalysesAction; +import com.sap.sailing.dashboards.gwt.client.notifications.bottom.BottomNotification; +import com.sap.sailing.dashboards.gwt.client.notifications.bottom.BottomNotificationClickListener; +import com.sap.sailing.dashboards.gwt.client.notifications.bottom.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; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO; +import com.sap.sailing.dashboards.gwt.client.widgets.PollsLiveDataEvery5Seconds; +import com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.card.StartAnalysisCard; +import com.sap.sailing.dashboards.gwt.shared.DashboardURLParameters; +import com.sap.sailing.dashboards.gwt.shared.dto.LeaderboardCompetitorsDTO; +import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysesDTO; +import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisDTO; import com.sap.sailing.domain.common.dto.CompetitorDTO; -import com.sap.sailing.gwt.ui.client.SailingServiceAsync; -import com.sap.sse.gwt.client.player.TimeListener; -import com.sap.sse.gwt.client.player.Timer; -import com.sap.sse.gwt.client.player.Timer.PlayModes; /** - * The class contains an collection of {@link StartlineAnalysisCard}s that are displayed in horizontal aligned pages. It - * shows only one {@link StartlineAnalysisCard} at a time and enables the user to switch between - * {@link StartlineAnalysisCard}s with left and right buttons represented by {@link #left_focus_panel} and - * {@link #right_focus_panel}. When a new {@link StartlineAnalysisCard} gets added to the component it shows a + * The class contains an collection of {@link StartAnalysisCard}s that are displayed in horizontal aligned pages. It + * shows only one {@link StartAnalysisCard} at a time and enables the user to switch between + * {@link StartAnalysisCard}s with left and right buttons represented by {@link #left_focus_panel} and + * {@link #right_focus_panel}. When a new {@link StartAnalysisCard} gets added to the component it shows a * {@link BottomNotification}. * * @author Alexander Ries (D062114) * */ -public class StartlineAnalysisComponent extends Composite implements HasWidgets { +public class StartAnalysisWidget extends Composite implements HasWidgets, PollsLiveDataEvery5Seconds { - private static StartlineAnalysisComponentUiBinder uiBinder = GWT.create(StartlineAnalysisComponentUiBinder.class); + private static StartAnalysisWidgetUiBinder uiBinder = GWT.create(StartAnalysisWidgetUiBinder.class); - interface StartlineAnalysisComponentUiBinder extends UiBinder { + interface StartAnalysisWidgetUiBinder extends UiBinder { } interface StartlineAnalysis extends CssResource { } - @UiField - StartlineAnalysis style; - @UiField HTMLPanel header; @@ -78,7 +76,7 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets FocusPanel right_focus_panel; /** - * Gets populated with new {@link StartlineAnalysisCard}s when the method + * Gets populated with new {@link StartAnalysisCard}s when the method * {@link #addStartAnalysisCard(StartAnalysisDTO)} gets called. * */ @UiField @@ -90,65 +88,57 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets private double currentScrollPosition = 0; /** - * The page or {@link StartlineAnalysisCard} the {@link #startanalysis_card_container} displays. Begins with 0. + * The page or {@link StartAnalysisCard} the {@link #startanalysis_card_container} displays. Begins with 0. * */ private int page = 0; /** - * Amount of {@link StartlineAnalysisCard}s in {@link #startanalysis_card_container}. + * Amount of {@link StartAnalysisCard}s in {@link #startanalysis_card_container}. * */ private int numberOfStartAnalysisCards = 0; private boolean displaysCards; private List starts; - private List pageChangeListener; + private List pageChangeListener; private BottomNotification bottomNotification; - private Timer timer; - private RibDashboardServiceAsync ribDashboardServiceAsync; - private SailingServiceAsync sailingServiceAsync; - - private static final int RERFRESH_INTERVAL = 10000; private CompetitorSelectionPopup competitorSelectionPopup; private SettingsButtonWithSelectionIndicationLabel settingsButtonWithSelectionIndicationLabel; + + private DashboardClientFactory dashboardClientFactory; - private String leaderboardName; - - private static final String PARAM_LEADERBOARD_NAME = "leaderboardName"; private static final String SELECTED_COMPETITOR_ID_COOKIE_KEY = "selectedCompetitorId"; private static final int SELECTED_COMPETITOR_ID_COOKIE_KEY_EXPIRE_TIME_IN_MILLIS = 60 * 1000 * 60 * 5; private static final int SCROLL_OFFSET_STARTANALYSIS_CARDS = 83; - private static final Logger logger = Logger.getLogger(StartlineAnalysisComponent.class.getName()); + private static final Logger logger = Logger.getLogger(StartAnalysisWidget.class.getName()); /** * Component that contains handles, displays and loads startanalysis cards. * */ - public StartlineAnalysisComponent(RibDashboardServiceAsync ribDashboardServiceAsync, SailingServiceAsync sailingServiceAsync) { - this.ribDashboardServiceAsync = ribDashboardServiceAsync; - this.sailingServiceAsync = sailingServiceAsync; - pageChangeListener = new ArrayList(); + public StartAnalysisWidget(DashboardClientFactory dashboardClientFactory) { + StartAnalysisWidgetResources.INSTANCE.gss().ensureInjected(); + StartAnalysisWidgetResources.INSTANCE.combinedWindPanelStyle().ensureInjected(); + this.dashboardClientFactory = dashboardClientFactory; + pageChangeListener = new ArrayList(); starts = new ArrayList(); - this.leaderboardName = Window.Location.getParameter(PARAM_LEADERBOARD_NAME); - initWidget(uiBinder.createAndBindUi(this)); - initCompetitorSelectionPopupAndAddCompetitorSelectionListener(); initLeftRightButtons(); - initTimer(); initAndAddBottomNotification(); getCachedSelectedCompetitorOrAskForWithPopup(); initAndAddSettingsButtonWithSelectionIndicationLabel(); + registerForDashboardFiveSecondsTimer(dashboardClientFactory); } private void initLeftRightButtons() { - leftButton.setResource(RibDashboardImageResources.INSTANCE.leftdisabled()); + leftButton.setResource(StartAnalysisWidgetResources.INSTANCE.leftdisabled()); left_focus_panel.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { clickedArrowButton(false); } }); - rightButton.setResource(RibDashboardImageResources.INSTANCE.rightdisabled()); + rightButton.setResource(StartAnalysisWidgetResources.INSTANCE.rightdisabled()); right_focus_panel.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { @@ -157,53 +147,33 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets }); } - private void initTimer() { - timer = new Timer(PlayModes.Live); - timer.setRefreshInterval(RERFRESH_INTERVAL); - timer.addTimeListener(new TimeListener() { - - @Override - public void timeChanged(Date newTime, Date oldTime) { - String selectedCompetitorId = Cookies.getCookie(SELECTED_COMPETITOR_ID_COOKIE_KEY); - if (selectedCompetitorId != null) { - loadStartAnalysisDTOsForCompetitorID(selectedCompetitorId); - } else { - loadCompetitorsAndShowCompetitorSelectionPopup(); - } - } - }); - } - private void loadStartAnalysisDTOsForCompetitorID(String competitorIdAsString){ logger.log(Level.INFO, "Loading startanalysis for competitor id " + competitorIdAsString); - ribDashboardServiceAsync.getStartAnalysisListForCompetitorIDAndLeaderboardName( - competitorIdAsString, leaderboardName, new AsyncCallback>() { - @Override - public void onSuccess(List result) { - logger.log(Level.INFO, "Received startanalysis list"); - if (result != null && !result.isEmpty()) { - - if (displayedStartAnalysisCompetitorDifferentToRequestedOne()) { - removeAllStartAnalysisCards(); - } - - if (result.size() != starts.size()) { - showNotificationForNewStartAnalysis(); - } - logger.log(Level.INFO, "Updating UI with startanalysis list"); - addNewStartAnalysisCards(result); - settingsButtonWithSelectionIndicationLabel - .setSelectionIndicationTextOnLabel(result.get(0).competitor.getName()); - } else { - logger.log(Level.INFO, "Received startanalysis list is null or empty"); - } - } + dashboardClientFactory.getDispatch().execute(new GetStartAnalysesAction(DashboardURLParameters.LEADERBOARD_NAME.getValue(), competitorIdAsString), new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - logger.log(Level.INFO, "Failed to received startanalysis list, "+caught.getMessage()); - } - }); + @Override + public void onFailure(Throwable caught) { + logger.log(Level.INFO, "Failed to received startanalysis list, "+caught.getMessage()); + } + + @Override + public void onSuccess(StartAnalysesDTO result) { + logger.log(Level.INFO, "Received startanalysis list"); + if (result != null && !result.getStartAnalyses().isEmpty()) { + if (displayedStartAnalysisCompetitorDifferentToRequestedOne()) { + removeAllStartAnalysisCards(); + } + if (result.getStartAnalyses().size() != starts.size()) { + showNotificationForNewStartAnalysis(); + } + logger.log(Level.INFO, "Updating UI with startanalysis list"); + addNewStartAnalysisCards(result.getStartAnalyses()); + settingsButtonWithSelectionIndicationLabel.setSelectionIndicationTextOnLabel(result.getStartAnalyses().get(0).competitor.getName()); + } else { + logger.log(Level.INFO, "Received startanalysis list is null or empty"); + } + } + }); } private void initAndAddBottomNotification() { @@ -247,27 +217,28 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets private void loadCompetitorsAndShowCompetitorSelectionPopup() { logger.log(Level.INFO, "Requesting Competitors in Leaderboard"); - ribDashboardServiceAsync.getCompetitorsInLeaderboard(leaderboardName, new AsyncCallback>() { - @Override - public void onSuccess(List result) { - logger.log(Level.INFO, "Received competitors for leaderboard name"); - if (result != null && result.size() > 0) { - if (!competitorSelectionPopup.isShown()) { - logger.log(Level.INFO, "Showing CompetitorSelectionPopup with competitors"); - competitorSelectionPopup.show(result); - } else { - logger.log(Level.INFO, "CompetitorSelectionPopup aleady shown"); - } - } else { - logger.log(Level.INFO, "Received competitors are null or empty"); - } - } + dashboardClientFactory.getDispatch().execute(new GetCompetitorInLeaderboardAction(DashboardURLParameters.LEADERBOARD_NAME.getValue()), new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - logger.log(Level.INFO, "Failed to received competitors for leaderboard name, "+caught.getMessage()); - } - }); + @Override + public void onSuccess(LeaderboardCompetitorsDTO result) { + logger.log(Level.INFO, "Received competitors for leaderboard name"); + if (result.getCompetitors() != null && result.getCompetitors().size() > 0) { + if (!competitorSelectionPopup.isShown()) { + logger.log(Level.INFO, "Showing CompetitorSelectionPopup with competitors"); + competitorSelectionPopup.show(result.getCompetitors()); + } else { + logger.log(Level.INFO, "CompetitorSelectionPopup aleady shown"); + } + } else { + logger.log(Level.INFO, "Received competitors are null or empty"); + } + } + + @Override + public void onFailure(Throwable caught) { + logger.log(Level.INFO, "Failed to received competitors for leaderboard name, "+caught.getMessage()); + } + }); } private void initAndAddSettingsButtonWithSelectionIndicationLabel() { @@ -298,11 +269,11 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets int displayPage = page + 1; header.getElement().setInnerHTML("Start " + starts.get(displayPage - 1).raceName); if (page != numberOfStartAnalysisCards - 1) { - rightButton.setResource(RibDashboardImageResources.INSTANCE.right()); + rightButton.setResource(StartAnalysisWidgetResources.INSTANCE.right()); rightButton.getElement().getStyle().setProperty("disabled", "false"); } if (page == 0) { - leftButton.setResource(RibDashboardImageResources.INSTANCE.leftdisabled()); + leftButton.setResource(StartAnalysisWidgetResources.INSTANCE.leftdisabled()); leftButton.getElement().getStyle().setProperty("disabled", "true"); } } @@ -315,11 +286,11 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets int displayPage = page + 1; header.getElement().setInnerHTML("Start " + starts.get(displayPage - 1).raceName); if (page >= 0) { - leftButton.setResource(RibDashboardImageResources.INSTANCE.left()); + leftButton.setResource(StartAnalysisWidgetResources.INSTANCE.left()); leftButton.getElement().getStyle().setProperty("disabled", "false"); } if (page == numberOfStartAnalysisCards - 1) { - rightButton.setResource(RibDashboardImageResources.INSTANCE.rightdisabled()); + rightButton.setResource(StartAnalysisWidgetResources.INSTANCE.rightdisabled()); rightButton.getElement().getStyle().setProperty("disabled", "true"); } } @@ -335,9 +306,9 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets startanalysis_card_container.getElement().getStyle().setLeft(currentScrollPosition, Unit.PCT); header.getElement().setInnerHTML("Start " + starts.get(page).raceName); notifyStartAnalysisPageChangeListener(page); - rightButton.setResource(RibDashboardImageResources.INSTANCE.rightdisabled()); + rightButton.setResource(StartAnalysisWidgetResources.INSTANCE.rightdisabled()); rightButton.getElement().getStyle().setProperty("disabled", "true"); - leftButton.setResource(RibDashboardImageResources.INSTANCE.left()); + leftButton.setResource(StartAnalysisWidgetResources.INSTANCE.left()); leftButton.getElement().getStyle().setProperty("disabled", "false"); } } @@ -349,11 +320,11 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets header.getElement().setInnerHTML("Start " + startAnalysisDTO.raceName); } if (numberOfStartAnalysisCards > 0) { - rightButton.setResource(RibDashboardImageResources.INSTANCE.right()); + rightButton.setResource(StartAnalysisWidgetResources.INSTANCE.right()); } - final StartlineAnalysisCard startlineAnalysisCard = new StartlineAnalysisCard(numberOfStartAnalysisCards + final StartAnalysisCard startlineAnalysisCard = new StartAnalysisCard(numberOfStartAnalysisCards * SCROLL_OFFSET_STARTANALYSIS_CARDS + 10, numberOfStartAnalysisCards, startAnalysisDTO, - sailingServiceAsync); + dashboardClientFactory.getSailingService()); startanalysis_card_container.add(startlineAnalysisCard); startlineAnalysisCard.startAnalysisComponentPageChangedToIndexAndStartAnalysis(page, startAnalysisDTO); registerPageChangeListener(startlineAnalysisCard); @@ -370,7 +341,7 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets this.bottomNotification.show(BottomNotificationType.NEW_STARTANALYSIS_AVAILABLE); } - public void registerPageChangeListener(StartlineAnalysisCard s) { + public void registerPageChangeListener(StartAnalysisCard s) { pageChangeListener.add(s); } @@ -412,6 +383,23 @@ public class StartlineAnalysisComponent extends Composite implements HasWidgets return false; } } + + @Override + public void timeChanged(Date newTime, Date oldTime) { + String selectedCompetitorId = Cookies.getCookie(SELECTED_COMPETITOR_ID_COOKIE_KEY); + if (selectedCompetitorId != null) { + loadStartAnalysisDTOsForCompetitorID(selectedCompetitorId); + } else { + loadCompetitorsAndShowCompetitorSelectionPopup(); + } + } + + @Override + public void registerForDashboardFiveSecondsTimer(DashboardClientFactory dashboardClientFactory) { + if (dashboardClientFactory != null) { + dashboardClientFactory.getDashboardFiveSecondsTimer().addTimeListener(this); + } + } @Override public void add(Widget w) { diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisWidget.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisWidget.ui.xml new file mode 100644 index 00000000000..3ede34ebdf6 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisWidget.ui.xml @@ -0,0 +1,22 @@ + + + + + + + + No Starts Available + + + + + + + + + + \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisWidgetResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisWidgetResources.java new file mode 100644 index 00000000000..7a0aab98c25 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/StartAnalysisWidgetResources.java @@ -0,0 +1,51 @@ +package com.sap.sailing.dashboards.gwt.client.widgets.startanalysis; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; +import com.google.gwt.resources.client.ImageResource; +import com.sap.sailing.gwt.ui.client.shared.racemap.CombinedWindPanelStyle; + +public interface StartAnalysisWidgetResources extends ClientBundle { + + public static final StartAnalysisWidgetResources INSTANCE = GWT.create(StartAnalysisWidgetResources.class); + + @Source("com/sap/sailing/dashboards/gwt/client/images/leftarrow.png") + ImageResource left(); + + @Source("com/sap/sailing/dashboards/gwt/client/images/rightarrow.png") + ImageResource right(); + + @Source("com/sap/sailing/dashboards/gwt/client/images/leftarrow_disabled.png") + ImageResource leftdisabled(); + + @Source("com/sap/sailing/dashboards/gwt/client/images/rightarrow_disabled.png") + ImageResource rightdisabled(); + + @Source("com/sap/sailing/dashboards/gwt/client/images/windarrow.png") + ImageResource combinedWindIcon(); + + @Source({"com/sap/sailing/dashboards/gwt/client/theme/theme.gss", "StartAnalysisWidget.gss"}) + StartAnalysisGSS gss(); + + @Source({"com/sap/sailing/dashboards/gwt/client/theme/theme.gss", "StartAnalysisCombinedWindPanel.gss"}) + CombinedWindPanelStyle combinedWindPanelStyle(); + + public interface StartAnalysisGSS extends CssResource { + String startanalysis(); + String panel_header(); + String controll_header_button(); + String controll_header_button_left(); + String controll_header_button_right(); + String card_container(); + String card(); + String card_table(); + String card_wind_line_data_container(); + String card_data(); + String card_line_advantage(); + String card_race_time(); + String card_line_data_geo(); + String left_focus_panel(); + String right_focus_panel(); + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysisCard.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/card/StartAnalysisCard.java similarity index 89% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysisCard.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/card/StartAnalysisCard.java index 3d4bc02cbec..8d997ca6d63 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAnalysisCard.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/card/StartAnalysisCard.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.startanalysis; +package com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.card; import java.util.ArrayList; import java.util.Collections; @@ -12,14 +12,18 @@ import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.i18n.client.NumberFormat; import com.google.gwt.resources.client.CssResource; +import com.google.gwt.safehtml.shared.SafeHtmlUtils; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; 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.startanalysis.rankingtable.StartAnalysisStartRankTable; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO; +import com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.StartAnalysisPageChangeListener; +import com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.StartAnalysisWidgetResources; +import com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.rankingtable.StartAnalysisStartRankTable; +import com.sap.sailing.dashboards.gwt.shared.StartlineAdvantageType; +import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisDTO; import com.sap.sailing.domain.common.racelog.RacingProcedureType; import com.sap.sailing.gwt.ui.client.CompetitorColorProvider; import com.sap.sailing.gwt.ui.client.CompetitorColorProviderImpl; @@ -35,19 +39,16 @@ import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings.ZoomType import com.sap.sse.gwt.client.async.AsyncActionsExecutor; import com.sap.sse.gwt.client.player.Timer.PlayModes; -public class StartlineAnalysisCard extends Composite implements HasWidgets, StartAnalysisPageChangeListener { +public class StartAnalysisCard extends Composite implements HasWidgets, StartAnalysisPageChangeListener { private static StartlineAnalysisCardUiBinder uiBinder = GWT.create(StartlineAnalysisCardUiBinder.class); - interface StartlineAnalysisCardUiBinder extends UiBinder { + interface StartlineAnalysisCardUiBinder extends UiBinder { } interface StartlineAnalysis extends CssResource { } - @UiField - StartlineAnalysis style; - @UiField HTMLPanel startanalysis_card; @@ -74,12 +75,8 @@ public class StartlineAnalysisCard extends Composite implements HasWidgets, Star private final int TABLE_MARGIN_IN_PT = 10; private final String RACE_TIME_START = "00:00:00"; - - private static StartAnalysisResources resources = GWT.create(StartAnalysisResources.class); - public StartlineAnalysisCard(double leftCSSProperty, int cardId, StartAnalysisDTO startAnalysisDTO, - SailingServiceAsync sailingServiceAsync) { + public StartAnalysisCard(double leftCSSProperty, int cardId, StartAnalysisDTO startAnalysisDTO, SailingServiceAsync sailingServiceAsync) { stringMessages = StringMessages.INSTANCE; - resources.combinedWindPanelStyle().ensureInjected(); this.sailingServiceAsync = sailingServiceAsync; colorProvider = new CompetitorColorProviderImpl(); competitorSelectionModel = new CompetitorSelectionModel(/* hasMultiSelection */true, colorProvider); @@ -96,20 +93,20 @@ public class StartlineAnalysisCard extends Composite implements HasWidgets, Star private void fillWindAndStartLineData(StartAnalysisDTO startAnalysisDTO) { if (startAnalysisDTO.startAnalysisWindLineInfoDTO != null) { setLineAdvantageDivWidth(startAnalysisDTO.startAnalysisWindLineInfoDTO.startLineAdvantage.startLineAdvatageType); - String startLineAdvantageType; + final String startLineAdvantageType; if (startAnalysisDTO.startAnalysisWindLineInfoDTO.startLineAdvantage.startLineAdvatageType .equals(StartlineAdvantageType.GEOMETRIC)) { startLineAdvantageType = stringMessages.dashboardStartlineAdvantageByGeometry(); - }else{ + } else { startLineAdvantageType = stringMessages.dashboardStartlineAdvantagesByWind(); } startanalysis_card_line_advantage - .setInnerHTML(startLineAdvantageType + .setInnerHTML(SafeHtmlUtils.fromString(startLineAdvantageType + ": " + NumberFormat .getFormat("#0.0") .format(startAnalysisDTO.startAnalysisWindLineInfoDTO.startLineAdvantage.startLineAdvantage) - + " m"); + + " m").asString()); String formattedTimeSinceStart; if (startAnalysisDTO.racingProcedureType.equals(RacingProcedureType.GateStart)) { formattedTimeSinceStart = getRaceTimeStringFromMilliseconds(startAnalysisDTO.tailLenghtInMilliseconds); @@ -152,7 +149,7 @@ public class StartlineAnalysisCard extends Composite implements HasWidgets, Star asyncActionsExecutor, null, Collections.singletonList(startAnalysisDTO.regattaAndRaceIdentifier), 5000l /* requestInterval */); raceMap = new RaceMap(sailingServiceAsync, asyncActionsExecutor, null, timer, competitorSelectionModel, StringMessages.INSTANCE, false, false, false, false, startAnalysisDTO.regattaAndRaceIdentifier, - resources.combinedWindPanelStyle(), /* showHeaderPanel */ true); + StartAnalysisWidgetResources.INSTANCE.combinedWindPanelStyle(), /* showHeaderPanel */ true); raceMap.getSettings().setZoomSettings(new RaceMapZoomSettings(zoomTypes, false)); raceMap.getSettings().setHelpLinesSettings(getHelpLineSettings()); raceMap.getSettings().setTailLengthInMilliseconds(startAnalysisDTO.tailLenghtInMilliseconds); diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/card/StartAnalysisCard.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/card/StartAnalysisCard.ui.xml new file mode 100644 index 00000000000..fbb57deff27 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/card/StartAnalysisCard.ui.xml @@ -0,0 +1,16 @@ + + + + + + +
+
+
+
Time: 00:05:00
+ +
+
\ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTable.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTable.java similarity index 96% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTable.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTable.java index 6cbde17f6a2..34ac687aae1 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTable.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTable.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.startanalysis.rankingtable; +package com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.rankingtable; import java.util.List; @@ -9,7 +9,7 @@ import com.google.gwt.user.cellview.client.CellTable; import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy; import com.google.gwt.user.cellview.client.TextColumn; import com.google.gwt.user.client.ui.AbsolutePanel; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisCompetitorDTO; +import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisCompetitorDTO; import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.common.Util.Pair; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableRankAtFirstMarkCell.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableRankAtFirstMarkCell.java similarity index 94% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableRankAtFirstMarkCell.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableRankAtFirstMarkCell.java index fd64139ae9f..3169789147f 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableRankAtFirstMarkCell.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableRankAtFirstMarkCell.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.startanalysis.rankingtable; +package com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.rankingtable; import com.google.gwt.cell.client.AbstractCell; import com.google.gwt.cell.client.Cell; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableRankAtFirstMarkColumn.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableRankAtFirstMarkColumn.java similarity index 84% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableRankAtFirstMarkColumn.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableRankAtFirstMarkColumn.java index f1caccad827..cc0291e1b60 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableRankAtFirstMarkColumn.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableRankAtFirstMarkColumn.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.startanalysis.rankingtable; +package com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.rankingtable; import com.google.gwt.user.cellview.client.Column; import com.sap.sse.common.Util.Pair; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableStyle.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableStyle.css similarity index 100% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableStyle.css rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableStyle.css diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableStyleResource.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableStyleResource.java similarity index 79% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableStyleResource.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableStyleResource.java index dc0c35c590e..d648ee97b44 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableStyleResource.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableStyleResource.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.startanalysis.rankingtable; +package com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.rankingtable; import com.google.gwt.user.cellview.client.CellTable; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableTeamCell.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableTeamCell.java similarity index 91% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableTeamCell.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableTeamCell.java index 7b2f32a3dda..20baef7dfe9 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableTeamCell.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableTeamCell.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.startanalysis.rankingtable; +package com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.rankingtable; import com.google.gwt.cell.client.AbstractCell; import com.google.gwt.cell.client.Cell; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableTeamCollumn.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableTeamCollumn.java similarity index 83% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableTeamCollumn.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableTeamCollumn.java index b3fc3121acf..9ad2d1c776f 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/rankingtable/StartAnalysisStartRankTableTeamCollumn.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startanalysis/rankingtable/StartAnalysisStartRankTableTeamCollumn.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.startanalysis.rankingtable; +package com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.rankingtable; import com.google.gwt.user.cellview.client.Column; import com.sap.sse.common.Util.Pair; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartLineAdvantageComponent.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/course/StartLineAdvantageByGeometryWidget.gss similarity index 76% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartLineAdvantageComponent.css rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/course/StartLineAdvantageByGeometryWidget.gss index 93008d74441..77918068ae3 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartLineAdvantageComponent.css +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/course/StartLineAdvantageByGeometryWidget.gss @@ -1,4 +1,4 @@ -@CHARSET "UTF-8"; +@require 'theme'; .startLineAdvantageComponent_liveAveragePanel { bottom: 5pt; @@ -19,12 +19,12 @@ bottom: 20%; } -.startLineAdvantageComponent_middleLine{ - top: 35% +.startLineAdvantageComponent_middleLine { + top: 35%; bottom: 20%; } -.startLineAdvantageComponent_wrapper{ +.startLineAdvantageComponent_wrapper { position: absolute; width: 100%; height: 100%; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/course/StartLineAdvantageByGeometryWidget.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/course/StartLineAdvantageByGeometryWidget.java new file mode 100644 index 00000000000..e930a70fa76 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/course/StartLineAdvantageByGeometryWidget.java @@ -0,0 +1,82 @@ +package com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.course; + +import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.google.gwt.i18n.client.NumberFormat; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.sap.sailing.dashboards.gwt.client.DashboardClientFactory; +import com.sap.sailing.dashboards.gwt.client.actions.GetStartlineAdvantageByGeometryAction; +import com.sap.sailing.dashboards.gwt.client.widgets.PollsLiveDataEvery5Seconds; +import com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.util.LiveAverageComponent; +import com.sap.sailing.dashboards.gwt.shared.DashboardURLParameters; +import com.sap.sailing.dashboards.gwt.shared.dto.StartLineAdvantageDTO; +import com.sap.sailing.gwt.ui.client.StringMessages; + +/** + * The purpose of the class is to display the live and average start line advantage either by wind or by geometry. There + * is only one advantage display at once, so the user can switch between these following two + * {@link StartLineAdvantageComponentState}s {@link StartLineAdvantageComponentStateShowsAdvantageByWind} and + * {@link StartLineAdvantageComponentStateShowsAdvantageByGeometry} by tabing somewhere at the widget. The class extends + * from {@link LiveAverageComponent} to get necessary Ui Elements but customizes these with own CSS. + * + * @author Alexander Ries (D062114) + * + */ +public class StartLineAdvantageByGeometryWidget extends LiveAverageComponent implements PollsLiveDataEvery5Seconds { + + private DashboardClientFactory dashboardClientFactory; + + private static StringMessages stringConstants = StringMessages.INSTANCE; + private static final Logger logger = Logger.getLogger(StartLineAdvantageByGeometryWidget.class.getName()); + + public StartLineAdvantageByGeometryWidget(DashboardClientFactory dashboardClientFactory) { + super(stringConstants.dashboardStartlineAdvantageByGeometry(), "m"); + this.dashboardClientFactory = dashboardClientFactory; + StartLineAdvantageByGeometryWidgetRessources.INSTANCE.gss().ensureInjected(); + this.header.setInnerText(stringConstants.dashboardStartlineAdvantageByGeometry()); + this.header.addClassName(StartLineAdvantageByGeometryWidgetRessources.INSTANCE.gss().startLineAdvantageComponent_header()); + liveAveragePanel.getElement().addClassName(StartLineAdvantageByGeometryWidgetRessources.INSTANCE.gss().startLineAdvantageComponent_liveAveragePanel()); + livePanel.getElement().addClassName(StartLineAdvantageByGeometryWidgetRessources.INSTANCE.gss().startLineAdvantageComponent_livePanel()); + middleLine.getElement().addClassName(StartLineAdvantageByGeometryWidgetRessources.INSTANCE.gss().startLineAdvantageComponent_middleLine()); + averagePanel.getElement().addClassName(StartLineAdvantageByGeometryWidgetRessources.INSTANCE.gss().startLineAdvantageComponent_averagePanel()); + this.liveLabel.setInnerHTML(stringConstants.dashboardLiveWind()); + this.averageLabel.setInnerHTML(stringConstants.dashboardAverageWind()+"
"+stringConstants.dashboardAverageWindMinutes(15)); + registerForDashboardFiveSecondsTimer(dashboardClientFactory); + } + + @Override + public void timeChanged(Date newTime, Date oldTime) { + String leaderboardNameParameterValue = DashboardURLParameters.LEADERBOARD_NAME.getValue(); + if (leaderboardNameParameterValue != null) { + dashboardClientFactory.getDispatch().execute( + new GetStartlineAdvantageByGeometryAction(leaderboardNameParameterValue), + new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + logger.log(Level.INFO, "Failed to received startline advantage by geometry"); + } + + @Override + public void onSuccess(StartLineAdvantageDTO result) { + if (result.startLineAdvantage != null) { + logger.log(Level.INFO, "Updating UI with RibDashboardRaceInfoDTO.startLineAdvantageDTO"); + setLiveValue(NumberFormat.getFormat("#0.0").format(result.startLineAdvantage.doubleValue())); + setAverageValue(NumberFormat.getFormat("#0.0").format(result.average.doubleValue())); + } else { + logger.log(Level.INFO, "RibDashboardRaceInfoDTO.startLineAdvantageDTO is 0"); + } + } + }); + } + } + + @Override + public void registerForDashboardFiveSecondsTimer(DashboardClientFactory dashboardClientFactory) { + if (dashboardClientFactory != null) { + dashboardClientFactory.getDashboardFiveSecondsTimer().addTimeListener(this); + } + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartLineAdvantageComponentRessources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/course/StartLineAdvantageByGeometryWidgetRessources.java similarity index 53% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartLineAdvantageComponentRessources.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/course/StartLineAdvantageByGeometryWidgetRessources.java index 0633f3c9dc0..ccbc0fe1578 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartLineAdvantageComponentRessources.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/course/StartLineAdvantageByGeometryWidgetRessources.java @@ -1,18 +1,19 @@ -package com.sap.sailing.dashboards.gwt.client.startlineadvantage; +package com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.course; import com.google.gwt.core.client.GWT; import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.CssResource; import com.google.gwt.resources.client.CssResource.Shared; -public interface StartLineAdvantageComponentRessources extends ClientBundle { - public static final StartLineAdvantageComponentRessources INSTANCE = GWT.create(StartLineAdvantageComponentRessources.class); +public interface StartLineAdvantageByGeometryWidgetRessources extends ClientBundle { + + public static final StartLineAdvantageByGeometryWidgetRessources INSTANCE = GWT.create(StartLineAdvantageByGeometryWidgetRessources.class); - @Source("StartLineAdvantageComponent.css") - LocalCss css(); + @Source({"com/sap/sailing/dashboards/gwt/client/theme/theme.gss", "StartLineAdvantageByGeometryWidget.gss"}) + StartLineAdvantageByGeometryGss gss(); @Shared - public interface LocalCss extends CssResource { + public interface StartLineAdvantageByGeometryGss extends CssResource { public String startLineAdvantageComponent_liveAveragePanel(); public String startLineAdvantageComponent_header(); diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/LiveAverageComponent.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/util/LiveAverageComponent.gss similarity index 56% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/LiveAverageComponent.css rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/util/LiveAverageComponent.gss index 62094360316..cdeb1373791 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/LiveAverageComponent.css +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/util/LiveAverageComponent.gss @@ -1,5 +1,6 @@ +@require 'theme'; -.liveAverageCompoment_panel { +.live_average_component { position: absolute; left: 0px; right: 0px; @@ -7,7 +8,7 @@ bottom: 0px; } -.liveAverageCompoment_header_container { +.header_container { position: absolute; left: 0px; right: 0px; @@ -15,20 +16,20 @@ height: 35%; } -.liveAverageCompoment_header { +.header { height: 100%; margin-top: 5pt; line-height: 15pt; vertical-align: middle; font-size: 13pt; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; width: 100%; text-align: center; overflow: visible; font-weight: bold; } -.liveAverageCompoment_live_container { +.live_container { position: absolute; top: 35%; bottom: 30%; @@ -36,7 +37,7 @@ left: 0%; } -.liveAverageCompoment_average_container { +.average_container { position: absolute; top: 35%; bottom: 30%; @@ -44,7 +45,7 @@ left: 52%; } -.liveAverageCompoment_middle_line { +.middle_line { position: absolute; top: 35%; height: 30pt; @@ -54,42 +55,42 @@ z-index: 100; } -.liveAverageCompoment_panel_value_number { - font-family: 'Open Sans', Arial, Verdana, sans-serif; +.panel_value_number { + font-family: DASHBOARD_FONT_FAMILY; font-size: 26pt; } -.liveAverageCompoment_panel_value_unit { - font-family: 'Open Sans', Arial, Verdana, sans-serif; +.panel_value_unit { + font-family: DASHBOARD_FONT_FAMILY; font-size: 15pt; } -.liveAverageCompoment_panel_value_unit_degrees { +.panel_value_unit_degrees { position: absolute; font-size: 20pt; font-weight: lighter; } -.liveAverageCompoment_value_panel { +.value_panel { margin: 0px; width: 100%; height: 90%; text-align: center; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; font-weight: bolder; } -.liveAverageCompoment_label_text { +.label_text { margin: 0px; width: 100%; height: 100%; text-align: center; font-size: 11pt; color: grey; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; } -.liveAverageCompoment_liveLabelContainer { +.live_label_container { position: absolute; bottom: 0px; left: 0px; @@ -97,7 +98,7 @@ height: 35%; } -.liveAverageCompoment_averageLabelContainer { +.average_label_container { position: absolute; bottom: 0px; right: 0px; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/LiveAverageComponent.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/util/LiveAverageComponent.java similarity index 63% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/LiveAverageComponent.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/util/LiveAverageComponent.java index 9afcaf508d3..dd976dc9f0a 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/LiveAverageComponent.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/util/LiveAverageComponent.java @@ -1,25 +1,24 @@ -package com.sap.sailing.dashboards.gwt.client.startlineadvantage; +package com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.util; import java.util.Iterator; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.SpanElement; -import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; 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.visualeffects.NumberTickingAnimation; -import com.sap.sailing.dashboards.gwt.client.windchart.VerticalWindChartClickListener; -import com.sap.sailing.dashboards.gwt.client.windchart.WindBotComponent; +import com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.course.StartLineAdvantageByGeometryWidget; +import com.sap.sailing.dashboards.gwt.client.widgets.windbot.WindBotWidget; +import com.sap.sailing.dashboards.gwt.client.widgets.windbot.charts.VerticalWindChartClickListener; import com.sap.sailing.gwt.ui.client.StringMessages; /** * The purpose of the class is to display a live and an average value of a continuously updating data source. - * {@link StartLineAdvantageByGeometryComponent} extends from it and the class {@link WindBotComponent} uses it to display wind + * {@link StartLineAdvantageByGeometryWidget} extends from it and the class {@link WindBotWidget} uses it to display wind * data. * * @author Alexander Ries (D062114) @@ -31,17 +30,12 @@ public class LiveAverageComponent extends Composite implements HasWidgets, Verti interface LiveAverageComponentUiBinder extends UiBinder { } - - interface LiveAverageComponentStyle extends CssResource { - - String liveAverageCompoment_panel_value_unit_degrees(); - } @UiField - HTMLPanel liveAveragePanel; + public HTMLPanel liveAveragePanel; @UiField - DivElement header; + public DivElement header; @UiField SpanElement liveNumber; @@ -56,28 +50,24 @@ public class LiveAverageComponent extends Composite implements HasWidgets, Verti SpanElement averageUnit; @UiField - DivElement liveLabel; + public DivElement liveLabel; @UiField - DivElement averageLabel; + public DivElement averageLabel; @UiField - HTMLPanel livePanel; + public HTMLPanel livePanel; @UiField - HTMLPanel middleLine; + public HTMLPanel middleLine; @UiField - HTMLPanel averagePanel; - - @UiField - LiveAverageComponentStyle style; + public HTMLPanel averagePanel; private StringMessages stringConstants; - private NumberTickingAnimation liveTickingAnimation; - private NumberTickingAnimation averageTickingAnimation; public LiveAverageComponent() { + LiveAverageComponentResources.INSTANCE.gss().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); } @@ -89,8 +79,8 @@ public class LiveAverageComponent extends Composite implements HasWidgets, Verti * * */ public LiveAverageComponent(String header, String unit) { + LiveAverageComponentResources.INSTANCE.gss().ensureInjected(); stringConstants = StringMessages.INSTANCE; - initTickingAnimations(); initWidget(uiBinder.createAndBindUi(this)); liveAveragePanel.getElement().getStyle().setProperty("backgroundColor", "white"); this.header.setInnerText(header); @@ -98,37 +88,19 @@ public class LiveAverageComponent extends Composite implements HasWidgets, Verti this.averageUnit.setInnerText(unit); // Lifts the degrees unit string "°". Otherwise it would be too small. if (unit.equals("°")) { - this.liveUnit.addClassName(style.liveAverageCompoment_panel_value_unit_degrees()); - this.averageUnit.setClassName(style.liveAverageCompoment_panel_value_unit_degrees()); + this.liveUnit.addClassName(LiveAverageComponentResources.INSTANCE.gss().panel_value_unit_degrees()); + this.averageUnit.setClassName(LiveAverageComponentResources.INSTANCE.gss().panel_value_unit_degrees()); } this.liveLabel.setInnerHTML(stringConstants.dashboardLiveWind()); this.averageLabel.setInnerHTML(stringConstants.dashboardAverageWind()+"
"+stringConstants.dashboardAverageWindMinutes(15)); } - - private void initTickingAnimations() { - liveTickingAnimation = new NumberTickingAnimation() { - - @Override - public void setValueInUI(String value) { - liveNumber.setInnerText(value); - } - }; - - averageTickingAnimation = new NumberTickingAnimation() { - - @Override - public void setValueInUI(String value) { - averageNumber.setInnerText(value); - } - }; - } public void setLiveValue(String liveValue) { - liveTickingAnimation.execute(liveValue); + liveNumber.setInnerText(liveValue); } public void setAverageValue(String averageValue) { - averageTickingAnimation.execute(averageValue); + averageNumber.setInnerText(averageValue); } @Override diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/util/LiveAverageComponent.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/util/LiveAverageComponent.ui.xml new file mode 100644 index 00000000000..907458fd311 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/util/LiveAverageComponent.ui.xml @@ -0,0 +1,41 @@ + + + + + + + + +
+
+ + +
+ + +
+
+ + + + + + +
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
\ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/util/LiveAverageComponentResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/util/LiveAverageComponentResources.java new file mode 100644 index 00000000000..2809a676b98 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/util/LiveAverageComponentResources.java @@ -0,0 +1,33 @@ +package com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.util; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; + +/** + * @author Alexander Ries (D062114) + * + */ +public interface LiveAverageComponentResources extends ClientBundle { + + public static final LiveAverageComponentResources INSTANCE = GWT.create(LiveAverageComponentResources.class); + + @Source({"com/sap/sailing/dashboards/gwt/client/theme/theme.gss", "LiveAverageComponent.gss"}) + LiveAverageComponentGss gss(); + + interface LiveAverageComponentGss extends CssResource { + String live_average_component(); + String header(); + String header_container(); + String live_container(); + String average_container(); + String middle_line(); + String panel_value_number(); + String panel_value_unit(); + String panel_value_unit_degrees(); + String value_panel(); + String label_text(); + String live_label_container(); + String average_label_container(); + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesByWindComponentStyle.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/StartlineAdvantagesByWindWidget.gss similarity index 78% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesByWindComponentStyle.css rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/StartlineAdvantagesByWindWidget.gss index d6d6da58539..3d15fb8ff12 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesByWindComponentStyle.css +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/StartlineAdvantagesByWindWidget.gss @@ -1,6 +1,6 @@ -@CHARSET "UTF-8"; +@require 'theme'; -.startline_advantages_by_wind_component_container{ +.start_line_advantages_by_wind_component{ position: absolute; height: 100%; width: 100%; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/StartlineAdvantagesByWindWidget.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/StartlineAdvantagesByWindWidget.java new file mode 100644 index 00000000000..c54b0cc2482 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/StartlineAdvantagesByWindWidget.java @@ -0,0 +1,127 @@ +package com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.wind; + +import java.util.Date; +import java.util.Iterator; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.i18n.client.NumberFormat; +import com.google.gwt.resources.client.CssResource; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HasWidgets; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.dashboards.gwt.client.DashboardClientFactory; +import com.sap.sailing.dashboards.gwt.client.actions.GetStartlineAdvantagesByWindAction; +import com.sap.sailing.dashboards.gwt.client.widgets.PollsLiveDataEvery5Seconds; +import com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.util.LiveAverageComponent; +import com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.wind.charts.StartlineAdvantagesOnLineChart; +import com.sap.sailing.dashboards.gwt.shared.DashboardURLParameters; +import com.sap.sailing.dashboards.gwt.shared.dto.StartlineAdvantagesWithMaxAndAverageDTO; +import com.sap.sailing.gwt.ui.client.StringMessages; + +/** + * @author Alexander Ries (D062114) + * + */ +public class StartlineAdvantagesByWindWidget extends Composite implements HasWidgets, PollsLiveDataEvery5Seconds { + + private static StartlineAdvantagesByWindComponentUiBinder uiBinder = GWT + .create(StartlineAdvantagesByWindComponentUiBinder.class); + + interface StartlineAdvantagesByWindComponentUiBinder extends UiBinder { + } + + interface StartlineAdvantagesByWindComponentStyle extends CssResource { + + } + + @UiField(provided = true) + LiveAverageComponent advantageMaximumLiveAverage; + + @UiField(provided = true) + StartlineAdvantagesOnLineChart startlineAdvantagesOnLineChart; + + public DashboardClientFactory dashboardClientFactory; + private static final Logger logger = Logger.getLogger(StartlineAdvantagesByWindWidget.class.getName()); + + public StartlineAdvantagesByWindWidget(DashboardClientFactory dashboardClientFactory) { + StartlineAdvantagesByWindWidgetResources.INSTANCE.gss().ensureInjected(); + this.dashboardClientFactory = dashboardClientFactory; + startlineAdvantagesOnLineChart = new StartlineAdvantagesOnLineChart(); + advantageMaximumLiveAverage = new LiveAverageComponent(StringMessages.INSTANCE.dashboardStartlineAdvantagesByWind(), "m"); + advantageMaximumLiveAverage.header.getStyle().setFontSize(14, Unit.PT); + advantageMaximumLiveAverage.liveLabel.setInnerHTML("advantage max."); + advantageMaximumLiveAverage.averageLabel.setInnerHTML("advantage max. average "+StringMessages.INSTANCE.dashboardAverageWindMinutes(15)); + initWidget(uiBinder.createAndBindUi(this)); + registerForDashboardFiveSecondsTimer(dashboardClientFactory); + } + + private void loadData() { + logger.log(Level.INFO, "Executing GetStartlineAdvantagesAction"); + String leaderboardNameParameterValue = DashboardURLParameters.LEADERBOARD_NAME.getValue(); + if (leaderboardNameParameterValue != null) { + dashboardClientFactory.getDispatch().execute( + new GetStartlineAdvantagesByWindAction(leaderboardNameParameterValue), + new AsyncCallback() { + + @Override + public void onSuccess(StartlineAdvantagesWithMaxAndAverageDTO result) { + logger.log(Level.INFO, "Received StartlineAdvantagesWithMaxAndAverageDTO"); + if (result != null && result.maximum != null && result.average != null) { + logger.log(Level.INFO, "Updating UI with StartlineAdvantagesWithMaxAndAverageDTO"); + startlineAdvantagesOnLineChart.setStartlineAdvantagesAndConfidences(result.distanceToRCBoatToStartlineAdvantage, result.distanceToRCBoatToConfidence); + advantageMaximumLiveAverage.setLiveValue(NumberFormat.getFormat("#0.0").format( + result.maximum.doubleValue())); + advantageMaximumLiveAverage.setAverageValue(NumberFormat.getFormat("#0.0").format( + result.average.doubleValue())); + } else { + logger.log(Level.INFO, "StartlineAdvantagesWithMaxAndAverageDTO is null"); + } + } + + @Override + public void onFailure(Throwable caught) { + logger.log(Level.INFO, "Failed to received StartlineAdvantagesWithMaxAndAverageDTO, " + + caught.getMessage()); + } + }); + } + } + + @Override + public void timeChanged(Date newTime, Date oldTime) { + loadData(); + } + + @Override + public void registerForDashboardFiveSecondsTimer(DashboardClientFactory dashboardClientFactory) { + if (dashboardClientFactory != null) { + dashboardClientFactory.getDashboardFiveSecondsTimer().addTimeListener(this); + } + } + + @Override + public void add(Widget w) { + throw new UnsupportedOperationException("The method add(Widget w) is not supported."); + } + + @Override + public void clear() { + throw new UnsupportedOperationException("The method clear() is not supported."); + } + + @Override + public Iterator iterator() { + return null; + } + + @Override + public boolean remove(Widget w) { + return false; + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/StartlineAdvantagesByWindWidget.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/StartlineAdvantagesByWindWidget.ui.xml new file mode 100644 index 00000000000..4b8cd97fb6b --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/StartlineAdvantagesByWindWidget.ui.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/StartlineAdvantagesByWindWidgetResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/StartlineAdvantagesByWindWidgetResources.java new file mode 100644 index 00000000000..7b59113b6b6 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/StartlineAdvantagesByWindWidgetResources.java @@ -0,0 +1,23 @@ +package com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.wind; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; + +/** + * @author Alexander Ries (D062114) + * + */ +public interface StartlineAdvantagesByWindWidgetResources extends ClientBundle { + + public static final StartlineAdvantagesByWindWidgetResources INSTANCE = GWT.create(StartlineAdvantagesByWindWidgetResources.class); + + @Source({"com/sap/sailing/dashboards/gwt/client/theme/theme.gss", "StartlineAdvantagesByWindWidget.gss"}) + StartlineAdvantagesOnLineChartGSS gss(); + + public interface StartlineAdvantagesOnLineChartGSS extends CssResource { + String start_line_advantages_by_wind_component(); + String advantage_maximum_live_average(); + String advantages_on_line_chart_container(); + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesOnLineChartStyle.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/charts/StartlineAdvantagesOnLineChart.gss similarity index 50% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesOnLineChartStyle.css rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/charts/StartlineAdvantagesOnLineChart.gss index aacb90d9078..f6f89b4bb09 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesOnLineChartStyle.css +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/charts/StartlineAdvantagesOnLineChart.gss @@ -1,4 +1,4 @@ -@CHARSET "UTF-8"; +@require 'theme'; .advantages_on_line_chart_container { position: absolute !important; @@ -6,7 +6,7 @@ bottom: 50px; left: 0px; right: 0px; - font-family: 'Open Sans', Arial, Verdana, sans-serif !important; + font-family: DASHBOARD_FONT_FAMILY !important; } .confidence_bar_container { @@ -23,12 +23,12 @@ left: 15px; right: 15px; height: 15px; - background: -moz-linear-gradient(left, #FFDD00 0%, #008FFF 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left bottom, right bottom, color-stop(0%,#FFDD00), color-stop(100%,#008FFF)); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(left, #FFDD00 0%,#008FFF 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(left, #FFDD00 0%,#008FFF 100%); /* Opera 11.10+ */ - background: -ms-linear-gradient(left, #FFDD00 0%,#008FFF 100%); /* IE10+ */ - background: linear-gradient(to right, #FFDD00 0%,#008FFF 100%); /* W3C */ + /* @alternate */ background: -moz-linear-gradient(left, #FFDD00 0%, #008FFF 100%); /* FF3.6+ */ + /* @alternate */ background: -webkit-gradient(linear, left bottom, right bottom, color-stop(0%,#FFDD00), color-stop(100%,#008FFF)); /* Chrome,Safari4+ */ + /* @alternate */ background: -webkit-linear-gradient(left, #FFDD00 0%,#008FFF 100%); /* Chrome10+,Safari5.1+ */ + /* @alternate */ background: -o-linear-gradient(left, #FFDD00 0%,#008FFF 100%); /* Opera 11.10+ */ + /* @alternate */ background: -ms-linear-gradient(left, #FFDD00 0%,#008FFF 100%); /* IE10+ */ + /* @alternate */ background: linear-gradient(to right, #FFDD00 0%,#008FFF 100%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFDD00', endColorstr='#008FFF',GradientType=0 ); /* IE6*/ } @@ -42,7 +42,7 @@ font-size: 11px; text-align: center; vertical-align: center; - font-family: 'Open Sans', Arial, Verdana, sans-serif !important; + font-family: DASHBOARD_FONT_FAMILY !important; } .confidence_bar_label { @@ -50,7 +50,7 @@ top: 20px; font-size: 12px; color: grey; - font-family: 'Open Sans', Arial, Verdana, sans-serif !important; + font-family: DASHBOARD_FONT_FAMILY !important; } .confidence_bar_min_label { diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesOnLineChart.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/charts/StartlineAdvantagesOnLineChart.java similarity index 55% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesOnLineChart.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/charts/StartlineAdvantagesOnLineChart.java index 6c68e0f9e05..6a6ed9ac540 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startlineadvantage/StartlineAdvantagesOnLineChart.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/charts/StartlineAdvantagesOnLineChart.java @@ -1,17 +1,15 @@ -package com.sap.sailing.dashboards.gwt.client.startlineadvantage; +package com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.wind.charts; import java.util.Iterator; -import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; -import org.moxieapps.gwt.highcharts.client.Animation; -import org.moxieapps.gwt.highcharts.client.Animation.Easing; import org.moxieapps.gwt.highcharts.client.AxisTitle; import org.moxieapps.gwt.highcharts.client.Chart; import org.moxieapps.gwt.highcharts.client.Color; import org.moxieapps.gwt.highcharts.client.Credits; import org.moxieapps.gwt.highcharts.client.Legend; import org.moxieapps.gwt.highcharts.client.PlotLine.DashStyle; -import org.moxieapps.gwt.highcharts.client.Point; import org.moxieapps.gwt.highcharts.client.Series; import org.moxieapps.gwt.highcharts.client.Style; import org.moxieapps.gwt.highcharts.client.ToolTip; @@ -31,9 +29,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.shared.dto.StartLineAdvantageDTO; +import com.sap.sailing.dashboards.gwt.client.util.HighchartsUtil; import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sse.common.Util.Pair; /** * @author Alexander Ries (D062114) @@ -63,28 +60,32 @@ public class StartlineAdvantagesOnLineChart extends Composite implements HasWidg private Chart chart; private Series series; - - private static final int POINT_ADDING_ANIMATION_DURATION_IN_MILLIS = 2000; + private static final Logger logger = Logger.getLogger(StartlineAdvantagesOnLineChart.class.getName()); public StartlineAdvantagesOnLineChart() { + StartlineAdvantagesOnLineChartResources.INSTANCE.gss().ensureInjected(); initWidget(uiBinder.createAndBindUi(this)); initAndAddChart(); setConfidenceColorBarLabelValues(); - //TODO Remove and centralize data retrieving + } + + public void setStartlineAdvantagesAndConfidences(Number [][] distanceToRCBoatToStartlineAdvantages, Number [][] distanceToRCBoatToConfidences) { + if (distanceToRCBoatToStartlineAdvantages != null) { + series.setPoints(distanceToRCBoatToStartlineAdvantages, true); + } + setConfidenceGradientColorToSeries(series, distanceToRCBoatToConfidences); + chart.redraw(); } private void initAndAddChart() { chart = initChart(); - /** - * Highcharts default chart element spacing is not consistent - * so there is a need to correct the right spacing - * of the chart to make it look visually right. - * */ - setCorrectChartSpacing(chart); + HighchartsUtil.correctSpacingOfChart(chart); setXAxisOfChart(chart); setYAxisOfChart(chart); series = createSeries(chart); + chart.addSeries(series); chartContainer.add(chart); + HighchartsUtil.setSizeToMatchContainerDelayed(chart); } private Chart initChart() { @@ -97,22 +98,16 @@ public class StartlineAdvantagesOnLineChart extends Composite implements HasWidg .setBackgroundColor("#FFFFFF") .setBorderColor("#FFFFFF") .setPlotShadow(false) + .setWidth100() + .setHeight100() .setPlotBorderColor("#FFFFFF") .setOption("/exporting/enabled", false) .setShadow(false) .setStyle(new Style().setPosition("absolute").setTop("0px").setBottom("0px").setLeft("0px").setRight("0px")) .setAnimation(true); - chart.setSize("100%", "100%"); - chart.setSizeToMatchContainer(); return chart; } - private void setCorrectChartSpacing(Chart chart){ - chart.setSpacingTop(17) - .setSpacingBottom(13) - .setSpacingRight(35); - } - private void setXAxisOfChart(Chart chart){ chart.getXAxis() .setAxisTitle(new AxisTitle().setText(StringMessages.INSTANCE.dashboardDistanceToRCBoat()).setStyle(new Style().setFontFamily("Open Sans") @@ -156,10 +151,9 @@ public class StartlineAdvantagesOnLineChart extends Composite implements HasWidg Series series = chart .createSeries() .setName(null) - .setPlotOptions( - new AreaPlotOptions().setDashStyle(DashStyle.SOLID).setLineWidth(1) + .setPlotOptions(new AreaPlotOptions().setDashStyle(DashStyle.SOLID).setLineWidth(1) .setMarker(new Marker().setEnabled(false)).setShadow(false).setHoverStateEnabled(false) - .setLineColor("#FFFFFF").setFillColor("#FFFFFF")); + .setLineColor("white").setFillColor("white")); return series; } @@ -170,71 +164,18 @@ public class StartlineAdvantagesOnLineChart extends Composite implements HasWidg } private String getAxisLabelValueForLabelData(double labelData) { - String result = String.valueOf(labelData); - com.sap.sse.common.Util.Pair firstAndLastXValue = getFirstnAndLastXValueOfSeries(); - if (firstAndLastXValue != null && firstAndLastXValue.getA() != null && firstAndLastXValue.getB() != null) { - chart.getXAxis().setTickInterval(firstAndLastXValue.getB()/2); - if (labelData == firstAndLastXValue.getA().doubleValue()) { - result = StringMessages.INSTANCE.dashboardRCBoat(); - } else if (labelData == firstAndLastXValue.getB().doubleValue()) { - result = StringMessages.INSTANCE.dashboardPinEnd(); - } - } - return result; - } - - private com.sap.sse.common.Util.Pair getFirstnAndLastXValueOfSeries(){ - if(series != null && - series.getPoints() != null && - series.getPoints().length > 1){ - Double firstValue = new Double(series.getPoints()[0].getX().doubleValue()); - Double lastValue = new Double(series.getPoints()[series.getPoints().length-1].getX().doubleValue()); - com.sap.sse.common.Util.Pair firstAndLastXValue = new Pair(firstValue, lastValue); - return firstAndLastXValue; - }else{ - return null; + if(labelData != 0) { + return labelData+""; + }else { + return "RC Boat"; } } - public void setStartlineAdvantages(List startlineAdvantages) { - if (startlineAdvantages != null) { - if (series.getPoints() != null && series.getPoints().length > 0) { - updateStartlineAdvantages(startlineAdvantages, series); - } else { - addStartlineAdvantages(startlineAdvantages, series); - chart.addSeries(series, true, new Animation().setDuration(POINT_ADDING_ANIMATION_DURATION_IN_MILLIS).setEasing(Easing.SWING)); - } - } - chart.setSizeToMatchContainer(); - } - - private void updateStartlineAdvantages(List startlineAdvantages, Series series) { - removeAllSeriesPoints(chart.getSeries()[0]); - addStartlineAdvantages(startlineAdvantages, series); - } - - private void removeAllSeriesPoints(Series series) { - for (Point point : series.getPoints()) { - series.removePoint(point); - } - } - - private void addStartlineAdvantages(List startlineAdvantages, Series series){ - //TODO Build this with forEach consumer as soon as the bundle uses GWT 2.8 with Java 8 Support. - for (StartLineAdvantageDTO startlineAdvantage : startlineAdvantages) { - Point point = new Point(startlineAdvantage.distanceToRCBoatInMeters, startlineAdvantage.startLineAdvantage); - series.addPoint(point, false, false, false); - } - setConfidenceGradientColorToSeries(series, startlineAdvantages); - chart.redraw(); - } - - private void setConfidenceGradientColorToSeries(Series series, List startlineAdvantages) { - Color confidenceGradientColor = ConfidenceColorCalculator.getColorWithConfidenceGradients(startlineAdvantages); - series.setPlotOptions( - new AreaPlotOptions().setDashStyle(DashStyle.SOLID).setLineWidth(1) - .setMarker(new Marker().setEnabled(false)).setShadow(false).setHoverStateEnabled(false) - .setLineColor("#FFFFFF").setFillColor(confidenceGradientColor)); + private void setConfidenceGradientColorToSeries(Series series, Number [][] distanceToRCBoatToConfidences) { + Color confidenceGradientColor = ConfidenceColorCalculator.getColorWithConfidenceGradients(distanceToRCBoatToConfidences); + String fillColor = confidenceGradientColor.getOptions().toString(); + logger.log(Level.INFO, fillColor); + series.updateSeriesFillColor(fillColor); } @Override @@ -261,26 +202,21 @@ public class StartlineAdvantagesOnLineChart extends Composite implements HasWidg private static final String LOW_CONFIDENCE_COLOR_AS_HEX = "#43cea2"; private static final String HIGHT_CONFIDENCE_COLOR_AS_HEX = "#008FFF"; - public static Color getColorWithConfidenceGradients(List startlineAdvantages) { + public static Color getColorWithConfidenceGradients(Number [][] distanceToRCBoatToConfidences) { Color color = new Color().setLinearGradient(200, 0, 0, 0); - double lineLenght = getBiggestDistanceToRCBoat(startlineAdvantages); - //TODO Need to find a prettier way of at adding color stops - double lastConfidence = 2; - for (StartLineAdvantageDTO startlineAdvantageDTO : startlineAdvantages) { - if (lastConfidence != startlineAdvantageDTO.confidence) { - lastConfidence = startlineAdvantageDTO.confidence; - double gradientPosition = getGradientStopPositionFromStartlineLenghtAndDistanceToRCBoat(lineLenght, - startlineAdvantageDTO.distanceToRCBoatInMeters); - color.addColorStop(gradientPosition, getColorAsHexStringFromConfidence(startlineAdvantageDTO.confidence)); + int previousIndex = 0; + for (int i = 0; i < distanceToRCBoatToConfidences.length; i++) { + double previousConfidence = distanceToRCBoatToConfidences[previousIndex][1].doubleValue(); + double currentConfidence = distanceToRCBoatToConfidences[i][1].doubleValue(); + if (previousConfidence != currentConfidence || i == 0) { + logger.log(Level.INFO, previousConfidence+" "+currentConfidence); + color.addColorStop(i, getColorAsHexStringFromConfidence(distanceToRCBoatToConfidences[i][0].doubleValue())); } + previousIndex++; } return color; } - private static double getGradientStopPositionFromStartlineLenghtAndDistanceToRCBoat(double startlineLenght, double distanceToRCBoat) { - return distanceToRCBoat/startlineLenght; - } - private static String getColorAsHexStringFromConfidence(double position) { if(position > 0.6) { return HIGHT_CONFIDENCE_COLOR_AS_HEX; @@ -288,10 +224,5 @@ public class StartlineAdvantagesOnLineChart extends Composite implements HasWidg return LOW_CONFIDENCE_COLOR_AS_HEX; } } - - private static double getBiggestDistanceToRCBoat(List startlineAdvantages) { - StartLineAdvantageDTO startlineAdvantageDTO = startlineAdvantages.get(startlineAdvantages.size()-1); - return startlineAdvantageDTO.distanceToRCBoatInMeters; - } } } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/charts/StartlineAdvantagesOnLineChart.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/charts/StartlineAdvantagesOnLineChart.ui.xml new file mode 100644 index 00000000000..ce8b9fcc78b --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/charts/StartlineAdvantagesOnLineChart.ui.xml @@ -0,0 +1,16 @@ + + + + + + + +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/charts/StartlineAdvantagesOnLineChartResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/charts/StartlineAdvantagesOnLineChartResources.java new file mode 100644 index 00000000000..aee914f6eef --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/startlineadvantage/wind/charts/StartlineAdvantagesOnLineChartResources.java @@ -0,0 +1,27 @@ +package com.sap.sailing.dashboards.gwt.client.widgets.startlineadvantage.wind.charts; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; + +/** + * @author Alexander Ries (D062114) + * + */ +public interface StartlineAdvantagesOnLineChartResources extends ClientBundle { + + public static final StartlineAdvantagesOnLineChartResources INSTANCE = GWT.create(StartlineAdvantagesOnLineChartResources.class); + + @Source({"com/sap/sailing/dashboards/gwt/client/theme/theme.gss", "StartlineAdvantagesOnLineChart.gss"}) + StartlineAdvantagesOnLineChartGSS gss(); + + public interface StartlineAdvantagesOnLineChartGSS extends CssResource { + String advantages_on_line_chart_container(); + String confidence_bar_container(); + String confidence_bar(); + String confidence_bar_header(); + String confidence_bar_label(); + String confidence_bar_min_label(); + String confidence_bar_max_label(); + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/WindBotComponentStyle.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/WindBotWidget.gss similarity index 67% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/WindBotComponentStyle.css rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/WindBotWidget.gss index 799c6df9a76..3443715463a 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/WindBotComponentStyle.css +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/WindBotWidget.gss @@ -1,18 +1,18 @@ -@CHARSET "UTF-8"; +@require 'theme'; -.windBotComponent{ +.wind_bot_component{ position: absolute; height: 100%; width: 100%; z-index: 5; } -.windBotNamePanel { +.name_panel { height: 45pt; line-height: 45pt; vertical-align: middle; font-size: 14pt; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; width: 100%; text-align: center; font-weight: bold; @@ -20,7 +20,7 @@ background-color: white; } -.wind_bot_component_live_average_container { +.live_average_container { position: absolute; border: none; border-radius: 0pt; @@ -29,17 +29,17 @@ bottom: 65%; } -.wind_bot_component_left { +.left { left: 0pt; right: 50%; } -.wind_bot_component_right { +.right { left: 50%; right: 0pt; } -.wind_bot_component_windchart_container { +.windchart_container { position: absolute; border: none; border-radius: 0pt; @@ -48,7 +48,7 @@ bottom: 0pt; } -.wind_bot_component_windchart{ +.windchart{ position: absolute; left: 0pt; right: 0pt; @@ -56,7 +56,7 @@ bottom: 0pt; } -.wind_bot_component_compass_container{ +.compass_container{ position: absolute; height: 45pt; width: 45pt; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/WindBotComponent.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/WindBotWidget.java similarity index 54% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/WindBotComponent.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/WindBotWidget.java index acba0c39e09..5794821f6ff 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/WindBotComponent.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/WindBotWidget.java @@ -1,33 +1,30 @@ -package com.sap.sailing.dashboards.gwt.client.windchart; +package com.sap.sailing.dashboards.gwt.client.widgets.windbot; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import org.moxieapps.gwt.highcharts.client.Point; - import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.i18n.client.NumberFormat; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; -import com.google.gwt.user.client.Window; 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.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.client.widgets.startlineadvantage.util.LiveAverageComponent; +import com.sap.sailing.dashboards.gwt.client.widgets.windbot.charts.VerticalWindChart; +import com.sap.sailing.dashboards.gwt.client.widgets.windbot.compass.LocationPointerCompass; import com.sap.sailing.dashboards.gwt.shared.MovingAverage; -import com.sap.sailing.dashboards.gwt.shared.SinWave; import com.sap.sailing.dashboards.gwt.shared.WindType; import com.sap.sailing.domain.common.WindSource; import com.sap.sailing.domain.common.WindSourceType; +import com.sap.sailing.gwt.dispatch.client.batching.SplitScheduler; import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.client.shared.charts.ChartPointRecalculator; import com.sap.sailing.gwt.ui.shared.WindDTO; import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO; import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO; @@ -42,20 +39,15 @@ import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO; * @author Alexander Ries (D062114) * */ -public class WindBotComponent extends Composite implements HasWidgets, WindBotDataRetrieverListener { - - private SinWave speedSinWave; - private SinWave directionSinWave; - private boolean inSimulationMode; +public class WindBotWidget extends Composite implements HasWidgets, WindBotDataRetrieverListener { private MovingAverage movingAverageSpeed; private MovingAverage movingAverageDirection; - private static WindBotComponentUiBinder uiBinder = GWT.create(WindBotComponentUiBinder.class); - private static final String IN_SIMULATION_MODE = "simulation"; - private static final Logger logger = Logger.getLogger(WindBotComponent.class.getName()); + private static WindBotWidgetUiBinder uiBinder = GWT.create(WindBotWidgetUiBinder.class); + private static final Logger logger = Logger.getLogger(WindBotWidget.class.getName()); - interface WindBotComponentUiBinder extends UiBinder { + interface WindBotWidgetUiBinder extends UiBinder { } interface WindBotComponentStyle extends CssResource { @@ -109,17 +101,10 @@ public class WindBotComponent extends Composite implements HasWidgets, WindBotDa private StringMessages stringConstants; private final static String UNIT_WIND_DIRECTION = "°"; - public WindBotComponent(String windBotId) { + public WindBotWidget(String windBotId) { + WindBotWidgetResources.INSTANCE.gss().ensureInjected(); this.windBotId = windBotId; stringConstants = StringMessages.INSTANCE; - String inSimulationModeParameter = Window.Location.getParameter(IN_SIMULATION_MODE); - if (inSimulationModeParameter != null && inSimulationModeParameter.equals("true")) { - inSimulationMode = true; - this.speedSinWave = new SinWave(50, 8); - this.directionSinWave = new SinWave(100, 8); - } else { - inSimulationMode = false; - } movingAverageSpeed = new MovingAverage(500); movingAverageDirection = new MovingAverage(500); trueWindSpeedLiveAverageComponent = new LiveAverageComponent(stringConstants.dashboardTrueWindSpeed(), stringConstants.dashboardTrueWindSpeedUnit()); @@ -169,30 +154,42 @@ public class WindBotComponent extends Composite implements HasWidgets, WindBotDa * */ @Override public void updateWindBotUI(WindInfoForRaceDTO windInfoForRaceDTO) { - logger.log(Level.INFO, "WindBotComponent with id "+windBotId+" got notified about new WindInfoForRaceDTO"); + logger.log(Level.INFO, "WindBotComponent with id " + windBotId + " got notified about new WindInfoForRaceDTO"); if (windInfoForRaceDTO != null) { - WindTrackInfoDTO windTrackInfoDTO = getWindTrackInfoDTOFromAndWindBotID(windInfoForRaceDTO, windBotId); + final WindTrackInfoDTO windTrackInfoDTO = getWindTrackInfoDTOFromAndWindBotID(windInfoForRaceDTO, windBotId); if (windTrackInfoDTO != null) { - logger.log(Level.INFO, "WindInfoForRaceDTO contains WindTrackInfoDTO for Windbot id "+ windBotId); + logger.log(Level.INFO, "WindInfoForRaceDTO contains WindTrackInfoDTO for Windbot id " + windBotId); if (windTrackInfoDTO.windFixes != null) { if (windTrackInfoDTO.windFixes.size() > 0) { - logger.log(Level.INFO, "Upating UI with Wind Fixes for WindBot id "+ windBotId); - Point[] speedPoints = convertWindFixListIntoPointsArray(windTrackInfoDTO.windFixes, WindType.SPEED); - Point[] directionPoints = convertWindFixListIntoPointsArray(windTrackInfoDTO.windFixes, - WindType.DIRECTION); + logger.log(Level.INFO, "Upating UI with Wind Fixes for WindBot id " + windBotId); + SplitScheduler.get().schedule(new ScheduledCommand() { - trueWindSpeedLiveAverageComponent.setLiveValue(""+NumberFormat.getFormat("#0.0").format(speedPoints[speedPoints.length - 1].getY().doubleValue())); - trueWindSpeedLiveAverageComponent.setAverageValue(""+NumberFormat.getFormat("#0.0").format(movingAverageSpeed.getAverage())); - - trueWindDirectionLiveAverageComponent.setLiveValue(""+NumberFormat.getFormat("#0.0").format(directionPoints[directionPoints.length - 1].getY().doubleValue())); - trueWindDirectionLiveAverageComponent.setAverageValue(""+NumberFormat.getFormat("#0.0").format(movingAverageDirection.getAverage())); + @Override + public void execute() { + updateMovingAverages(windTrackInfoDTO.windFixes); + } + }); + SplitScheduler.get().schedule(new ScheduledCommand() { - trueWindSpeedVerticalWindChart.addPointsToSeriesWithAverage(speedPoints, - movingAverageSpeed.getAverage()); - trueWindDirectionVerticalWindChart.addPointsToSeriesWithAverage(directionPoints, - movingAverageDirection.getAverage()); - locationPointerCompass.windBotPositionChanged(windTrackInfoDTO.windFixes - .get(windTrackInfoDTO.windFixes.size() - 1).position); + @Override + public void execute() { + updateWindSpeedLabelsAndChart(windTrackInfoDTO); + } + }); + SplitScheduler.get().schedule(new ScheduledCommand() { + + @Override + public void execute() { + updateWindDirectionLabelsAndChart(windTrackInfoDTO); + } + }); + SplitScheduler.get().schedule(new ScheduledCommand() { + + @Override + public void execute() { + updateLocationPointerCompass(windTrackInfoDTO); + } + }); } else { logger.log(Level.INFO, "WindTrackInfoDTO.windFixes is empty"); } @@ -200,52 +197,37 @@ public class WindBotComponent extends Composite implements HasWidgets, WindBotDa logger.log(Level.INFO, "WindTrackInfoDTO.windFixes is null"); } } else { - logger.log(Level.INFO, "WindInfoForRaceDTO does not contains WindTrackInfoDTO for Windbot id "+ windBotId); + logger.log(Level.INFO, "WindInfoForRaceDTO does not contains WindTrackInfoDTO for Windbot id " + + windBotId); } } else { logger.log(Level.INFO, "WindInfoForRaceDTO is null"); } } - - private Point[] convertWindFixListIntoPointsArray(List windFixes, WindType windtype) { - if (windFixes != null && windFixes.size() > 0) { - 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).trueWindFromDeg); - for (WindDTO windDTO : windFixes) { - double nextSinusValue = 0; - if (inSimulationMode == true) { - nextSinusValue = directionSinWave.getNexNumber(); - } - points[counter] = new Point(windDTO.requestTimepoint, windDTO.trueWindFromDeg + nextSinusValue); - points[counter] = adaptWindDirectionPointToStayCloseToLastPoint(previouspoint, points[counter]); - previouspoint = points[counter]; - movingAverageDirection.add(windDTO.trueWindFromDeg + nextSinusValue); - counter++; - } - } else if (windtype.equals(WindType.SPEED)) { - Point previouspoint = new Point(windFixes.get(0).requestTimepoint, - windFixes.get(0).trueWindSpeedInKnots); - for (WindDTO windDTO : windFixes) { - double nextSinusValue = 0; - if (inSimulationMode == true) { - nextSinusValue = speedSinWave.getNexNumber(); - } - points[counter] = new Point(windDTO.requestTimepoint, windDTO.trueWindSpeedInKnots + nextSinusValue); - points[counter] = adaptWindDirectionPointToStayCloseToLastPoint(previouspoint, points[counter]); - previouspoint = points[counter]; - movingAverageSpeed.add(windDTO.trueWindSpeedInKnots + nextSinusValue); - counter++; - } - } - return points; - } else { - return null; + + private void updateWindSpeedLabelsAndChart(final WindTrackInfoDTO windTrackInfoDTO) { + int size = windTrackInfoDTO.windFixes.size(); + trueWindSpeedLiveAverageComponent.setLiveValue(""+NumberFormat.getFormat("#0.0").format(windTrackInfoDTO.windFixes.get(size-1).trueWindSpeedInKnots)); + trueWindSpeedVerticalWindChart.addPointsToSeriesWithAverageAndWindType(windTrackInfoDTO.windFixes, movingAverageSpeed.getAverage(), WindType.SPEED); + trueWindSpeedLiveAverageComponent.setAverageValue(""+NumberFormat.getFormat("#0.0").format(movingAverageSpeed.getAverage())); + } + + private void updateWindDirectionLabelsAndChart(final WindTrackInfoDTO windTrackInfoDTO) { + int size = windTrackInfoDTO.windFixes.size(); + trueWindDirectionLiveAverageComponent.setLiveValue(""+NumberFormat.getFormat("#0.0").format(windTrackInfoDTO.windFixes.get(size-1).trueWindFromDeg)); + trueWindDirectionVerticalWindChart.addPointsToSeriesWithAverageAndWindType(windTrackInfoDTO.windFixes, movingAverageDirection.getAverage(), WindType.DIRECTION); + trueWindDirectionLiveAverageComponent.setAverageValue(""+NumberFormat.getFormat("#0.0").format(movingAverageDirection.getAverage())); + } + + private void updateLocationPointerCompass(final WindTrackInfoDTO windTrackInfoDTO) { + locationPointerCompass.windBotPositionChanged(windTrackInfoDTO.windFixes + .get(windTrackInfoDTO.windFixes.size() - 1).position); + } + + private void updateMovingAverages(List windFixes) { + for(WindDTO windDTO : windFixes) { + movingAverageSpeed.add(windDTO.trueWindSpeedInKnots); + movingAverageDirection.add(windDTO.trueWindFromDeg); } } - - private Point adaptWindDirectionPointToStayCloseToLastPoint(Point previousPoint, Point point) { - return ChartPointRecalculator.stayClosestToPreviousPoint(previousPoint, point); - } } \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/WindBotWidget.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/WindBotWidget.ui.xml new file mode 100644 index 00000000000..7a9d59ee719 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/WindBotWidget.ui.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/WindBotWidgetResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/WindBotWidgetResources.java new file mode 100644 index 00000000000..c4e600796ba --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/WindBotWidgetResources.java @@ -0,0 +1,28 @@ +package com.sap.sailing.dashboards.gwt.client.widgets.windbot; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; + +/** + * @author Alexander Ries (D062114) + * + */ +public interface WindBotWidgetResources extends ClientBundle { + + public static final WindBotWidgetResources INSTANCE = GWT.create(WindBotWidgetResources.class); + + @Source({"com/sap/sailing/dashboards/gwt/client/theme/theme.gss", "WindBotWidget.gss"}) + WindBotComponentGss gss(); + + public interface WindBotComponentGss extends CssResource { + String wind_bot_component(); + String name_panel(); + String live_average_container(); + String left(); + String right(); + String windchart_container(); + String windchart(); + String compass_container(); + } +} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/VerticalWindChartStyle.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChart.gss similarity index 69% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/VerticalWindChartStyle.css rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChart.gss index 5f192987e9c..382fc2773a8 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/VerticalWindChartStyle.css +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChart.gss @@ -1,18 +1,12 @@ -@CHARSET "UTF-8"; +@require 'theme'; -.flowPanelContainer { +.verical_wind_chart { position: absolute; height: 100%; width: 100%; } -.verticalWindChartClickArea { - position: absolute; - height: 100%; - width: 100%; -} - -.verticalWindChart { +.chart { position: absolute; top: 0px; bottom: 5px; @@ -20,7 +14,13 @@ right: 0px; } -.verticalWindChartClickHint { +.click_area { + position: absolute; + height: 100%; + width: 100%; +} + +.click_hint { position: absolute; height: 35px; bottom: 0px; @@ -29,12 +29,12 @@ line-height: 35px; vertical-align: middle; font-size: 12px; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; text-align: center; color: black; } -.windloadinghint { +.loading_hint { position: absolute; background-color: white; opacity: 0.4; @@ -45,21 +45,20 @@ z-index: 0; } -.windloadinghinttext { +.loading_hint_text { position: absolute; bottom: 0pt; height: 15pt; line-height: 15pt; - margin-top: 0pt; vertical-align: middle; font-size: 12pt; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; width: 100%; text-align: center; top: 50%; margin-top: -7pt; } -.clickHintMinutesSpan{ +.click_hint_minutes { font-weight: bolder; } \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/VerticalWindChart.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChart.java similarity index 79% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/VerticalWindChart.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChart.java index 58eb388f314..01ea5d824aa 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/VerticalWindChart.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChart.java @@ -1,9 +1,8 @@ -package com.sap.sailing.dashboards.gwt.client.windchart; +package com.sap.sailing.dashboards.gwt.client.widgets.windbot.charts; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.logging.Level; import java.util.logging.Logger; import org.moxieapps.gwt.highcharts.client.Axis.Type; @@ -28,8 +27,6 @@ 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; @@ -40,6 +37,10 @@ import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FocusPanel; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.dashboards.gwt.client.util.HighchartsUtil; +import com.sap.sailing.dashboards.gwt.shared.WindType; +import com.sap.sailing.gwt.ui.client.shared.charts.ChartPointRecalculator; +import com.sap.sailing.gwt.ui.shared.WindDTO; /** * The class represents a wind chart that is displayed vertically. Because it is meant to be used to display wind fixes, @@ -53,8 +54,7 @@ import com.google.gwt.user.client.ui.Widget; public class VerticalWindChart extends Composite implements HasWidgets { private Series verticalWindChartSeries; - private String positiveSeriesColorAsHex; - private String negativeSeriesColorAsHex; + private Point lastPoint; private List verticalWindChartClickListeners; /** @@ -74,6 +74,7 @@ public class VerticalWindChart extends Composite implements HasWidgets { private static VerticalWindChartUiBinder uiBinder = GWT.create(VerticalWindChartUiBinder.class); + @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(VerticalWindChart.class.getName()); interface VerticalWindChartUiBinder extends UiBinder { @@ -97,6 +98,7 @@ public class VerticalWindChart extends Composite implements HasWidgets { } public @UiConstructor VerticalWindChart(String positiveFillColorAsHex, String negativeFillColorAsHex) { + VerticalWindChartResources.INSTANCE.gss().ensureInjected(); initVerticalWindChartWithColors(positiveFillColorAsHex, negativeFillColorAsHex); initWidget(uiBinder.createAndBindUi(this)); } @@ -111,9 +113,9 @@ public class VerticalWindChart extends Composite implements HasWidgets { setChartOptions(); setXAxisOptions(); setYAxisOptions(); - positiveSeriesColorAsHex = positiveFillColor; - negativeSeriesColorAsHex = negativeFillColor; + initVerticalWindChartSeries(positiveFillColor, negativeFillColor); verticalWindChartClickListeners = new ArrayList(); + HighchartsUtil.setSizeToMatchContainerDelayed(verticalWindChart); } private void setChartOptions() { @@ -171,13 +173,13 @@ public class VerticalWindChart extends Composite implements HasWidgets { })); } - private void initVerticalWindChartSeries() { + private void initVerticalWindChartSeries(String positivSeriesColorAsHex, String negativeSeriesColorAsHex) { verticalWindChartSeries = verticalWindChart.createSeries(); AreaPlotOptions areaPlotOptions = new AreaPlotOptions(); verticalWindChart.addSeries(verticalWindChartSeries.setName(null).setPlotOptions( areaPlotOptions.setDashStyle(DashStyle.SOLID).setLineWidth(0.1) .setMarker(new Marker().setEnabled(false)).setShadow(false).setHoverStateEnabled(false) - .setLineColor("#FFFFFF").setFillColor(positiveSeriesColorAsHex) + .setLineColor("#FFFFFF").setFillColor(positivSeriesColorAsHex) .setOption("negativeFillColor", negativeSeriesColorAsHex)).setOption("turboThreshold", MAX_SERIES_POINTS)); } @@ -190,34 +192,52 @@ public class VerticalWindChart extends Composite implements HasWidgets { * {@link #setXAxisExtremesForSeriesPointRangeIsSmallerThanChartDisplayIntervall()} and * {@link #setXAxisExtremesForSeriesPointRangeIsBiggerThanChartDisplayIntervall()}. * */ - 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); - logger.log(Level.INFO, "Set Points"); - } else { - for (Point point : points) { - verticalWindChartSeries.addPoint(point, true, false, false); - logger.log(Level.INFO, "Add Point"); - } - } - verticalWindChartSeries.updateThreshold("" + average); - adaptVerticalWindChartExtemes(); - verticalWindChart.setSizeToMatchContainer(); - } - }); + public void addPointsToSeriesWithAverageAndWindType(List windFixes, final double average, WindType windType) { + if(windType.equals(WindType.SPEED)) { + addPointsToSeriesOfTypeSpeed(windFixes); + } else { + addPointsToSeriesOfTypeDirection(windFixes); + } + verticalWindChartSeries.updateThreshold(""+average); + adaptVerticalWindChartExtemes(lastPoint.getX().longValue()); + } + + private Point createSpeedPoint(WindDTO windDTO) { + Point result = new Point(windDTO.measureTimepoint, windDTO.trueWindSpeedInKnots); + if (lastPoint != null) { + adaptWindDirectionPointToStayCloseToLastPoint(lastPoint, result); + } + lastPoint = result; + return result; + } + + private Point createDirectionPoint(WindDTO windDTO) { + Point result = new Point(windDTO.measureTimepoint, windDTO.trueWindFromDeg); + if (lastPoint != null) { + adaptWindDirectionPointToStayCloseToLastPoint(lastPoint, result); + } + lastPoint = result; + return result; + } + + private void addPointsToSeriesOfTypeSpeed(List windFixes) { + for (WindDTO windDTO : windFixes) { + verticalWindChartSeries.addPoint(createSpeedPoint(windDTO), false, false, false); + } + } + + private void addPointsToSeriesOfTypeDirection(List windFixes) { + for (WindDTO windDTO : windFixes) { + verticalWindChartSeries.addPoint(createDirectionPoint(windDTO), false, false, false); + } } /** * Depending on the series points time range and the selected display interval, the series fits into the display * interval or not. So there are two cases where the extreme points of the x-axis get calculated differently. * */ - private void adaptVerticalWindChartExtemes() { - setXAxisExtremesForSeriesPointRangeIsBiggerThanChartDisplayIntervall(); + private void adaptVerticalWindChartExtemes(Long lastTimePoint) { + setXAxisExtremesForSeriesPointRangeIsBiggerThanChartDisplayIntervall(lastTimePoint.longValue()); } /** @@ -226,23 +246,10 @@ public class VerticalWindChart extends Composite implements HasWidgets { * the the max value minus the selected display interval and the max value the last points time value. The chart * gets other extremes, because the values do not fit anymore into the selected display interval. * */ - private void setXAxisExtremesForSeriesPointRangeIsBiggerThanChartDisplayIntervall() { - long maximumExtremeValueInMillis = getLastPointOfVerticalWindChartSeries().getX().longValue(); + private void setXAxisExtremesForSeriesPointRangeIsBiggerThanChartDisplayIntervall(long lastTimePoint) { + long maximumExtremeValueInMillis = lastTimePoint; long minimumExtremeValueInMillis = maximumExtremeValueInMillis - chartIntervallinMinutes * 60 * 1000; - verticalWindChart.getXAxis().setExtremes(minimumExtremeValueInMillis, maximumExtremeValueInMillis, true, true); - } - - - private Point getLastPointOfVerticalWindChartSeries() { - Point lastPointOfVerticalWindChartSeries = null; - if (verticalWindChartSeries != null) { - Point[] seriesPoints = verticalWindChartSeries.getPoints(); - int seriesPointsLenght = seriesPoints.length; - if (seriesPointsLenght > 0) { - lastPointOfVerticalWindChartSeries = seriesPoints[seriesPointsLenght - 1]; - } - } - return lastPointOfVerticalWindChartSeries; + verticalWindChart.getXAxis().setExtremes(minimumExtremeValueInMillis, maximumExtremeValueInMillis, true, false); } public void addVerticalWindChartClickListener(VerticalWindChartClickListener verticalWindChartClickListener) { @@ -258,6 +265,10 @@ public class VerticalWindChart extends Composite implements HasWidgets { verticalWindChartClickListener.clickedWindChartWithNewIntervalChangeInMillis(intervalInMillis); } } + + private Point adaptWindDirectionPointToStayCloseToLastPoint(Point previousPoint, Point point) { + return ChartPointRecalculator.stayClosestToPreviousPoint(previousPoint, point); + } /** * The method handles a click on the vertical wind charts focus panel. It changes the display interval of the x-axis @@ -270,13 +281,8 @@ public class VerticalWindChart extends Composite implements HasWidgets { } else { chartIntervallinMinutes = SMALL_DISPLAY_INTERVALL_IN_MINUTES; } - Scheduler.get().scheduleFinally(new ScheduledCommand() { - - @Override - public void execute() { - adaptVerticalWindChartExtemes(); - notifyVerticalWindChartClickListeners(chartIntervallinMinutes); - }}); + adaptVerticalWindChartExtemes(lastPoint.getX().longValue()); + notifyVerticalWindChartClickListeners(chartIntervallinMinutes); } @Override diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChart.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChart.ui.xml new file mode 100644 index 00000000000..4d3182113d3 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChart.ui.xml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/VerticalWindChartClickListener.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChartClickListener.java similarity index 67% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/VerticalWindChartClickListener.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChartClickListener.java index 26c03f15def..4d02fd8ad74 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/VerticalWindChartClickListener.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChartClickListener.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.windchart; +package com.sap.sailing.dashboards.gwt.client.widgets.windbot.charts; public interface VerticalWindChartClickListener { public void clickedWindChartWithNewIntervalChangeInMillis(int windChartIntervallInMillis); diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChartResources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChartResources.java new file mode 100644 index 00000000000..f1f82307d93 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/charts/VerticalWindChartResources.java @@ -0,0 +1,27 @@ +package com.sap.sailing.dashboards.gwt.client.widgets.windbot.charts; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; + +/** + * @author Alexander Ries (D062114) + * + */ +public interface VerticalWindChartResources extends ClientBundle { + + public static final VerticalWindChartResources INSTANCE = GWT.create(VerticalWindChartResources.class); + + @Source({"com/sap/sailing/dashboards/gwt/client/theme/theme.gss", "VerticalWindChart.gss"}) + VerticalWindChartGSS gss(); + + public interface VerticalWindChartGSS extends CssResource { + String verical_wind_chart(); + String chart(); + String click_area(); + String click_hint(); + String loading_hint(); + String loading_hint_text(); + String click_hint_minutes(); + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompass.css b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompass.gss similarity index 64% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompass.css rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompass.gss index 4db1b4107b7..adbcad59e81 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompass.css +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompass.gss @@ -1,12 +1,12 @@ -@CHARSET "UTF-8"; +@require 'theme'; -.locationPointerCompass{ +.compass{ height: 100%; width: 100%; overflow: visible !important; } -.locationPointerCompass_needle{ +.needle{ position: absolute; height: 100%; width: 100%; @@ -14,7 +14,7 @@ left: 0%; } -.locationPointerCompass_angleToLocationLabel{ +.angleToLocationLabel{ position: absolute; height: 10pt; width: 100%; @@ -22,20 +22,20 @@ top: -5pt; text-align: center; vertical-align: middle; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; font-size: 9pt; font-weight: bold; color: white; } -.locationPointerCompass_distanceToLocationLabel{ +.distanceToLocationLabel{ position: absolute; height: 15pt; width: 100%; bottom: -17pt; text-align: center; vertical-align: middle; - font-family: 'Open Sans', Arial, Verdana, sans-serif; + font-family: DASHBOARD_FONT_FAMILY; line-height: 10pt; font-weight: bold; font-size: 9pt; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompass.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompass.java similarity index 84% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompass.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompass.java index f51ed0e3238..f92b6b3a1b9 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompass.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompass.java @@ -1,11 +1,10 @@ -package com.sap.sailing.dashboards.gwt.client.windchart.compass; +package com.sap.sailing.dashboards.gwt.client.widgets.windbot.compass; import com.google.gwt.i18n.client.NumberFormat; import com.google.gwt.user.client.ui.AbsolutePanel; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; -import com.sap.sailing.dashboards.gwt.client.RibDashboardImageResources; import com.sap.sailing.domain.common.Position; /** @@ -41,8 +40,8 @@ public class LocationPointerCompass extends AbsolutePanel implements HasWidgets, private LocationPointerCompassAngleDistance locationPointerCompassAngleDistance; public LocationPointerCompass() { - LocationPointerCompassRessources.INSTANCE.css().ensureInjected(); - this.getElement().addClassName(LocationPointerCompassRessources.INSTANCE.css().locationPointerCompass()); + LocationPointerCompassRessources.INSTANCE.gss().ensureInjected(); + this.getElement().addClassName(LocationPointerCompassRessources.INSTANCE.gss().compass()); initCompassNeedle(); initAngleToPointetLocationLabel(); initDistanceToPointedLocationLabel(); @@ -53,20 +52,20 @@ public class LocationPointerCompass extends AbsolutePanel implements HasWidgets, private void initCompassNeedle() { compassNeedle = new Image(); - compassNeedle.setResource(RibDashboardImageResources.INSTANCE.compass()); - compassNeedle.getElement().addClassName(LocationPointerCompassRessources.INSTANCE.css().locationPointerCompass_needle()); + compassNeedle.setResource(LocationPointerCompassRessources.INSTANCE.compass()); + compassNeedle.getElement().addClassName(LocationPointerCompassRessources.INSTANCE.gss().needle()); LocationPointerCompass.this.add(compassNeedle); } private void initAngleToPointetLocationLabel() { angleToPointetLocationLabel = new Label(); - angleToPointetLocationLabel.getElement().addClassName(LocationPointerCompassRessources.INSTANCE.css().locationPointerCompass_angleToLocationLabel()); + angleToPointetLocationLabel.getElement().addClassName(LocationPointerCompassRessources.INSTANCE.gss().angleToLocationLabel()); this.add(angleToPointetLocationLabel); } private void initDistanceToPointedLocationLabel() { distanceToPointetLocationLabel = new Label(); - distanceToPointetLocationLabel.getElement().addClassName(LocationPointerCompassRessources.INSTANCE.css().locationPointerCompass_distanceToLocationLabel()); + distanceToPointetLocationLabel.getElement().addClassName(LocationPointerCompassRessources.INSTANCE.gss().distanceToLocationLabel()); distanceToPointetLocationLabel.setText("m"); this.add(distanceToPointetLocationLabel); } @@ -74,11 +73,13 @@ public class LocationPointerCompass extends AbsolutePanel implements HasWidgets, private void updateNeedleAngle(double newDirection) { // Adapt degrees to image angle synchronized (this) { - String winddirectionformatted = NumberFormat.getFormat("#0").format(newDirection-angleOffset); + double newAngle = newDirection-angleOffset; + String winddirectionformatted = NumberFormat.getFormat("#0").format(newAngle); compassNeedle.getElement().getStyle().setProperty("transform", "rotate(" + winddirectionformatted + "deg)"); compassNeedle.getElement().getStyle() .setProperty("webkitTransform", "rotate(" + winddirectionformatted + "deg)"); - angleToPointetLocationLabel.setText(winddirectionformatted + "°"); + String winddirectionFormattedForLabel = NumberFormat.getFormat("#0").format((newAngle < 0) ? 360+newAngle : newAngle); + angleToPointetLocationLabel.setText(winddirectionFormattedForLabel+"°"); } } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompassAngleDistance.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompassAngleDistance.java similarity index 98% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompassAngleDistance.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompassAngleDistance.java index f195355744e..11d2d0020c7 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompassAngleDistance.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompassAngleDistance.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.windchart.compass; +package com.sap.sailing.dashboards.gwt.client.widgets.windbot.compass; import java.util.ArrayList; import java.util.List; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompassAngleDistanceListener.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompassAngleDistanceListener.java similarity index 76% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompassAngleDistanceListener.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompassAngleDistanceListener.java index 98b2852adbf..6c914e5fe61 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompassAngleDistanceListener.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompassAngleDistanceListener.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.windchart.compass; +package com.sap.sailing.dashboards.gwt.client.widgets.windbot.compass; public interface LocationPointerCompassAngleDistanceListener { diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompassRessources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompassRessources.java new file mode 100644 index 00000000000..b38b91e3b57 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/widgets/windbot/compass/LocationPointerCompassRessources.java @@ -0,0 +1,26 @@ +package com.sap.sailing.dashboards.gwt.client.widgets.windbot.compass; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; +import com.google.gwt.resources.client.CssResource.Shared; +import com.google.gwt.resources.client.ImageResource; + +public interface LocationPointerCompassRessources extends ClientBundle { + + public static final LocationPointerCompassRessources INSTANCE = GWT.create(LocationPointerCompassRessources.class); + + @Source("com/sap/sailing/dashboards/gwt/client/images/compass.png") + ImageResource compass(); + + @Source({"com/sap/sailing/dashboards/gwt/client/theme/theme.gss", "LocationPointerCompass.gss"}) + LocationPointerCompassGSS gss(); + + @Shared + public interface LocationPointerCompassGSS extends CssResource { + public String compass(); + public String needle(); + public String angleToLocationLabel(); + public String distanceToLocationLabel(); + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/VerticalWindChart.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/VerticalWindChart.ui.xml deleted file mode 100644 index d07585ece67..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/VerticalWindChart.ui.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/WindBotComponent.ui.xml b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/WindBotComponent.ui.xml deleted file mode 100644 index ef3a9e37080..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/WindBotComponent.ui.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompassRessources.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompassRessources.java deleted file mode 100644 index c5d33105fa0..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/windchart/compass/LocationPointerCompassRessources.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.sap.sailing.dashboards.gwt.client.windchart.compass; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.resources.client.ClientBundle; -import com.google.gwt.resources.client.CssResource; -import com.google.gwt.resources.client.CssResource.Shared; - -public interface LocationPointerCompassRessources extends ClientBundle { - public static final LocationPointerCompassRessources INSTANCE = GWT.create(LocationPointerCompassRessources.class); - - @Source("LocationPointerCompass.css") - LocalCss css(); - - @Shared - public interface LocalCss extends CssResource { - - public String locationPointerCompass(); - - public String locationPointerCompass_needle(); - - public String locationPointerCompass_angleToLocationLabel(); - - public String locationPointerCompass_distanceToLocationLabel(); - } -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/DashboardDispatchRPCServletImpl.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/DashboardDispatchRPCServletImpl.java new file mode 100644 index 00000000000..7f7533190d9 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/DashboardDispatchRPCServletImpl.java @@ -0,0 +1,87 @@ +package com.sap.sailing.dashboards.gwt.server; + +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; + +import com.sap.sailing.dashboards.gwt.shared.DashboardLiveRaceProvider; +import com.sap.sailing.dashboards.gwt.shared.MovingAveragesCache; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext; +import com.sap.sailing.dashboards.gwt.shared.dispatch.impl.DashboardDispatchContextImpl; +import com.sap.sailing.domain.polars.PolarDataService; +import com.sap.sailing.gwt.dispatch.client.Action; +import com.sap.sailing.gwt.dispatch.client.Result; +import com.sap.sailing.gwt.dispatch.client.ResultWrapper; +import com.sap.sailing.gwt.dispatch.client.exceptions.DispatchException; +import com.sap.sailing.gwt.dispatch.client.exceptions.ServerDispatchException; +import com.sap.sailing.gwt.dispatch.client.rpcimpl.DispatchRPC; +import com.sap.sailing.gwt.dispatch.client.rpcimpl.RequestWrapper; +import com.sap.sailing.gwt.ui.server.Activator; +import com.sap.sailing.gwt.ui.server.ProxiedRemoteServiceServlet; +import com.sap.sailing.server.RacingEventService; +import com.sap.sse.util.ServiceTrackerFactory; + +public class DashboardDispatchRPCServletImpl extends ProxiedRemoteServiceServlet implements DispatchRPC { + private static final long serialVersionUID = -245230476512348999L; + private static final Logger logger = Logger.getLogger(DashboardDispatchRPCServletImpl.class.getName()); + + private final ServiceTracker racingEventServiceTracker; + private final PolarDataService polarDataService; + private final DashboardLiveRaceProvider dashboardLiveRaceProvider; + private final MovingAveragesCache movingAveragesCache; + + public DashboardDispatchRPCServletImpl() { + final BundleContext context = Activator.getDefault(); + racingEventServiceTracker = ServiceTrackerFactory.createAndOpen(context, RacingEventService.class); + polarDataService = getPolarDataService(); + dashboardLiveRaceProvider = new DashboardLiveRaceProvider(racingEventServiceTracker.getService()); + movingAveragesCache = new MovingAveragesCache(); + } + + @Override + public > ResultWrapper execute( + RequestWrapper request) throws DispatchException { + A action = request.getAction(); + long start = System.currentTimeMillis(); + try { + R executionResult = action.execute(new DashboardDispatchContextImpl(request.getCurrentClientTime(), + racingEventServiceTracker.getService(), polarDataService, dashboardLiveRaceProvider, + movingAveragesCache, request.getClientLocaleName(), getThreadLocalRequest())); + return new ResultWrapper(executionResult); + } catch (DispatchException d) { + logger.log(Level.WARNING, "Server exception", d); + throw d; + } catch (Throwable t) { + String serverExceptionUUID = UUID.randomUUID().toString(); + logger.log(Level.SEVERE, "Uncaught server exception id: " + serverExceptionUUID, t); + throw new ServerDispatchException(serverExceptionUUID, t); + } finally { + long duration = System.currentTimeMillis() - start; + final Level logLevel; + if (duration < 100) { + logLevel = Level.FINEST; + } else if (duration < 500) { + logLevel = Level.INFO; + } else { + logLevel = Level.WARNING; + } + logger.log(logLevel, "Dispatch took " + duration + "ms for " + action.getClass().getSimpleName()); + } + } + + @Override + protected void doUnexpectedFailure(Throwable e) { + logger.log(Level.WARNING, "GWT RPC Exception: " + e.getMessage(), e); + super.doUnexpectedFailure(e); + } + + private PolarDataService getPolarDataService() { + BundleContext context = Activator.getDefault(); + ServiceReference polarServiceReference = context.getServiceReference(PolarDataService.class); + return context.getService(polarServiceReference); + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/LiveTrackedRaceListener.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/LiveTrackedRaceListener.java deleted file mode 100644 index c67872c5d89..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/LiveTrackedRaceListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.sap.sailing.dashboards.gwt.server; - -import com.sap.sailing.domain.tracking.TrackedRace; - -/** - * Informs the listener about changes in a certain environment, where a {@link TrackedRace} with - * {@link TrackedRace#getStatus()} live is continuously required. - * - * @author Alexander Ries (D062114) - * - */ -public interface LiveTrackedRaceListener { - - public void liveTrackedRaceDidChange(TrackedRace trackedRace); -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/LiveTrackedRaceProvider.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/LiveTrackedRaceProvider.java deleted file mode 100644 index 71dc43a4589..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/LiveTrackedRaceProvider.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.sap.sailing.dashboards.gwt.server; - -import java.util.ArrayList; -import java.util.List; - -import com.sap.sailing.domain.tracking.TrackedRace; - -/** - * Is continuously looking for {@link TrackedRace} with {@link TrackedRace#getStatus()} live and - * notifies {@link LiveTrackedRaceListener} if the current live {@link TrackedRace} has changed. - * - * - * @author Alexander Ries (D062114) - * - */ -public interface LiveTrackedRaceProvider { - - List listener = new ArrayList(); - - public void notifyLiveTrackedRaceListenerAboutLiveTrackedRaceChange(TrackedRace trackedRace); - - default void addLiveTrackedRaceListener(LiveTrackedRaceListener liveTrackedRaceListener){ - listener.add(liveTrackedRaceListener); - } - - default void removeLiveTrackedRaceListener(LiveTrackedRaceListener liveTrackedRaceListener){ - listener.remove(liveTrackedRaceListener); - } -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/RibDashboardServiceImpl.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/RibDashboardServiceImpl.java deleted file mode 100644 index 59452db071e..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/RibDashboardServiceImpl.java +++ /dev/null @@ -1,323 +0,0 @@ -package com.sap.sailing.dashboards.gwt.server; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.util.tracker.ServiceTracker; - -import com.google.gwt.user.server.rpc.RemoteServiceServlet; -import com.sap.sailing.dashboards.gwt.client.RibDashboardService; -import com.sap.sailing.dashboards.gwt.client.startanalysis.StartlineAdvantageType; -import com.sap.sailing.dashboards.gwt.server.startanalysis.StartAnalysisCreationController; -import com.sap.sailing.dashboards.gwt.server.startlineadvantages.StartlineAdvantagesCalculator; -import com.sap.sailing.dashboards.gwt.shared.MovingAverage; -import com.sap.sailing.dashboards.gwt.shared.ResponseMessage; -import com.sap.sailing.dashboards.gwt.shared.dto.RibDashboardRaceInfoDTO; -import com.sap.sailing.dashboards.gwt.shared.dto.StartLineAdvantageDTO; -import com.sap.sailing.dashboards.gwt.shared.dto.StartlineAdvantagesWithMaxAndAverageDTO; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO; -import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.Course; -import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.base.Mark; -import com.sap.sailing.domain.base.RaceColumn; -import com.sap.sailing.domain.base.Waypoint; -import com.sap.sailing.domain.common.Distance; -import com.sap.sailing.domain.common.NoWindException; -import com.sap.sailing.domain.common.Position; -import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; -import com.sap.sailing.domain.common.dto.CompetitorDTO; -import com.sap.sailing.domain.common.tracking.GPSFix; -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.TrackedRace; -import com.sap.sailing.server.RacingEventService; -import com.sap.sse.common.TimePoint; -import com.sap.sse.common.Util.Pair; -import com.sap.sse.common.impl.MillisecondsTimePoint; - -/** - * The server side implementation of the RPC {@link RibDashboardService}. - * - * @author Alexander Ries (D062114) - * - */ -public class RibDashboardServiceImpl extends RemoteServiceServlet implements RibDashboardService, LiveTrackedRaceProvider { - - /** - * - */ - private static final long serialVersionUID = 1L; - - private StartAnalysisCreationController startAnalysisCreationController; - - private StartlineAdvantagesCalculator startlineAdvantagesCalculator; - - /** - * Variable contains last {@link TrackedRace} that is or was live - * */ - private TrackedRace runningRace; - - /** - * {@link MovingAverage} of last 400 start line advantage values during the last races. See initialization at - * {@link #RibDashboardServiceImpl()}) Advantage by geometry is the delta in meters of the distance from race - * committee boat to first mark and pin end mark to first mark. Wind has no influence on the value. - * */ - private MovingAverage averageStartLineAdvantageByGeometry; - - private final ServiceTracker racingEventServiceTracker; - private final com.sap.sailing.domain.base.DomainFactory baseDomainFactory; - private final BundleContext context; - - private static final Logger logger = Logger.getLogger(RibDashboardServiceImpl.class.getName()); - - public RibDashboardServiceImpl() { - this.context = Activator.getDefault(); - this.racingEventServiceTracker = createAndOpenRacingEventServiceTracker(context); - this.baseDomainFactory = getRacingEventService().getBaseDomainFactory(); - this.startAnalysisCreationController = new StartAnalysisCreationController(getRacingEventService()); - this.startlineAdvantagesCalculator = new StartlineAdvantagesCalculator(getPolarService()); - addLiveTrackedRaceListener(startlineAdvantagesCalculator); - this.averageStartLineAdvantageByGeometry = new MovingAverage(400); - } - - protected RacingEventService getRacingEventService() { - return racingEventServiceTracker.getService(); - } - - private PolarDataService getPolarService() { - ServiceReference polarServiceReference = context.getServiceReference(PolarDataService.class); - PolarDataService polarDataService = context.getService(polarServiceReference); - return polarDataService; - } - - protected ServiceTracker createAndOpenRacingEventServiceTracker( - BundleContext context) { - ServiceTracker result = new ServiceTracker( - context, RacingEventService.class.getName(), null); - result.open(); - return result; - } - - /** - * leaderboardName is used to retrieve the live running race with the method - * {@link #getLiveRaceFromLeaderboardName(String)}. - * - * @throws NoWindException - * */ - @Override - public RibDashboardRaceInfoDTO getLiveRaceInfo(String leaderboardName) throws NoWindException { - RibDashboardRaceInfoDTO lRInfo = new RibDashboardRaceInfoDTO(); - if (leaderboardName != null) { - TimePoint timePointOfRequest = MillisecondsTimePoint.now(); - if (checkIfRaceIsStillRunning(timePointOfRequest, leaderboardName)) { - fillLiveRaceInfoDTOWithRaceData(lRInfo, timePointOfRequest); - fillLiveRaceInfoDTOWithStartLineAdavantageByGeometryData(lRInfo, timePointOfRequest); - lRInfo.responseMessage = ResponseMessage.RACE_LIVE; - } else { - lRInfo.responseMessage = ResponseMessage.NO_RACE_LIVE; - } - } else { - lRInfo.responseMessage = ResponseMessage.NO_RACE_LIVE; - } - return lRInfo; - } - - @Override - public RegattaAndRaceIdentifier getIDFromRaceThatTakesWindFixesNow(String leaderboardName) { - RegattaAndRaceIdentifier result = null; - if(leaderboardName != null) { - List trackedRaces = getTrackedRacesFromLeaderboard(leaderboardName); - List filteredTrackedRaces = trackedRaces.stream().filter(trackedRace -> trackedRace.takesWindFixWithTimePoint(MillisecondsTimePoint.now())).collect(Collectors.toList()); - if(filteredTrackedRaces != null && filteredTrackedRaces.size() > 0) { - TrackedRace raceThatTakesWindNow = filteredTrackedRaces.get(0); - if(raceThatTakesWindNow != null) { - result = raceThatTakesWindNow.getRaceIdentifier(); - } - } - } - return result; - } - - private void fillLiveRaceInfoDTOWithRaceData(RibDashboardRaceInfoDTO lRInfo, TimePoint now) { - if (runningRace != null) { - lRInfo.idOfLastTrackedRace = runningRace.getRaceIdentifier(); - List competitors = runningRace.getCompetitorsFromBestToWorst(now); - List competitorNames = new ArrayList(); - for (Competitor competitor : competitors) { - competitorNames.add(competitor.getName()); - } - Collections.sort(competitorNames); - lRInfo.competitorNamesFromLastTrackedRace = competitorNames; - } - } - - // returns true if race is still live - private boolean checkIfRaceIsStillRunning(TimePoint now, String leaderboardName) { - if (runningRace == null || !(runningRace.isLive(now))) { - runningRace = getLiveRaceFromLeaderboardName(leaderboardName); - if (runningRace == null) { - return false; - } else { - return true; - } - } else { - return true; - } - } - - private TrackedRace getLiveRaceFromLeaderboardName(String leaderboardName) { - TrackedRace result = null; - Leaderboard lb = getRacingEventService().getLeaderboardByName(leaderboardName); - if (lb != null) { - for (RaceColumn column : lb.getRaceColumns()) { - for (Fleet fleet : column.getFleets()) { - TrackedRace race = column.getTrackedRace(fleet); - if (race != null && race.isLive(MillisecondsTimePoint.now())) { - result = race; - notifyLiveTrackedRaceListenerAboutLiveTrackedRaceChange(race); - } - } - } - } - return result; - } - - private List getTrackedRacesFromLeaderboard(String leaderboardName) { - List result = new ArrayList(); - Leaderboard lb = getRacingEventService().getLeaderboardByName(leaderboardName); - if (lb != null) { - for (RaceColumn column : lb.getRaceColumns()) { - for (Fleet fleet : column.getFleets()) { - TrackedRace race = column.getTrackedRace(fleet); - if (race != null) { - result.add(race); - } - } - } - } - return result; - } - - private void fillLiveRaceInfoDTOWithStartLineAdavantageByGeometryData(RibDashboardRaceInfoDTO lRInfo, - TimePoint timePoint) throws NoWindException { - if (runningRace != null && timePoint != null) { - StartLineAdvantageDTO startLineAdvantageDTO = new StartLineAdvantageDTO(); - startLineAdvantageDTO.startLineAdvatageType = StartlineAdvantageType.GEOMETRIC; - double startlineAdvantage = calculateStartlineAdvantageByGeometry(); - startLineAdvantageDTO.startLineAdvantage = startlineAdvantage; - averageStartLineAdvantageByGeometry.add(startlineAdvantage); - startLineAdvantageDTO.average = averageStartLineAdvantageByGeometry.getAverage(); - lRInfo.startLineAdvantageDTO = startLineAdvantageDTO; - } - } - - private double calculateStartlineAdvantageByGeometry() { - double result = 0.0; - Course course = runningRace.getRace().getCourse(); - if (course != null) { - Waypoint startlineWayPoint = course.getFirstLeg().getFrom(); - Waypoint firstmarkWayPoint = course.getFirstLeg().getTo(); - if (startlineWayPoint != null && firstmarkWayPoint != null) { - Pair startlineMarkPositions = retrieveStartlineMarkPositionsFromStartLineWayPoint(startlineWayPoint); - Position firstMarkPosition = retrieveFirstMarkPositionFromFirstMarkWayPoint(firstmarkWayPoint); - if (startlineMarkPositions != null && firstMarkPosition != null) { - Distance rcToMark = firstMarkPosition.getDistance(startlineMarkPositions.getA()); - Distance pinToMark = firstMarkPosition.getDistance(startlineMarkPositions.getB()); - return rcToMark.getMeters() - pinToMark.getMeters(); - } - } - } - return result; - } - - private Pair retrieveStartlineMarkPositionsFromStartLineWayPoint(Waypoint startLineWayPoint) { - Pair result = null; - Iterator markIterator = startLineWayPoint.getMarks().iterator(); - if (markIterator.hasNext()) { - Mark startboat = (Mark) markIterator.next(); - if (markIterator.hasNext()) { - Mark pinEnd = (Mark) markIterator.next(); - TimePoint now = MillisecondsTimePoint.now(); - Position startBoatPosition = getPositionFromMarkAtTimePoint(runningRace, startboat, now); - Position pinEndPosition = getPositionFromMarkAtTimePoint(runningRace, pinEnd, now); - if(startBoatPosition != null && pinEndPosition != null) { - result = new Pair(startBoatPosition, pinEndPosition); - } - } - } - return result; - } - - private Position getPositionFromMarkAtTimePoint(TrackedRace trackedRace, Mark mark, TimePoint timePoint) { - GPSFixTrack fixTrack = trackedRace.getTrack(mark); - return fixTrack.getEstimatedPosition(timePoint, true); - } - - private Position retrieveFirstMarkPositionFromFirstMarkWayPoint(Waypoint firstMarkWayPoint) { - Position firstMarkPosition = null; - if (firstMarkWayPoint.getMarks().iterator().hasNext()) { - Mark firstMark = firstMarkWayPoint.getMarks().iterator().next(); - TimePoint now = MillisecondsTimePoint.now(); - firstMarkPosition = getPositionFromMarkAtTimePoint(runningRace, firstMark, now); - logger.log(Level.INFO, "Firstmark: " + firstMarkPosition); - } - return firstMarkPosition; - } - - protected com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory() { - return baseDomainFactory; - } - - @Override - public List getStartAnalysisListForCompetitorIDAndLeaderboardName(String competitorIdAsString, - String leaderboardName) { - List result = null; - if (competitorIdAsString != null && leaderboardName != null) { - result = new ArrayList(); - try { - Competitor competitor = baseDomainFactory.getCompetitorStore().getExistingCompetitorByIdAsString(competitorIdAsString); - List trackedRacesForLeaderBoardName = getTrackedRacesFromLeaderboard(leaderboardName); - for (TrackedRace trackedRace : trackedRacesForLeaderBoardName) { - StartAnalysisDTO startAnalysisDTO = startAnalysisCreationController.checkStartAnalysisForCompetitorInTrackedRace(competitor, trackedRace); - if (startAnalysisDTO != null) { - result.add(startAnalysisDTO); - } - } - } catch (NullPointerException e) { - logger.log(Level.INFO, "", e); - } - } - return result; - } - - @Override - public List getCompetitorsInLeaderboard(String leaderboardName) { - logger.log(Level.INFO, "getCompetitorsInLeaderboard(...) Request."); - if (leaderboardName != null) { - Leaderboard lb = getRacingEventService().getLeaderboardByName(leaderboardName); - return baseDomainFactory.getCompetitorDTOList(lb.getCompetitorsFromBestToWorst(MillisecondsTimePoint.now())); - } else { - return null; - } - } - - @Override - public StartlineAdvantagesWithMaxAndAverageDTO getAdvantagesOnStartline(String leaderboardName) { - return startlineAdvantagesCalculator.getStartLineAdvantagesAccrossLineAtTimePoint(MillisecondsTimePoint.now()); - } - - - @Override - public void notifyLiveTrackedRaceListenerAboutLiveTrackedRaceChange(TrackedRace trackedRace) { - listener.forEach(listener -> listener.liveTrackedRaceDidChange(trackedRace)); - } -} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/AbstractStartAnalysisCreationValidator.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startanalysis/AbstractStartAnalysisCreationValidator.java similarity index 79% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/AbstractStartAnalysisCreationValidator.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startanalysis/AbstractStartAnalysisCreationValidator.java index 8747a387975..1839f4b31ef 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/AbstractStartAnalysisCreationValidator.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startanalysis/AbstractStartAnalysisCreationValidator.java @@ -1,19 +1,21 @@ -package com.sap.sailing.dashboards.gwt.server.startanalysis; +package com.sap.sailing.dashboards.gwt.server.util.actions.startanalysis; import java.util.Iterator; +import com.google.gwt.core.shared.GwtIncompatible; 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; +@GwtIncompatible public abstract class AbstractStartAnalysisCreationValidator { protected static int MINIMUM_MARKPASSIINGS_AT_FIRST_MARK = 3; protected static long MINIMUM_RACE_PROGRESSION_IN_MILLISECONDS = 6*60*1000; - protected boolean threeCompetitorsPassedSecondWayPoint(TrackedRace trackedRace){ + protected static boolean threeCompetitorsPassedSecondWayPoint(TrackedRace trackedRace){ Waypoint secondWaypoint = trackedRace.getRace().getCourse().getFirstLeg().getTo(); Iterator markPassingsInOrder = trackedRace.getMarkPassingsInOrder(secondWaypoint).iterator(); int markPassingsCounter = 0; @@ -24,12 +26,12 @@ public abstract class AbstractStartAnalysisCreationValidator { return markPassingsCounter >= MINIMUM_MARKPASSIINGS_AT_FIRST_MARK ? true : false; } - private boolean competitorPassedSecondWayPoint(Competitor competitor, TrackedRace trackedRace){ + private static 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){ + private static boolean gateStartGolfFlagIsDown(TrackedRace trackedRace){ if(trackedRace.getGateStartGolfDownTime() != 0){ return true; }else{ @@ -44,7 +46,7 @@ public abstract class AbstractStartAnalysisCreationValidator { return false; } - protected boolean raceProgressedFarEnough(Competitor competitor, TrackedRace trackedRace){ + protected static boolean raceProgressedFarEnough(Competitor competitor, TrackedRace trackedRace){ final Boolean isGateStart = trackedRace.isGateStart(); if(isGateStart == Boolean.TRUE){ return gateStartGolfFlagIsDown(trackedRace); diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/StartAnalysisCreationController.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startanalysis/StartAnalysisCreationController.java similarity index 52% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/StartAnalysisCreationController.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startanalysis/StartAnalysisCreationController.java index 35ff0fc276f..c424e122404 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/StartAnalysisCreationController.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startanalysis/StartAnalysisCreationController.java @@ -1,30 +1,29 @@ -package com.sap.sailing.dashboards.gwt.server.startanalysis; +package com.sap.sailing.dashboards.gwt.server.util.actions.startanalysis; import java.util.logging.Level; import java.util.logging.Logger; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO; +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext; +import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisDTO; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.tracking.TrackedRace; -import com.sap.sailing.server.RacingEventService; -public class StartAnalysisCreationController extends AbstractStartAnalysisCreationValidator { +@GwtIncompatible +public final class StartAnalysisCreationController extends AbstractStartAnalysisCreationValidator { - private StartAnalysisDTOFactory startAnalysisDTOFactory; - private static final Logger logger = Logger.getLogger(StartAnalysisCreationController.class.getName()); - public StartAnalysisCreationController(RacingEventService racingEventService) { - startAnalysisDTOFactory = new StartAnalysisDTOFactory(racingEventService); + private StartAnalysisCreationController(DashboardDispatchContext ctx) { + } - public StartAnalysisDTO checkStartAnalysisForCompetitorInTrackedRace(Competitor competitor, TrackedRace trackedRace) { + public static StartAnalysisDTO checkStartAnalysisForCompetitorInTrackedRace(DashboardDispatchContext dashboardDispatchContext, Competitor competitor, TrackedRace trackedRace) { StartAnalysisDTO result = null; if (competitor != null && trackedRace != null) { if (threeCompetitorsPassedSecondWayPoint(trackedRace) && raceProgressedFarEnough(competitor, trackedRace)) { logger.log(Level.INFO, "Creating startanalysis for race " + trackedRace.getRace().getName() + " and competitor: " + competitor.getName()); - result = startAnalysisDTOFactory.createStartAnalysisForCompetitorAndTrackedRace(competitor, trackedRace); - + result = StartAnalysisDTOFactory.createStartAnalysisForCompetitorAndTrackedRace(dashboardDispatchContext, competitor, trackedRace); } else { logger.log(Level.INFO, "Waiting to create startanalysis for race " + trackedRace.getRace().getName() + " and competitor: " + competitor.getName()); } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/StartAnalysisDTOFactory.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startanalysis/StartAnalysisDTOFactory.java similarity index 76% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/StartAnalysisDTOFactory.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startanalysis/StartAnalysisDTOFactory.java index 582ba70c694..a2de29ccd6d 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/StartAnalysisDTOFactory.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startanalysis/StartAnalysisDTOFactory.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.server.startanalysis; +package com.sap.sailing.dashboards.gwt.server.util.actions.startanalysis; import java.util.ArrayList; import java.util.Date; @@ -7,12 +7,14 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import com.sap.sailing.dashboards.gwt.client.startanalysis.StartlineAdvantageType; +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.dashboards.gwt.shared.StartlineAdvantageType; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext; +import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisCompetitorDTO; +import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisDTO; +import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisRankingTableEntryDTO; import com.sap.sailing.dashboards.gwt.shared.dto.StartLineAdvantageDTO; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisCompetitorDTO; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisRankingTableEntryDTO; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.WindAndAdvantagesInfoForStartLineDTO; +import com.sap.sailing.dashboards.gwt.shared.dto.WindAndAdvantagesInfoForStartLineDTO; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.common.LegType; @@ -24,24 +26,20 @@ import com.sap.sailing.domain.tracking.LineDetails; import com.sap.sailing.domain.tracking.MarkPassing; import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedRace; -import com.sap.sailing.server.RacingEventService; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint; -public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValidator { - - private final com.sap.sailing.domain.base.DomainFactory baseDomainFactory; +@GwtIncompatible +public final class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValidator { 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()); - public StartAnalysisDTOFactory(RacingEventService racingEventService) { - baseDomainFactory = racingEventService.getBaseDomainFactory(); - } + private StartAnalysisDTOFactory() {} - public StartAnalysisDTO createStartAnalysisForCompetitorAndTrackedRace(Competitor competitor, TrackedRace trackedRace) { + public static StartAnalysisDTO createStartAnalysisForCompetitorAndTrackedRace(DashboardDispatchContext dashboardDispatchContext, Competitor competitor, TrackedRace trackedRace) { StartAnalysisDTO startAnalysisDTO = new StartAnalysisDTO(); addStaticDataToStartAnalysisDTOFrom(startAnalysisDTO, trackedRace); List competitors = new ArrayList(); @@ -49,7 +47,7 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida List markPassingsInOrder = convertMarkpPassingsIteratorToList(trackedRace.getMarkPassingsInOrder(secondWaypoint).iterator()); boolean isCompetitorOneOfFirstThree = false; for (int i = 0; i < MINIMUM_MARKPASSIINGS_AT_FIRST_MARK; i++) { - competitors.add(createStartAnalysisCompetitorDTO(trackedRace, i + 1, markPassingsInOrder.get(i).getCompetitor())); + competitors.add(createStartAnalysisCompetitorDTO(dashboardDispatchContext, trackedRace, i + 1, markPassingsInOrder.get(i).getCompetitor())); if (markPassingsInOrder.get(i).getCompetitor().equals(competitor)) { isCompetitorOneOfFirstThree = true; } @@ -57,9 +55,9 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida if (!isCompetitorOneOfFirstThree) { int rankOfCompetitorWhilePassingSecondWaypoint = getRankOfCompetitorWhilePassingSecondWaypoint(competitor, trackedRace); - competitors.add(createStartAnalysisCompetitorDTO(trackedRace, rankOfCompetitorWhilePassingSecondWaypoint, competitor)); + competitors.add(createStartAnalysisCompetitorDTO(dashboardDispatchContext, trackedRace, rankOfCompetitorWhilePassingSecondWaypoint, competitor)); } - startAnalysisDTO.competitor = baseDomainFactory.getCompetitorStore().convertToCompetitorDTO(competitor); + startAnalysisDTO.competitor = dashboardDispatchContext.getRacingEventService().getBaseDomainFactory().getCompetitorStore().convertToCompetitorDTO(competitor); startAnalysisDTO.startAnalysisCompetitorDTOs = competitors; final Boolean isGateStart = trackedRace.isGateStart(); if(isGateStart == Boolean.TRUE){ @@ -83,7 +81,7 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida return startAnalysisDTO; } - private List convertMarkpPassingsIteratorToList(Iterator iterator) { + private static List convertMarkpPassingsIteratorToList(Iterator iterator) { List list = new ArrayList(); while (iterator.hasNext()) { list.add(iterator.next()); @@ -91,7 +89,7 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida return list; } - private int getRankOfCompetitorWhilePassingSecondWaypoint(Competitor competitor, TrackedRace trackedRace) { + private static int getRankOfCompetitorWhilePassingSecondWaypoint(Competitor competitor, TrackedRace trackedRace) { Waypoint secondWaypoint = trackedRace.getRace().getCourse().getFirstLeg().getTo(); Iterator markPassings = trackedRace.getMarkPassingsInOrder(secondWaypoint).iterator(); int counter = 0; @@ -103,20 +101,20 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida return 0; } - private StartAnalysisDTO addStaticDataToStartAnalysisDTOFrom(StartAnalysisDTO startAnalysisDTO, TrackedRace trackedRace) { + private static StartAnalysisDTO addStaticDataToStartAnalysisDTOFrom(StartAnalysisDTO startAnalysisDTO, TrackedRace trackedRace) { startAnalysisDTO.raceName = trackedRace.getRace().getName(); startAnalysisDTO.startAnalysisWindLineInfoDTO = createStartAnalysisWindAndLineData(trackedRace); return startAnalysisDTO; } - private StartAnalysisRankingTableEntryDTO createRankTableEntry(TrackedRace trackedRace, int rank, + private static StartAnalysisRankingTableEntryDTO createRankTableEntry(TrackedRace trackedRace, int rank, Competitor competitor) { StartAnalysisRankingTableEntryDTO startAnalysisRankTableEntryDTO = createStartAnalysisRankTableEntryDTOWithRankAndStartTimepoint( competitor, rank, trackedRace); return startAnalysisRankTableEntryDTO; } - private StartAnalysisRankingTableEntryDTO createStartAnalysisRankTableEntryDTOWithRankAndStartTimepoint( + private static StartAnalysisRankingTableEntryDTO createStartAnalysisRankTableEntryDTOWithRankAndStartTimepoint( Competitor competitor, int rank, TrackedRace trackedRace) { StartAnalysisRankingTableEntryDTO tableentry = new StartAnalysisRankingTableEntryDTO(); tableentry.rankAtFirstMark = rank; @@ -133,7 +131,7 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida return tableentry; } - private WindAndAdvantagesInfoForStartLineDTO createStartAnalysisWindAndLineData(TrackedRace trackedRace) { + private static WindAndAdvantagesInfoForStartLineDTO createStartAnalysisWindAndLineData(TrackedRace trackedRace) { WindAndAdvantagesInfoForStartLineDTO startAnalysisWindLineInfoDTO = new WindAndAdvantagesInfoForStartLineDTO(); final TimePoint startOfRace = trackedRace.getStartOfRace(); final TimePoint timePoint = startOfRace == null ? MillisecondsTimePoint.now() : startOfRace; @@ -158,7 +156,7 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida return startAnalysisWindLineInfoDTO; } - private StartlineAdvantageType getStartlineAdvantageType(TrackedRace trackedRace, TimePoint timePoint) { + private static StartlineAdvantageType getStartlineAdvantageType(TrackedRace trackedRace, TimePoint timePoint) { try { LegType typeOfFirstLeg; typeOfFirstLeg = getFirstLegTypeOfTrackedRaceAtTimePoint(trackedRace, timePoint); @@ -176,7 +174,7 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida } } - private LegType getFirstLegTypeOfTrackedRaceAtTimePoint(TrackedRace trackedRace, TimePoint timePoint) + private static LegType getFirstLegTypeOfTrackedRaceAtTimePoint(TrackedRace trackedRace, TimePoint timePoint) throws NoWindException { Iterable trackedLegs = trackedRace.getTrackedLegs(); if (trackedLegs != null && trackedLegs.iterator().hasNext()) { @@ -187,10 +185,10 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida } } - private StartAnalysisCompetitorDTO createStartAnalysisCompetitorDTO(TrackedRace trackedRace, int rank, + private static StartAnalysisCompetitorDTO createStartAnalysisCompetitorDTO(DashboardDispatchContext dashboardDispatchContext, TrackedRace trackedRace, int rank, Competitor competitor) { StartAnalysisCompetitorDTO startAnalysisCompetitorDTOsForRace = new StartAnalysisCompetitorDTO(); - startAnalysisCompetitorDTOsForRace.competitorDTO = baseDomainFactory.getCompetitorStore() + startAnalysisCompetitorDTOsForRace.competitorDTO = dashboardDispatchContext.getRacingEventService().getBaseDomainFactory().getCompetitorStore() .convertToCompetitorDTO(competitor); startAnalysisCompetitorDTOsForRace.rankingTableEntryDTO = createRankTableEntry(trackedRace, rank, competitor); return startAnalysisCompetitorDTOsForRace; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/DefaultPolarValues.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/DefaultPolarValues.java similarity index 87% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/DefaultPolarValues.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/DefaultPolarValues.java index 721524ae6ae..955f215fef8 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/DefaultPolarValues.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/DefaultPolarValues.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.server.startlineadvantages; +package com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage; import com.sap.sailing.domain.common.ManeuverType; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/DefaultPolarWindAngleBoatSpeedFunction.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/DefaultPolarWindAngleBoatSpeedFunction.java similarity index 96% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/DefaultPolarWindAngleBoatSpeedFunction.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/DefaultPolarWindAngleBoatSpeedFunction.java index 8c7082fdb43..7b16e26be3d 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/DefaultPolarWindAngleBoatSpeedFunction.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/DefaultPolarWindAngleBoatSpeedFunction.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.server.startlineadvantages; +package com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage; import org.apache.commons.math.ArgumentOutsideDomainException; import org.apache.commons.math.analysis.interpolation.SplineInterpolator; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/StartlineAdvantageByGeometryCalculator.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/StartlineAdvantageByGeometryCalculator.java new file mode 100644 index 00000000000..3c0dfd8e3e9 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/StartlineAdvantageByGeometryCalculator.java @@ -0,0 +1,77 @@ +package com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage; + +import java.util.Iterator; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.domain.base.Course; +import com.sap.sailing.domain.base.Mark; +import com.sap.sailing.domain.base.Waypoint; +import com.sap.sailing.domain.common.Distance; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.tracking.GPSFix; +import com.sap.sailing.domain.tracking.GPSFixTrack; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util.Pair; +import com.sap.sse.common.impl.MillisecondsTimePoint; + +/** + * @author Alexander Ries (D062114) + * + */ +@GwtIncompatible +public final class StartlineAdvantageByGeometryCalculator { + + public static Double calculateStartlineAdvantageByGeometry(TrackedRace trackedRace) { + Double result = null; + Course course = trackedRace.getRace().getCourse(); + if (course != null) { + Waypoint startlineWayPoint = course.getFirstLeg().getFrom(); + Waypoint firstmarkWayPoint = course.getFirstLeg().getTo(); + if (startlineWayPoint != null && firstmarkWayPoint != null) { + Pair startlineMarkPositions = retrieveStartlineMarkPositionsFromStartLineWayPoint(trackedRace, startlineWayPoint); + Position firstMarkPosition = retrieveFirstMarkPositionFromFirstMarkWayPoint(trackedRace, firstmarkWayPoint); + if (startlineMarkPositions != null && firstMarkPosition != null) { + Distance rcToMark = firstMarkPosition.getDistance(startlineMarkPositions.getA()); + Distance pinToMark = firstMarkPosition.getDistance(startlineMarkPositions.getB()); + double startlineadvantage = rcToMark.getMeters() - pinToMark.getMeters(); + result = new Double(startlineadvantage); + } + } + } + return result; + } + + private static Pair retrieveStartlineMarkPositionsFromStartLineWayPoint(TrackedRace trackedRace, Waypoint startLineWayPoint) { + Pair result = null; + Iterator markIterator = startLineWayPoint.getMarks().iterator(); + if (markIterator.hasNext()) { + Mark startboat = (Mark) markIterator.next(); + if (markIterator.hasNext()) { + Mark pinEnd = (Mark) markIterator.next(); + TimePoint now = MillisecondsTimePoint.now(); + Position startBoatPosition = getPositionFromMarkAtTimePoint(trackedRace, startboat, now); + Position pinEndPosition = getPositionFromMarkAtTimePoint(trackedRace, pinEnd, now); + if(startBoatPosition != null && pinEndPosition != null) { + result = new Pair(startBoatPosition, pinEndPosition); + } + } + } + return result; + } + + private static Position getPositionFromMarkAtTimePoint(TrackedRace trackedRace, Mark mark, TimePoint timePoint) { + GPSFixTrack fixTrack = trackedRace.getTrack(mark); + return fixTrack.getEstimatedPosition(timePoint, true); + } + + private static Position retrieveFirstMarkPositionFromFirstMarkWayPoint(TrackedRace trackedRace, Waypoint firstMarkWayPoint) { + Position firstMarkPosition = null; + if (firstMarkWayPoint.getMarks().iterator().hasNext()) { + Mark firstMark = firstMarkWayPoint.getMarks().iterator().next(); + TimePoint now = MillisecondsTimePoint.now(); + firstMarkPosition = getPositionFromMarkAtTimePoint(trackedRace, firstMark, now); + } + return firstMarkPosition; + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/StartlineAdvantagesCalculator.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/StartlineAdvantagesByWindCalculator.java similarity index 80% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/StartlineAdvantagesCalculator.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/StartlineAdvantagesByWindCalculator.java index a42c039702a..806bd4bbf3c 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/StartlineAdvantagesCalculator.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/StartlineAdvantagesByWindCalculator.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.server.startlineadvantages; +package com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage; import java.util.ArrayList; import java.util.Collections; @@ -6,9 +6,8 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import com.sap.sailing.dashboards.gwt.server.LiveTrackedRaceListener; -import com.sap.sailing.dashboards.gwt.server.startlineadvantages.precalculation.AbstracPreCalculationDataRetriever; -import com.sap.sailing.dashboards.gwt.shared.MovingAverage; +import com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage.precalculation.AbstracPreCalculationDataRetriever; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext; import com.sap.sailing.dashboards.gwt.shared.dto.StartLineAdvantageDTO; import com.sap.sailing.dashboards.gwt.shared.dto.StartlineAdvantagesWithMaxAndAverageDTO; import com.sap.sailing.domain.common.Bearing; @@ -17,7 +16,6 @@ import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.impl.DegreeBearingImpl; import com.sap.sailing.domain.common.impl.MeterDistance; -import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util.Pair; @@ -26,54 +24,40 @@ import com.sap.sse.common.Util.Pair; * @author Alexander Ries (D062114) * */ -public class StartlineAdvantagesCalculator extends AbstracPreCalculationDataRetriever implements LiveTrackedRaceListener{ +public class StartlineAdvantagesByWindCalculator extends AbstracPreCalculationDataRetriever { - private TrackedRace currentLiveTrackedRace; - private MovingAverage advantageMaximumAverage; - private PolarDataService polarDataService; + private DashboardDispatchContext dashboardDispatchContext; private DefaultPolarWindAngleBoatSpeedFunction defaultPolarSpeedWindAngleFunction; - private static final Logger logger = Logger.getLogger(StartlineAdvantagesCalculator.class.getName()); + private final Logger logger = Logger.getLogger(StartlineAdvantagesByWindCalculator.class.getName()); - public StartlineAdvantagesCalculator(PolarDataService polarDataService){ - this.advantageMaximumAverage = new MovingAverage(500); - this.polarDataService = polarDataService; + public StartlineAdvantagesByWindCalculator(DashboardDispatchContext dashboardDispatchContext){ + this.dashboardDispatchContext = dashboardDispatchContext; this.defaultPolarSpeedWindAngleFunction = new DefaultPolarWindAngleBoatSpeedFunction(); } - // Get Course Buoys - // Get Wind - // Get Maneuver Angle and Boat Speed at Angle - // Get Positions on start line with normal upwind and overlaying lay line upwind - // Calculate intersection point(s) between start line and lay lines - // Calculate duration from start line to first mark for overlaying positions - // Calculate intersection points from normal upwind start positions to first mark - // Calculate duration from two new distances for normal upwind starts - // Put all durations in one set - // Get the smallest of the durations and subtract number from every other number - public StartlineAdvantagesWithMaxAndAverageDTO getStartLineAdvantagesAccrossLineAtTimePoint(TimePoint timepoint) { + public StartlineAdvantagesWithMaxAndAverageDTO getStartLineAdvantagesAccrossLineFromTrackedRaceAtTimePoint(TrackedRace trackedRace,TimePoint timepoint) { StartlineAdvantagesWithMaxAndAverageDTO result = new StartlineAdvantagesWithMaxAndAverageDTO(); - if (currentLiveTrackedRace != null) { - retrieveDataForCalculation(currentLiveTrackedRace); + if (trackedRace != null) { + retrieveDataForCalculation(trackedRace, dashboardDispatchContext.getPolarDataService()); if (wind != null) { + Pair startlineAdvantagesAndConfidencesAsArray = null; if (isStartlineCompletelyUnderneathLaylines()) { logger.log(Level.INFO, "Startline is completely underneath laylines"); Pair advantagesRange = new Pair(0.0, startlineLenghtInMeters); - result.advantages = calculateStartlineAdvantagesUnderneathLaylinesInRange(advantagesRange); - double maximum = getMaximumAdvantageOfStartlineAdvantageDTOs(result.advantages); + List startlineAdvantages = calculateStartlineAdvantagesUnderneathLaylinesInRange(advantagesRange); + double maximum = getMaximumAdvantageOfStartlineAdvantageDTOs(startlineAdvantages); result.maximum = maximum; - advantageMaximumAverage.add(maximum); - result.average = advantageMaximumAverage.getAverage(); + startlineAdvantagesAndConfidencesAsArray = convertStartLineAdvantageDTOListToPointAndConfidenceArrays(startlineAdvantages); } else if (isStartlineCompletelyAboveLaylines()) { logger.log(Level.INFO, "Startline is completely above laylines"); Pair advantagesRange = new Pair(0.0, startlineLenghtInMeters); - result.advantages = calculatePolarBasedStartlineAdvantagesInRange(advantagesRange); - subtractMinimumOfAllStartlineAdvantages(result.advantages); - double maximum = getMaximumAdvantageOfStartlineAdvantageDTOs(result.advantages); + List startlineAdvantages = calculatePolarBasedStartlineAdvantagesInRange(advantagesRange); + subtractMinimumOfAllStartlineAdvantages(startlineAdvantages); + double maximum = getMaximumAdvantageOfStartlineAdvantageDTOs(startlineAdvantages); result.maximum = maximum; - advantageMaximumAverage.add(maximum); - result.average = advantageMaximumAverage.getAverage(); - subtractAgainstMaximumOfAllStartlineAdvantages(result.advantages, maximum); + subtractAgainstMaximumOfAllStartlineAdvantages(startlineAdvantages, maximum); + startlineAdvantagesAndConfidencesAsArray = convertStartLineAdvantageDTOListToPointAndConfidenceArrays(startlineAdvantages); } else { logger.log(Level.INFO, "Layline(s) cross startline"); Position intersectionOfRightLaylineAndStartline = getIntersectionOfRightLaylineAndStartline(); @@ -81,14 +65,17 @@ public class StartlineAdvantagesCalculator extends AbstracPreCalculationDataRet Pair polarBasedStartlineAdvatagesRange = getStartAndEndPointOfPolarBasedStartlineAdvatagesInDistancesToRCBoat( intersectionOfRightLaylineAndStartline, intersectionOfleftLaylineAndStartline); Pair pinEndStartlineAdvatagesRange = getPinEndStartlineAdvantagesRangeFromPolarAdvantagesRange(polarBasedStartlineAdvatagesRange); - result.advantages = calculatePolarBasedStartlineAdvantagesInRange(polarBasedStartlineAdvatagesRange); - subtractMinimumOfAllStartlineAdvantages(result.advantages); - double maximum = getMaximumAdvantageOfStartlineAdvantageDTOs(result.advantages); + List startlineAdvantages = calculatePolarBasedStartlineAdvantagesInRange(polarBasedStartlineAdvatagesRange); + subtractMinimumOfAllStartlineAdvantages(startlineAdvantages); + double maximum = getMaximumAdvantageOfStartlineAdvantageDTOs(startlineAdvantages); result.maximum = maximum; - advantageMaximumAverage.add(maximum); - result.average = advantageMaximumAverage.getAverage(); - subtractAgainstMaximumOfAllStartlineAdvantages(result.advantages, maximum); - addClosingZeroPointToMixedAdvantages(result.advantages, pinEndStartlineAdvatagesRange); + subtractAgainstMaximumOfAllStartlineAdvantages(startlineAdvantages, maximum); + addClosingZeroPointToMixedAdvantages(startlineAdvantages, pinEndStartlineAdvatagesRange); + startlineAdvantagesAndConfidencesAsArray = convertStartLineAdvantageDTOListToPointAndConfidenceArrays(startlineAdvantages); + } + if (startlineAdvantagesAndConfidencesAsArray != null) { + result.distanceToRCBoatToStartlineAdvantage = startlineAdvantagesAndConfidencesAsArray.getA(); + result.distanceToRCBoatToConfidence = startlineAdvantagesAndConfidencesAsArray.getB(); } } } else { @@ -108,7 +95,7 @@ public class StartlineAdvantagesCalculator extends AbstracPreCalculationDataRet return result; } - private boolean isBearingUnderneathAdvantageLines(Bearing bearing){ + private boolean isBearingUnderneathAdvantageLines(Bearing bearing){ boolean result = false; Bearing bearingOfRightLaylineInDeg = new DegreeBearingImpl(wind.getBearing().getDegrees() - meouvreAngle / 2); Bearing bearingOfLeftLaylineInDeg = new DegreeBearingImpl(wind.getBearing().getDegrees() + meouvreAngle / 2); @@ -269,6 +256,23 @@ public class StartlineAdvantagesCalculator extends AbstracPreCalculationDataRet return result; } + private Pair convertStartLineAdvantageDTOListToPointAndConfidenceArrays(List startLineAdvantageDTOList) { + Pair result = null; + if(startLineAdvantageDTOList != null && startLineAdvantageDTOList.size() > 0) { + Number[][] distanceToRCBoatToStartlineAdvantage = new Number[startLineAdvantageDTOList.size()][2]; + Number[][] distanceToRCBoatToConfidence = new Number[startLineAdvantageDTOList.size()][2]; + for(int i = 0; i < startLineAdvantageDTOList.size(); i++) { + StartLineAdvantageDTO startLineAdvantageDTO = startLineAdvantageDTOList.get(i); + distanceToRCBoatToStartlineAdvantage[i][0] = startLineAdvantageDTO.distanceToRCBoatInMeters; + distanceToRCBoatToStartlineAdvantage[i][1] = startLineAdvantageDTO.startLineAdvantage; + distanceToRCBoatToConfidence[i][0] = startLineAdvantageDTO.distanceToRCBoatInMeters; + distanceToRCBoatToConfidence[i][1] = startLineAdvantageDTO.confidence; + } + result = new Pair(distanceToRCBoatToStartlineAdvantage, distanceToRCBoatToConfidence); + } + return result; + } + private List calculatePolarBasedStartlineAdvantagesInRange(Pair rangePinEndStartlineAdvantage) { List result = new ArrayList(); if (rangePinEndStartlineAdvantage != null) { @@ -314,13 +318,13 @@ public class StartlineAdvantagesCalculator extends AbstracPreCalculationDataRet return advantages; } - private double getMaximumAdvantageOfStartlineAdvantageDTOs(List advantages) { - double result = 0; + private Double getMaximumAdvantageOfStartlineAdvantageDTOs(List advantages) { + Double result = null; List sortedAdvantages = new ArrayList(); sortedAdvantages.addAll(advantages); - if(sortedAdvantages != null && sortedAdvantages.size() > 0) { - Collections.sort(sortedAdvantages, StartLineAdvantageDTO.startlineAdvantageComparatorByAdvantageDesc); - result = sortedAdvantages.get(0).startLineAdvantage; + if (sortedAdvantages != null && sortedAdvantages.size() > 0) { + Collections.sort(sortedAdvantages, StartLineAdvantageDTO.startlineAdvantageComparatorByAdvantageDesc); + result = new Double(sortedAdvantages.get(0).startLineAdvantage); } return result; } @@ -335,14 +339,4 @@ public class StartlineAdvantagesCalculator extends AbstracPreCalculationDataRet } return result; } - - @Override - public void liveTrackedRaceDidChange(TrackedRace trackedRace) { - this.currentLiveTrackedRace = trackedRace; - } - - @Override - public PolarDataService getPolarDataService() { - return this.polarDataService; - } } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/AbstracPreCalculationDataRetriever.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/AbstracPreCalculationDataRetriever.java similarity index 86% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/AbstracPreCalculationDataRetriever.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/AbstracPreCalculationDataRetriever.java index 4353242c43f..1cf1ab8d0e9 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/AbstracPreCalculationDataRetriever.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/AbstracPreCalculationDataRetriever.java @@ -1,9 +1,10 @@ -package com.sap.sailing.dashboards.gwt.server.startlineadvantages.precalculation; +package com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage.precalculation; import com.sap.sailing.domain.base.impl.BoatClassImpl; import com.sap.sailing.domain.common.BoatClassMasterdata; import com.sap.sailing.domain.common.ManeuverType; import com.sap.sailing.domain.common.Wind; +import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.tracking.TrackedRace; /** @@ -20,11 +21,11 @@ public abstract class AbstracPreCalculationDataRetriever implements PreCalculati public Wind wind; public double meouvreAngle; - protected void retrieveDataForCalculation(TrackedRace trackedRace) { + protected void retrieveDataForCalculation(TrackedRace trackedRace, PolarDataService polarDataService) { startlineAndFirstMarkPositions = retrieveMarkPositions(trackedRace); startlineAdvantageAtPinEndInMeters = retrieveStartlineAdvantage(trackedRace); startlineLenghtInMeters = retrieveStartlineLenght(trackedRace); wind = retrieveWindAtPosition(startlineAndFirstMarkPositions.startBoatPosition, trackedRace); - meouvreAngle = retrieveManouvreAngleAtWindSpeedAndBoatClass(new BoatClassImpl("Extreme40", BoatClassMasterdata.EXTREME_40), ManeuverType.TACK, wind); + meouvreAngle = retrieveManouvreAngleAtWindSpeedAndBoatClass(new BoatClassImpl("Extreme40", BoatClassMasterdata.EXTREME_40), ManeuverType.TACK, wind, polarDataService); } } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/PreCalculationMarkRetriever.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/PreCalculationMarkRetriever.java similarity index 97% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/PreCalculationMarkRetriever.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/PreCalculationMarkRetriever.java index 112195ba379..ae909348bae 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/PreCalculationMarkRetriever.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/PreCalculationMarkRetriever.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.server.startlineadvantages.precalculation; +package com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage.precalculation; import java.util.Iterator; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/PreCalculationPolarDataRetriever.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/PreCalculationPolarDataRetriever.java similarity index 73% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/PreCalculationPolarDataRetriever.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/PreCalculationPolarDataRetriever.java index 2f5998945ad..c7068933782 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/PreCalculationPolarDataRetriever.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/PreCalculationPolarDataRetriever.java @@ -1,6 +1,6 @@ -package com.sap.sailing.dashboards.gwt.server.startlineadvantages.precalculation; +package com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage.precalculation; -import com.sap.sailing.dashboards.gwt.server.startlineadvantages.DefaultPolarValues; +import com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage.DefaultPolarValues; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.common.ManeuverType; import com.sap.sailing.domain.common.Speed; @@ -14,11 +14,11 @@ import com.sap.sailing.domain.polars.PolarDataService; */ public interface PreCalculationPolarDataRetriever { - default double retrieveManouvreAngleAtWindSpeedAndBoatClass(BoatClass boatClass, ManeuverType maneuverType, Speed windSpeed) { + default double retrieveManouvreAngleAtWindSpeedAndBoatClass(BoatClass boatClass, ManeuverType maneuverType, Speed windSpeed, PolarDataService polarDataService) { double result = 0; try { if (boatClass != null && maneuverType != null && windSpeed != null) { - BearingWithConfidence bearingWithConfidence = getPolarDataService().getManeuverAngle(boatClass, maneuverType, windSpeed); + BearingWithConfidence bearingWithConfidence = polarDataService.getManeuverAngle(boatClass, maneuverType, windSpeed); result = bearingWithConfidence.getObject().getDegrees(); } else { result = DefaultPolarValues.getManouvreAngle(ManeuverType.TACK); @@ -28,6 +28,4 @@ public interface PreCalculationPolarDataRetriever { } return result; } - - PolarDataService getPolarDataService(); } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/PreCalculationStartlineAdvantageRetriever.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/PreCalculationStartlineAdvantageRetriever.java similarity index 90% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/PreCalculationStartlineAdvantageRetriever.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/PreCalculationStartlineAdvantageRetriever.java index 9da4e2f2850..c02595e475d 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/PreCalculationStartlineAdvantageRetriever.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/PreCalculationStartlineAdvantageRetriever.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.server.startlineadvantages.precalculation; +package com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage.precalculation; import com.sap.sailing.domain.tracking.LineDetails; import com.sap.sailing.domain.tracking.TrackedRace; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/PreCalculationWindRetriever.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/PreCalculationWindRetriever.java similarity index 84% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/PreCalculationWindRetriever.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/PreCalculationWindRetriever.java index e52ee193d0e..f1ff3539a4f 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startlineadvantages/precalculation/PreCalculationWindRetriever.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/util/actions/startlineadvantage/precalculation/PreCalculationWindRetriever.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.server.startlineadvantages.precalculation; +package com.sap.sailing.dashboards.gwt.server.util.actions.startlineadvantage.precalculation; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Wind; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/DashboardLiveRaceProvider.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/DashboardLiveRaceProvider.java new file mode 100644 index 00000000000..a13477f7a50 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/DashboardLiveRaceProvider.java @@ -0,0 +1,55 @@ +package com.sap.sailing.dashboards.gwt.shared; + +import java.util.HashMap; +import java.util.Map; + +import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.server.RacingEventService; +import com.sap.sse.common.impl.MillisecondsTimePoint; + +/** + * @author Alexander Ries (D062114) + * + */ +public class DashboardLiveRaceProvider { + + private Map liveRaceForLeaderboardNames; + private RacingEventService racingEventService; + + public DashboardLiveRaceProvider(RacingEventService racingEventService) { + liveRaceForLeaderboardNames = new HashMap(); + this.racingEventService = racingEventService; + } + + public void validateLiveRaceForLeaderboardName(String leaderboardName) { + Leaderboard leaderboard = racingEventService.getLeaderboardByName(leaderboardName); + TrackedRace liveRace = null; + if (leaderboard != null) { + for (RaceColumn column : leaderboard.getRaceColumns()) { + for (Fleet fleet : column.getFleets()) { + TrackedRace race = column.getTrackedRace(fleet); + if (race != null && race.isLive(MillisecondsTimePoint.now())) { + liveRace = race; + } + } + } + } + if (liveRace != null) + setLiveRaceForLeaderboardName(leaderboardName, liveRace); + } + + public TrackedRace getLiveRaceForLeaderboardName(String leaderboardName) { + return liveRaceForLeaderboardNames.get(leaderboardName); + } + + private void setLiveRaceForLeaderboardName(String leaderboardName, TrackedRace liveRace) { + if (liveRaceForLeaderboardNames.containsKey(leaderboardName)) { + liveRaceForLeaderboardNames.replace(leaderboardName, liveRace); + } else { + liveRaceForLeaderboardNames.put(leaderboardName, liveRace); + } + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/DashboardURLParameters.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/DashboardURLParameters.java new file mode 100644 index 00000000000..80de5e507f7 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/DashboardURLParameters.java @@ -0,0 +1,28 @@ +package com.sap.sailing.dashboards.gwt.shared; + +import com.google.gwt.user.client.Window; + + +/** + * @author Alexander Ries (D062114) + * + */ +public enum DashboardURLParameters { + + EVENT_ID("eventId"), + LEADERBOARD_NAME("leaderboardName"); + + private String key; + + private DashboardURLParameters(String key) { + this.key = key; + } + + public String getKey() { + return key; + } + + public String getValue() { + return Window.Location.getParameter(getKey()); + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/MovingAverage.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/MovingAverage.java index 84bbc5e637a..54f803eb96d 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/MovingAverage.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/MovingAverage.java @@ -5,10 +5,10 @@ package com.sap.sailing.dashboards.gwt.shared; /** - * Used to calculate the average value for a certain amount of renewing values. - * The amount of values is defined by {@link #NUMBER_OF_VALUES_AVERAGE_CALCULATED}. + * Used to calculate the average value for a defined amount of renewing values. + * The amount of values saved is defined by {@link #NUMBER_OF_VALUES_AVERAGE_CALCULATED}. * It uses a doubleEnededQueue to delete old values, when the queue reached the size - * of {@link #NUMBER_OF_FIEXES_AVERAGE_CALCULATED} and populate it with new ones. + * of {@link #NUMBER_OF_FIEXES_AVERAGE_CALCULATED} and populates it with new ones. * * @author Alexander Ries * diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/MovingAveragesCache.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/MovingAveragesCache.java new file mode 100644 index 00000000000..d04c0e8185d --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/MovingAveragesCache.java @@ -0,0 +1,44 @@ +package com.sap.sailing.dashboards.gwt.shared; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Alexander Ries (D062114) + * + */ +public class MovingAveragesCache { + + private Map averagesForStringKeys; + + public MovingAveragesCache() { + averagesForStringKeys = new HashMap(); + } + + public boolean containesCacheWithKey(String key) { + return averagesForStringKeys.containsKey(key); + } + + public void createMovingAverageWithKeyAndSize(String key, int size) { + if (!averagesForStringKeys.containsKey(key)) { + averagesForStringKeys.put(key, new MovingAverage(size)); + } + } + + public void addValueToAverageWithKey(String key, double value) { + if (averagesForStringKeys.containsKey(key)) { + MovingAverage movingAverage = averagesForStringKeys.get(key); + movingAverage.add(value); + averagesForStringKeys.replace(key, movingAverage); + } + } + + public Double getValueForKey(String key) { + Double result = null; + MovingAverage movingAverage = averagesForStringKeys.get(key); + if(movingAverage != null) { + result = new Double(movingAverage.getAverage()); + } + return result; + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/ResponseMessage.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/ResponseMessage.java deleted file mode 100644 index d7166e925c3..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/ResponseMessage.java +++ /dev/null @@ -1,15 +0,0 @@ -/** - * - */ -package com.sap.sailing.dashboards.gwt.shared; - -/** - * @author Alexander Ries - * - */ -public enum ResponseMessage -{ - RACE_LIVE, - NO_RACE_LIVE -} - diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/SinWave.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/SinWave.java deleted file mode 100644 index ad0d951226d..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/SinWave.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.sap.sailing.dashboards.gwt.shared; - -public class SinWave { - private double period = 100; // loop every 8 calls to updateNumber - private double scale = 5; // go between 0 and this - - private int _pos = 0; - private double Number1 = 0; - - public SinWave(double period, double scale) { - this.period = period; - this.scale = scale; - } - - - - public double getNexNumber() { - _pos++; - Number1 = (double) (Math.sin(_pos * 2 * Math.PI / period) * (scale / 2) + (scale / 2)); - return Number1; - } -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/StartlineAdvantageCalculationBasis.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/StartlineAdvantageCalculationBasis.java deleted file mode 100644 index c9178e8bd74..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/StartlineAdvantageCalculationBasis.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.sap.sailing.dashboards.gwt.shared; - -import com.google.gwt.user.client.rpc.IsSerializable; -import com.sap.sailing.dashboards.gwt.shared.dto.StartLineAdvantageDTO; - -/** - * @author Alexander Ries (D062114) - * - */ -public enum StartlineAdvantageCalculationBasis implements IsSerializable { - MEASURED, - - /** - * When the {@link StartLineAdvantageDTO} is calculated with the Polar API and there are not values returned - * there are used manually entered polar values to provide still a {@link StartLineAdvantageDTO}. - */ - DEFAULT_VALUES -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAdvantageType.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/StartlineAdvantageType.java similarity index 90% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAdvantageType.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/StartlineAdvantageType.java index 3e0f4a50ea2..bf6b953b85f 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/client/startanalysis/StartlineAdvantageType.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/StartlineAdvantageType.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.client.startanalysis; +package com.sap.sailing.dashboards.gwt.shared; import com.sap.sailing.domain.common.LegType; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/DashboardAction.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/DashboardAction.java new file mode 100644 index 00000000000..b9cc7b6ea50 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/DashboardAction.java @@ -0,0 +1,17 @@ +package com.sap.sailing.dashboards.gwt.shared.dispatch; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.gwt.dispatch.client.Action; +import com.sap.sailing.gwt.dispatch.client.Result; +import com.sap.sailing.gwt.dispatch.client.exceptions.DispatchException; + +/** + * @author Alexander Ries (D062114) + * + */ +public interface DashboardAction extends Action { + + @GwtIncompatible + R execute(DashboardDispatchContext dashboardDispatchContext) throws DispatchException; + +} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/DashboardDispatchContext.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/DashboardDispatchContext.java new file mode 100644 index 00000000000..ef159975ee2 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/DashboardDispatchContext.java @@ -0,0 +1,39 @@ +package com.sap.sailing.dashboards.gwt.shared.dispatch; + +import java.util.Date; +import java.util.Locale; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.dashboards.gwt.shared.DashboardLiveRaceProvider; +import com.sap.sailing.dashboards.gwt.shared.MovingAveragesCache; +import com.sap.sailing.domain.polars.PolarDataService; +import com.sap.sailing.gwt.dispatch.client.DispatchContext; +import com.sap.sailing.server.RacingEventService; + +/** + * @author Alexander Ries (D062114) + * + */ +public interface DashboardDispatchContext extends DispatchContext { + + @GwtIncompatible + RacingEventService getRacingEventService(); + + @GwtIncompatible + PolarDataService getPolarDataService(); + + @GwtIncompatible + DashboardLiveRaceProvider getDashboardLiveRaceProvider(); + + @GwtIncompatible + MovingAveragesCache getMovingAveragesCache(); + + @GwtIncompatible + String getClientLocaleName(); + + @GwtIncompatible + Locale getClientLocale(); + + @GwtIncompatible + Date getCurrentClientTime(); +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/DashboardDispatchSystem.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/DashboardDispatchSystem.java new file mode 100644 index 00000000000..4902a45e242 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/DashboardDispatchSystem.java @@ -0,0 +1,11 @@ +package com.sap.sailing.dashboards.gwt.shared.dispatch; + +import com.sap.sailing.gwt.dispatch.client.impl.DispatchSystem; + +/** + * @author Alexander Ries (D062114) + * + */ +public interface DashboardDispatchSystem extends DispatchSystem{ + +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/RequiresLiveRaceAction.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/RequiresLiveRaceAction.java new file mode 100644 index 00000000000..1c84c01a309 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/RequiresLiveRaceAction.java @@ -0,0 +1,30 @@ +package com.sap.sailing.dashboards.gwt.shared.dispatch; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.gwt.dispatch.client.Result; + +/** + * @author Alexander Ries (D062114) + * + */ +public abstract class RequiresLiveRaceAction implements DashboardAction{ + + private String leaderboardName; + + public RequiresLiveRaceAction() {} + + public RequiresLiveRaceAction(String leaderboardName) { + this.leaderboardName = leaderboardName; + } + + @GwtIncompatible + protected TrackedRace getLiveRace(DashboardDispatchContext dashboardDispatchContext) { + dashboardDispatchContext.getDashboardLiveRaceProvider().validateLiveRaceForLeaderboardName(this.leaderboardName); + return dashboardDispatchContext.getDashboardLiveRaceProvider().getLiveRaceForLeaderboardName(this.leaderboardName); + } + + protected String getLeaderboardName() { + return this.leaderboardName; + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/RequiresLiveRaceAndCachesMovingAverageAction.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/RequiresLiveRaceAndCachesMovingAverageAction.java new file mode 100644 index 00000000000..2c9907ccf49 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/RequiresLiveRaceAndCachesMovingAverageAction.java @@ -0,0 +1,30 @@ +package com.sap.sailing.dashboards.gwt.shared.dispatch; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.dashboards.gwt.shared.MovingAveragesCache; +import com.sap.sailing.gwt.dispatch.client.Result; + +/** + * @author Alexander Ries (D062114) + * + */ +public abstract class RequiresLiveRaceAndCachesMovingAverageAction extends RequiresLiveRaceAction{ + + private static final int MOVING_AVERAGE_CACHE_SIZE = (60/5)*15;/*15 minutes in seconds divided by request intervall*/ + + public RequiresLiveRaceAndCachesMovingAverageAction() {} + + public RequiresLiveRaceAndCachesMovingAverageAction(String leaderboardName) { + super(leaderboardName); + } + + @GwtIncompatible + protected void addValueToMovingAverage(double value, MovingAveragesCache movingAveragesCache) { + if(!movingAveragesCache.containesCacheWithKey(getKeyForMovingAverage())) { + movingAveragesCache.createMovingAverageWithKeyAndSize(getKeyForMovingAverage(), MOVING_AVERAGE_CACHE_SIZE); + } + movingAveragesCache.addValueToAverageWithKey(getKeyForMovingAverage(), value); + } + + protected abstract String getKeyForMovingAverage(); +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/impl/DashboardDispatchContextImpl.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/impl/DashboardDispatchContextImpl.java new file mode 100644 index 00000000000..706f0133c3a --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/impl/DashboardDispatchContextImpl.java @@ -0,0 +1,86 @@ +package com.sap.sailing.dashboards.gwt.shared.dispatch.impl; + +import java.net.URL; +import java.util.Date; +import java.util.Locale; + +import javax.servlet.http.HttpServletRequest; + +import com.sap.sailing.dashboards.gwt.shared.DashboardLiveRaceProvider; +import com.sap.sailing.dashboards.gwt.shared.MovingAveragesCache; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext; +import com.sap.sailing.domain.polars.PolarDataService; +import com.sap.sailing.gwt.dispatch.client.exceptions.DispatchException; +import com.sap.sailing.gwt.server.HomeServiceUtil; +import com.sap.sailing.server.RacingEventService; + +/** + * @author Alexander Ries (D062114) + * + */ +public class DashboardDispatchContextImpl implements DashboardDispatchContext{ + private final RacingEventService racingEventService; + private final PolarDataService polarDataService; + private final DashboardLiveRaceProvider dashboardLiveRaceProvider; + private final MovingAveragesCache movingAveragesCache; + private final Date currentClientTime; + private String clientLocaleName; + private final HttpServletRequest request; + + public DashboardDispatchContextImpl(Date currentClientTime, RacingEventService racingEventService, + PolarDataService polarDataService, DashboardLiveRaceProvider dashboardLiveRaceProvider, + MovingAveragesCache movingAveragesCache, String clientLocaleName, HttpServletRequest request) { + this.currentClientTime = currentClientTime; + this.racingEventService = racingEventService; + this.polarDataService = polarDataService; + this.dashboardLiveRaceProvider = dashboardLiveRaceProvider; + this.movingAveragesCache = movingAveragesCache; + this.clientLocaleName = clientLocaleName; + this.request = request; + } + + @Override + public RacingEventService getRacingEventService() { + return racingEventService; + } + + @Override + public PolarDataService getPolarDataService() { + return polarDataService; + } + + @Override + public DashboardLiveRaceProvider getDashboardLiveRaceProvider() { + return dashboardLiveRaceProvider; + } + + @Override + public Date getCurrentClientTime() { + return currentClientTime; + } + + @Override + public String getClientLocaleName() { + return clientLocaleName; + } + + @Override + public Locale getClientLocale() { + return Locale.forLanguageTag(clientLocaleName); + } + + @Override + public HttpServletRequest getRequest() { + return request; + } + + @Override + public URL getRequestBaseURL() throws DispatchException { + return HomeServiceUtil.getRequestBaseURL(request); + } + + @Override + public MovingAveragesCache getMovingAveragesCache() { + return movingAveragesCache; + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/impl/DashboardDispatchSystemImpl.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/impl/DashboardDispatchSystemImpl.java new file mode 100644 index 00000000000..67bdb57fdb3 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dispatch/impl/DashboardDispatchSystemImpl.java @@ -0,0 +1,13 @@ +package com.sap.sailing.dashboards.gwt.shared.dispatch.impl; + +import com.sap.sailing.dashboards.gwt.client.RemoteServiceMappingConstants; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext; +import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchSystem; +import com.sap.sailing.gwt.dispatch.client.impl.DispatchSystemImpl; + +public class DashboardDispatchSystemImpl extends DispatchSystemImpl implements DashboardDispatchSystem { + + public DashboardDispatchSystemImpl() { + super(RemoteServiceMappingConstants.ribdashboardDispatchServiceRemotePath, true); + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/AverageDTO.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/AverageDTO.java index 540ccffa8a1..df20cc4a3a5 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/AverageDTO.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/AverageDTO.java @@ -1,15 +1,15 @@ package com.sap.sailing.dashboards.gwt.shared.dto; -import com.google.gwt.user.client.rpc.IsSerializable; +import com.sap.sailing.gwt.dispatch.client.Result; /** * @author Alexander Ries (D062114) * */ -public class AverageDTO implements IsSerializable { +public class AverageDTO implements Result { - public double average; - public double collectingTimeFrameInMilliseconds; + public Double average; + public Double collectingTimeFrameInMilliseconds; public AverageDTO(){} } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/LeaderboardCompetitorsDTO.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/LeaderboardCompetitorsDTO.java new file mode 100644 index 00000000000..3becb6c12e5 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/LeaderboardCompetitorsDTO.java @@ -0,0 +1,25 @@ +package com.sap.sailing.dashboards.gwt.shared.dto; + +import java.util.List; + +import com.sap.sailing.domain.common.dto.CompetitorDTO; +import com.sap.sailing.gwt.dispatch.client.Result; + +/** + * @author Alexander Ries (D062114) + * + */ +public class LeaderboardCompetitorsDTO implements Result { + + private List competitors; + + public LeaderboardCompetitorsDTO() {} + + public List getCompetitors() { + return competitors; + } + + public void setCompetitors(List competitors) { + this.competitors = competitors; + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/RaceIdDTO.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/RaceIdDTO.java new file mode 100644 index 00000000000..ee100009561 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/RaceIdDTO.java @@ -0,0 +1,23 @@ +package com.sap.sailing.dashboards.gwt.shared.dto; + +import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; +import com.sap.sailing.gwt.dispatch.client.Result; + +/** + * @author Alexander Ries (D062114) + * + */ +public class RaceIdDTO implements Result { + + private RegattaAndRaceIdentifier raceId; + + public RaceIdDTO() {} + + public RegattaAndRaceIdentifier getRaceId() { + return raceId; + } + + public void setRaceId(RegattaAndRaceIdentifier raceId) { + this.raceId = raceId; + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/RibDashboardRaceInfoDTO.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/RibDashboardRaceInfoDTO.java deleted file mode 100644 index bbc4c4039d7..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/RibDashboardRaceInfoDTO.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * - */ -package com.sap.sailing.dashboards.gwt.shared.dto; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -import com.sap.sailing.dashboards.gwt.shared.ResponseMessage; -import com.sap.sailing.dashboards.gwt.shared.dto.startanalysis.StartAnalysisDTO; -import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; - -/** - * @author Alexander Ries - * - */ -public class RibDashboardRaceInfoDTO implements Serializable{ - - private static final long serialVersionUID = -1325150193180234561L; - - public Map windBotDTOForID; - public StartLineAdvantageDTO startLineAdvantageDTO; - public List startAnalysisDTOList; - public List competitorNamesFromLastTrackedRace; - public RegattaAndRaceIdentifier idOfLastTrackedRace; - public ResponseMessage responseMessage; - - public RibDashboardRaceInfoDTO() {} - -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartAnalysesDTO.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartAnalysesDTO.java new file mode 100644 index 00000000000..467b7463b36 --- /dev/null +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartAnalysesDTO.java @@ -0,0 +1,24 @@ +package com.sap.sailing.dashboards.gwt.shared.dto; + +import java.util.List; + +import com.sap.sailing.gwt.dispatch.client.Result; + +/** + * @author Alexander Ries (D062114) + * + */ +public class StartAnalysesDTO implements Result { + + private List startAnalyses; + + public StartAnalysesDTO() {} + + public List getStartAnalyses() { + return startAnalyses; + } + + public void setStartAnalyses(List startAnalyses) { + this.startAnalyses = startAnalyses; + } +} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/startanalysis/StartAnalysisCompetitorDTO.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartAnalysisCompetitorDTO.java similarity index 84% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/startanalysis/StartAnalysisCompetitorDTO.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartAnalysisCompetitorDTO.java index 2f56496ee13..42c2acd9715 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/startanalysis/StartAnalysisCompetitorDTO.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartAnalysisCompetitorDTO.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.shared.dto.startanalysis; +package com.sap.sailing.dashboards.gwt.shared.dto; import java.io.Serializable; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/startanalysis/StartAnalysisDTO.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartAnalysisDTO.java similarity index 95% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/startanalysis/StartAnalysisDTO.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartAnalysisDTO.java index a58757c4a94..40f25217439 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/startanalysis/StartAnalysisDTO.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartAnalysisDTO.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.shared.dto.startanalysis; +package com.sap.sailing.dashboards.gwt.shared.dto; import java.io.Serializable; import java.util.ArrayList; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/startanalysis/StartAnalysisRankingTableEntryDTO.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartAnalysisRankingTableEntryDTO.java similarity index 84% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/startanalysis/StartAnalysisRankingTableEntryDTO.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartAnalysisRankingTableEntryDTO.java index b29deee67a7..eb788b0cab2 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/startanalysis/StartAnalysisRankingTableEntryDTO.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartAnalysisRankingTableEntryDTO.java @@ -1,4 +1,4 @@ -package com.sap.sailing.dashboards.gwt.shared.dto.startanalysis; +package com.sap.sailing.dashboards.gwt.shared.dto; import java.io.Serializable; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartLineAdvantageDTO.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartLineAdvantageDTO.java index 9d2c7fe26f2..c77a1efab80 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartLineAdvantageDTO.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartLineAdvantageDTO.java @@ -2,15 +2,15 @@ package com.sap.sailing.dashboards.gwt.shared.dto; import java.util.Comparator; -import com.google.gwt.user.client.rpc.IsSerializable; -import com.sap.sailing.dashboards.gwt.client.startanalysis.StartlineAdvantageType; +import com.sap.sailing.dashboards.gwt.shared.StartlineAdvantageType; +import com.sap.sailing.gwt.dispatch.client.Result; -public class StartLineAdvantageDTO extends AverageDTO implements IsSerializable { +public class StartLineAdvantageDTO extends AverageDTO implements Result { - public double startLineAdvantage; - public double distanceToRCBoatInMeters; + public Double startLineAdvantage; + public Double distanceToRCBoatInMeters; public StartlineAdvantageType startLineAdvatageType; - public double confidence; + public Double confidence; public StartLineAdvantageDTO(){} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartlineAdvantagesWithMaxAndAverageDTO.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartlineAdvantagesWithMaxAndAverageDTO.java index 58c74a7973d..52ab09d94ba 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartlineAdvantagesWithMaxAndAverageDTO.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/StartlineAdvantagesWithMaxAndAverageDTO.java @@ -1,17 +1,16 @@ package com.sap.sailing.dashboards.gwt.shared.dto; -import java.util.List; - -import com.google.gwt.user.client.rpc.IsSerializable; +import com.sap.sailing.gwt.dispatch.client.Result; /** * @author Alexander Ries (D062114) * */ -public class StartlineAdvantagesWithMaxAndAverageDTO extends AverageDTO implements IsSerializable { +public class StartlineAdvantagesWithMaxAndAverageDTO extends AverageDTO implements Result { - public double maximum; - public List advantages; + public Double maximum; + public Number [][] distanceToRCBoatToStartlineAdvantage; + public Number [][] distanceToRCBoatToConfidence; public StartlineAdvantagesWithMaxAndAverageDTO(){} } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/startanalysis/WindAndAdvantagesInfoForStartLineDTO.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/WindAndAdvantagesInfoForStartLineDTO.java similarity index 69% rename from java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/startanalysis/WindAndAdvantagesInfoForStartLineDTO.java rename to java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/WindAndAdvantagesInfoForStartLineDTO.java index 4243fded2f4..c806405269b 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/startanalysis/WindAndAdvantagesInfoForStartLineDTO.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/WindAndAdvantagesInfoForStartLineDTO.java @@ -1,9 +1,7 @@ -package com.sap.sailing.dashboards.gwt.shared.dto.startanalysis; +package com.sap.sailing.dashboards.gwt.shared.dto; import java.io.Serializable; -import com.sap.sailing.dashboards.gwt.shared.dto.StartLineAdvantageDTO; - public class WindAndAdvantagesInfoForStartLineDTO implements Serializable{ private static final long serialVersionUID = -1325150193180234561L; diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/WindBotComponentDTO.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/WindBotComponentDTO.java deleted file mode 100644 index 897ebec43f2..00000000000 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/shared/dto/WindBotComponentDTO.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.sap.sailing.dashboards.gwt.shared.dto; - -import java.io.Serializable; - -import com.sap.sailing.domain.common.Position; - -public class WindBotComponentDTO implements Serializable{ - - private static final long serialVersionUID = 7552196781982269601L; - - public String id; - public double liveWindSpeedInKts; - public double liveWindDirectionInDegrees; - public double averageWindSpeedInKts; - public double averageWindDirectionInDegrees; - public Position position; - - public WindBotComponentDTO() {} -} diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/resources/com/sap/sailing/dashboards/gwt/RibDashboard.gwt.xml b/java/com.sap.sailing.dashboards.gwt/src/main/resources/com/sap/sailing/dashboards/gwt/RibDashboard.gwt.xml index 0c676581a97..8dfe25e1e71 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/resources/com/sap/sailing/dashboards/gwt/RibDashboard.gwt.xml +++ b/java/com.sap.sailing.dashboards.gwt/src/main/resources/com/sap/sailing/dashboards/gwt/RibDashboard.gwt.xml @@ -43,8 +43,7 @@ - + @@ -53,11 +52,13 @@ - + + + + diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties index cf29e983595..e8ec0210da2 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties @@ -57,4 +57,7 @@ RankGainsOrLosses=Positions-Verluste oder -Gewinne DistanceToStarboardSideAtStart=Distanz zur Steuerbordseite (% der Länge) NumberOfPodiumFinish=Azahl der Podium-Siege NumberOfWins=Anzahl der Siege -RankGainsOrLossesBetweenFirstMarkAndFinish=Positions-Verluste oder -Gewinne (1ter Wegpunkt -> Ziel) \ No newline at end of file +RankGainsOrLossesBetweenFirstMarkAndFinish=Positions-Verluste oder -Gewinne (1ter Wegpunkt -> Ziel) +IsTracked=Ist getracked +NumberOfCompetitorFixes=Anzahl der Teilnehmer-Fixes +NumberOfMarkFixes=Anzahl der Tonnen-Fixes \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_en.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_en.properties index 5fc160d042a..4dbc578b18f 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_en.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_en.properties @@ -57,4 +57,7 @@ RankGainsOrLosses=Rank Gains or Losses DistanceToStarboardSideAtStart=Distance to Starboard Side (% of Length) NumberOfPodiumFinish=Number of Podium Finishes NumberOfWins=Number of Wins -RankGainsOrLossesBetweenFirstMarkAndFinish=Rank Gains or Losses (1st Mark -> Finish) \ No newline at end of file +RankGainsOrLossesBetweenFirstMarkAndFinish=Rank Gains or Losses (1st Mark -> Finish) +IsTracked=Is Tracked +NumberOfCompetitorFixes=Number of Competitor Fixes +NumberOfMarkFixes=Number of Mark Fixes \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingDataRetrievalChainDefinitions.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingDataRetrievalChainDefinitions.java index 6c1dc531dc7..6e5345237db 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingDataRetrievalChainDefinitions.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingDataRetrievalChainDefinitions.java @@ -47,6 +47,7 @@ public class SailingDataRetrievalChainDefinitions { leaderboardRetrieverChainDefinition, HasTrackedRaceContext.class, "RaceSailingDomainRetrieverChain"); trackedRaceRetrieverChainDefinition.endWith(LeaderboardRetrievalProcessor.class, TrackedRaceRetrievalProcessor.class, HasTrackedRaceContext.class, "Race"); + dataRetrieverChainDefinitions.add(trackedRaceRetrieverChainDefinition); final DataRetrieverChainDefinition markPassingRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>( trackedRaceRetrieverChainDefinition, HasMarkPassingContext.class, "MarkPassingSailingDomainRetrieverChain"); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java index e072aced084..e5b6215a193 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java @@ -2,11 +2,13 @@ package com.sap.sailing.datamining.data; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.polars.PolarDataService; +import com.sap.sse.datamining.annotations.Dimension; public interface HasLeaderboardContext { - Leaderboard getLeaderboard(); PolarDataService getPolarDataService(); + @Dimension(messageKey="Leaderboard") + String getName(); } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java index 2fc0d426eff..aed8f28d024 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java @@ -8,6 +8,7 @@ import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sse.datamining.annotations.Connector; import com.sap.sse.datamining.annotations.Dimension; +import com.sap.sse.datamining.annotations.Statistic; public interface HasTrackedRaceContext { @@ -34,4 +35,13 @@ public interface HasTrackedRaceContext { @Dimension(messageKey="Year", ordinal=2) public Integer getYear(); + @Dimension(messageKey="IsTracked", ordinal=6) + public Boolean isTracked(); + + @Statistic(messageKey="NumberOfCompetitorFixes", resultDecimals=0, ordinal=0) + public int getNumberOfCompetitorFixes(); + + @Statistic(messageKey="NumberOfMarkFixes", resultDecimals=0, ordinal=1) + public int getNumberOfMarkFixes(); + } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardWithContext.java index 9f2ced4e8af..ef398fe8c7b 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardWithContext.java @@ -5,7 +5,6 @@ import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.polars.PolarDataService; public class LeaderboardWithContext implements HasLeaderboardContext { - private final Leaderboard leaderboard; private final PolarDataService polarDataService; @@ -19,9 +18,13 @@ public class LeaderboardWithContext implements HasLeaderboardContext { return leaderboard; } - @Override - public PolarDataService getPolarDataService() { - return polarDataService; - } + @Override + public PolarDataService getPolarDataService() { + return polarDataService; + } + @Override + public String getName() { + return getLeaderboard().getName(); + } } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java index 0f996858ab0..d899829ec8d 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java @@ -5,12 +5,19 @@ import java.util.Calendar; import com.sap.sailing.datamining.data.HasLeaderboardContext; import com.sap.sailing.datamining.data.HasTrackedRaceContext; import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.common.tracking.GPSFix; +import com.sap.sailing.domain.common.tracking.GPSFixMoving; +import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util; +import com.sap.sse.common.impl.MillisecondsTimePoint; public class TrackedRaceWithContext implements HasTrackedRaceContext { @@ -84,4 +91,39 @@ public class TrackedRaceWithContext implements HasTrackedRaceContext { return calendar.get(Calendar.YEAR); } + @Override + public Boolean isTracked() { + return getTrackedRace().hasStarted(MillisecondsTimePoint.now()); + } + + @Override + public int getNumberOfCompetitorFixes() { + int number = 0; + for (Competitor competitor : getRace().getCompetitors()) { + GPSFixTrack track = getTrackedRace().getTrack(competitor); + track.lockForRead(); + try { + number += Util.size(track.getRawFixes()); + } finally { + track.unlockAfterRead(); + } + } + return number; + } + + @Override + public int getNumberOfMarkFixes() { + int number = 0; + for (Mark mark : getTrackedRace().getMarks()) { + GPSFixTrack track = getTrackedRace().getTrack(mark); + track.lockForRead(); + try { + number += Util.size(track.getRawFixes()); + } finally { + track.unlockAfterRead(); + } + } + return number; + } + } \ No newline at end of file diff --git a/java/com.sap.sailing.domain.common/.settings/org.eclipse.core.resources.prefs b/java/com.sap.sailing.domain.common/.settings/org.eclipse.core.resources.prefs index 5912fe30df5..c111da40d73 100755 --- a/java/com.sap.sailing.domain.common/.settings/org.eclipse.core.resources.prefs +++ b/java/com.sap.sailing.domain.common/.settings/org.eclipse.core.resources.prefs @@ -1,4 +1,5 @@ eclipse.preferences.version=1 encoding//src/com/sap/sailing/domain/common/AbstractBearing.java=UTF-8 +encoding//src/com/sap/sailing/domain/common/confidence/impl/ConfidenceBasedAveragerImpl.java=utf-8 encoding//src/com/sap/sailing/domain/common/impl/AbstractSpeedWithAbstractBearingImpl.java=UTF-8 encoding//src/com/sap/sailing/domain/common/tracking/impl/CompactGPSFixMovingImpl.java=UTF-8 diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Bearing.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Bearing.java index 4508b693b6b..82e8e5660ec 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Bearing.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Bearing.java @@ -2,7 +2,13 @@ package com.sap.sailing.domain.common; import java.io.Serializable; +import com.sap.sailing.domain.common.impl.DegreeBearingImpl; + public interface Bearing extends Serializable { + Bearing NORTH = new DegreeBearingImpl(0); + Bearing EAST = new DegreeBearingImpl(90); + Bearing SOUTH = new DegreeBearingImpl(180); + Bearing WEST = new DegreeBearingImpl(270); double getDegrees(); diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RaceCompetitorIdsAsStringWithMD5Hash.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RaceCompetitorIdsAsStringWithMD5Hash.java new file mode 100644 index 00000000000..d4073411507 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/RaceCompetitorIdsAsStringWithMD5Hash.java @@ -0,0 +1,105 @@ +package com.sap.sailing.domain.common; + +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import com.sap.sse.common.Util; + +/** + * Manages the set of competitors participating in a specific race. This is not trivial for a {@link RaceBoardPanel} + * because it is provided with the {@link CompetitorSelectionProvider} that is also used by the {@link LeaderboardPanel} + * and therefore has all competitors of the entire regatta, not just those of the race that the race board is showing. + *

+ * + * The back-end knows the race-specific set of competitors and can tell the client. However, we'd like to keep the + * network traffic required to keep this information up to date at a minimum. The key idea is to use an MD5 hash across + * the ordered race's competitor IDs and send that with each {@link GetRaceMapDataAction} request. The server can then + * compare this hash with the current race's competitor set and send an update if and only if there is a difference + * detected. This will, for the most part, reduce the communication to an initial request by the client as long as the + * race's competitors are not known, and the additional MD5 hash being sent with each request. + *

+ * + * Objects of this type start out with an "unknown" race competitor set. When the + * {@link #getMd5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID() MD5 hash} for the currently + * known race competitors is asked, null will initially be returned. When the client has received the race + * competitors the client is expected to call {@link #setIdsAsStringsOfCompetitorsInRace(Iterable)}. If the argument to + * this call was not null, + * {@link #getMd5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID()} will from then on return + * the MD5 hash of the competitor IDs in order. + * + * @author Axel Uhl (D043530) + * + */ +public class RaceCompetitorIdsAsStringWithMD5Hash implements Serializable { + private static final long serialVersionUID = 6881670366184539259L; + + /** + * The {@link #competitorSelection} manages the competitors for the entire leaderboard which may be a + * superset of the competitors participating in the race shown by this map. For certain operations, + * however, it is useful to know exactly the competitors participating in the race shown by this map. + * For example, boat positions should only be requested from the server for those competitors, not all + * in the regatta, particularly when racing in split fleets.

+ * + * To keep this set consistent, the client sends a secure hash of this set to the server where the hash + * will be compared with the hash across the set of competitor IDs as string.

+ * + * If this field is null, nothing is known yet about the competitor-to-race assignment. + */ + private Set idsAsStringOfCompetitorsParticipatingInRace; + + /** + * The MD5 hash of the {@link #idsAsStringOfCompetitorsParticipatingInRace} where the competitors are first ordered + * alphanumerically by their ID as String using {@link String#compareTo(String)}, then concatenating these strings + * and converting to a byte[] using a UTF-8 encoding. May be null if it hasn't been computed before + * or if {@link #idsAsStringOfCompetitorsParticipatingInRace} is still null. + */ + private byte[] md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID; + + /** + * Starts out with an unknown set of race competitors. The {@link #getIdsOfCompetitorsParticipatingInRaceAsStrings()} + * and the {@link #getMd5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID()} will return + * null until a call to {@link #setIdsAsStringsOfCompetitorsInRace(Iterable)} with a non- + * null argument has been performed. + */ + public RaceCompetitorIdsAsStringWithMD5Hash() { + } + + /** + * Immediately calls {@link #setIdsAsStringsOfCompetitorsInRace(Set)} with the argument provided. If that + * was null then this has the same effect as calling {@link #RaceCompetitorIdsAsStringWithMD5Hash()}. + */ + public RaceCompetitorIdsAsStringWithMD5Hash(Set idsAsStringOfCompetitorsParticipatingInRace) + throws UnsupportedEncodingException, NoSuchAlgorithmException { + this.setIdsAsStringsOfCompetitorsInRace(idsAsStringOfCompetitorsParticipatingInRace); + } + + public void setIdsAsStringsOfCompetitorsInRace(Set idsAsStringsOfCompetitorsInRace) throws UnsupportedEncodingException, NoSuchAlgorithmException { + this.idsAsStringOfCompetitorsParticipatingInRace = idsAsStringsOfCompetitorsInRace; + md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID = computeMD5(idsAsStringsOfCompetitorsInRace); + } + + public byte[] getMd5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID() { + return md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID; + } + + public Set getIdsOfCompetitorsParticipatingInRaceAsStrings() { + return idsAsStringOfCompetitorsParticipatingInRace; + } + + private byte[] computeMD5(Iterable idsAsStringsOfCompetitorsInRace) throws NoSuchAlgorithmException, UnsupportedEncodingException { + List l = new ArrayList<>(); + Util.addAll(idsAsStringsOfCompetitorsInRace, l); + Collections.sort(l); + final MessageDigest md5 = MessageDigest.getInstance("MD5"); + for (String c : l) { + md5.update(c.getBytes("UTF-8")); + } + return md5.digest(); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/QuadTree.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/QuadTree.java index 51f42e5f100..798f3ffbe55 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/QuadTree.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/QuadTree.java @@ -1,164 +1,90 @@ -// ********************************************************************** -// -// -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// -// ********************************************************************** -// -// $Source$ -// $RCSfile$ -// $Revision: 184 $ -// $Date: 2008-09-16 16:17:21 +0200 (Tue, 16 Sep 2008) $ -// $Author: axel.uhl $ -// -// ********************************************************************** - package com.sap.sailing.domain.common.quadtree; import java.io.Serializable; -import java.util.Collection; -import java.util.Vector; +import com.sap.sailing.domain.common.Bounds; import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.impl.BoundsImpl; import com.sap.sailing.domain.common.impl.DegreePosition; -import com.sap.sailing.domain.common.quadtree.impl.Bounds; -import com.sap.sailing.domain.common.quadtree.impl.QuadTreeNode; +import com.sap.sailing.domain.common.quadtree.impl.Node; +import com.sap.sailing.domain.common.quadtree.impl.Node.GetResult; /** - * The QuadTree lets you organize objects in a grid, that redefines itself and focuses more gridding when more objects - * appear in a certain area. - *

- * - * Note that this class is not thread safe. If multiple threads can access the same instance concurrently, callers have - * to ensure proper synchronization. Concurrent reads are permissible while any write should block all other operations. + * A spatial data structure that provides efficient (O(log n)) access to nearest neighbors and + * to objects in a certain radius around another object. The location of objects is provided as + * {@link Position}. * * @param * type of object stored by coordinates * @author Axel Uhl (D043530) */ public class QuadTree implements Serializable { + private static final long serialVersionUID = -5500716775749946017L; - static final long serialVersionUID = -7707825592455579873L; - - private QuadTreeNode top; + private final Node root; + + private final static int DEFAULT_MAX_NODE_ITEMS = 20; public QuadTree() { - this(new Bounds(new DegreePosition(-90.0, -180.0), new DegreePosition(90.0, 180.0)), 20, QuadTreeNode.NO_MIN_SIZE); + this(new BoundsImpl(new DegreePosition(-90.0, -180.0), new DegreePosition(90.0, 180.0)), DEFAULT_MAX_NODE_ITEMS); } public QuadTree(Position southWest, Position northEast, int maxItems) { - this(new Bounds(southWest, northEast), maxItems, QuadTreeNode.NO_MIN_SIZE); + this(new BoundsImpl(southWest, northEast), maxItems); } - public QuadTree(Bounds bounds, int maxItems, double minSize) { - top = new QuadTreeNode(bounds, maxItems, minSize); + private QuadTree(Bounds bounds, int maxItems) { + root = new Node(bounds, maxItems); } - /** - * Add a object into the tree at a location. - * - * @param lat up-down location in QuadTree Grid (latitude, y) - * @param lon left-right location in QuadTree Grid (longitude, x) - * @return true if the insertion worked. - * @throws RuntimeException in case the leaf's lat/lng lies outside of the node's bounds. - * This would typically be caused by the point being outside the whole quad tree's bounds. - */ - public void put(Position point, T obj) { - getTop().put(point, obj); + public T put(Position point, T obj) { + return root.put(point, obj); } - /** - * Remove a object out of the tree at a location. - * - * @param lat up-down location in QuadTree Grid (latitude, y) - * @param lon left-right location in QuadTree Grid (longitude, x) - * @return the object removed, null if the object not found. - */ public T remove(Position point, T obj) { - return getTop().remove(point, obj); + return root.remove(point); } - public void replace(Position point, T newObj) { - getTop().replace(point, newObj); - } - - /** Clear the tree. */ + /** + * Remove all elements from this tree. + */ public void clear() { - getTop().clear(); + root.clear(); } /** - * Get an object closest to a lat/lon. - * - * @param lat up-down location in QuadTree Grid (latitude, y) - * @param lon left-right location in QuadTree Grid (longitude, x) - * @return the object that was found. + * Get the value nearest to point. If the tree is empty, null is returned. Distance + * is calculated using the method {@link #getLatLngDistance(Position, Position)} which is an approximation only, + * based on Euklidian geometry with the latitude/longitude values. */ public T get(Position point) { - return getTop().get(point); + final GetResult result = root.get(point); + return result == null ? null : result.getValue(); } /** - * Get an object closest to a lat/lon, within a maximum distance. + * Get the value closest to point, within a maximum distance, where distance + * is computed by the rules of {@link #getLatLngDistance(Position, Position)}. If no key + * is found within that distance, null is returned. * - * @param lat up-down location in QuadTree Grid (latitude, y) - * @param lon left-right location in QuadTree Grid (longitude, x) - * @param withinDistance maximum get distance. The distance is given - * as the square root of the sum of - * the squares of the latitude and longitude differences, respectively. - * It therefore does not correspond to any distance in meters or - * any euclidian distance at all. However, it should be good enough - * (at least outside the polar regions, and in particular for smaller - * regions), and in particular to find minimum distances. - * @return the object that was found, null if nothing is within - * the maximum distance. + * @param withinDistance + * maximum get distance. The distance is given as the square root of the sum of the squares of the + * latitude and longitude differences, respectively. It therefore does not correspond to any distance in + * meters or any euclidian distance at all. However, it should be good enough (at least outside the polar + * regions, and in particular for smaller regions), and in particular to find minimum distances. + * See {@link #getLatLngDistance(Position, Position)}. + * @return the object that was found, null if nothing is within the maximum distance. */ public T get(Position point, double withinDistance) { - return getTop().get(point, withinDistance); + final GetResult result = root.get(point, withinDistance); + return result == null ? null : result.getValue(); } /** - * Get all the objects within a bounding box. - * - * @return Vector of objects. + * Get all values withing the bounds */ - public Collection get(Bounds rect) { - return get(rect, new Vector()); - } - - /** - * Get all the objects within a bounding box, and return the - * objects within a given Vector. - * - * @param vector a vector to add objects to. - * @return Vector of objects. - */ - private Collection get(Bounds rect, Collection vector) { - - if (vector == null) { - vector = new Vector(); - } - // crossing the dateline, right?? Or at least containing the - // entire earth. Might be trouble for VERY LARGE scales. The - // last check is for micro-errors that happen to lon points - // where there might be a smudge overlap for very small - // scales. - if (rect.getSouthWest().getLngDeg() > rect.getNorthEast().getLngDeg() || (Math.abs(rect.getSouthWest().getLngDeg() - rect.getNorthEast().getLngDeg()) < .001)) { - return getTop().get(new Bounds(rect.getSouthWest(), new DegreePosition(rect.getNorthEast().getLatDeg(), 180)), - getTop().get(new Bounds(new DegreePosition(rect.getSouthWest().getLatDeg(), -180), rect.getNorthEast()), vector)); - } else - return getTop().get(rect, vector); - } - - protected QuadTreeNode getTop() { - return top; + public Iterable get(Bounds bounds) { + return root.get(bounds); } /** @@ -166,8 +92,10 @@ public class QuadTree implements Serializable { * and doing the "sqrt thing" */ public static double getLatLngDistance(Position a, Position b) { - double distance = Math.sqrt((a.getLatDeg() - b.getLatDeg()) * (a.getLatDeg() - b.getLatDeg()) + (a.getLngDeg() - b.getLngDeg()) - * (a.getLngDeg() - b.getLngDeg())); + final double dy = a.getLatDeg() - b.getLatDeg(); + final double dx = (a.getLngDeg() - b.getLngDeg()); + final double dxWrapped = Math.abs(dx) <= 180 ? dx : 360.-Math.abs(dx); + double distance = Math.sqrt(dy * dy + dxWrapped * dxWrapped); return distance; } } \ No newline at end of file diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/Bounds.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/Bounds.java deleted file mode 100644 index 9599f7e5f69..00000000000 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/Bounds.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.sap.sailing.domain.common.quadtree.impl; - -import com.sap.sailing.domain.common.Position; - -public class Bounds { - private final Position southWest; - private final Position northEast; - - public Bounds(Position southWest, Position northEast) { - this.southWest = southWest; - this.northEast = northEast; - } - - public Position getSouthWest() { - return southWest; - } - - public Position getNorthEast() { - return northEast; - } - - public boolean contains(Position p) { - return p.getLatDeg() >= getSouthWest().getLatDeg() && p.getLatDeg() <= getNorthEast().getLatDeg() && - (getNorthEast().getLngDeg() >= getSouthWest().getLngDeg() && p.getLngDeg() >= getSouthWest().getLngDeg() && p.getLngDeg() <= getNorthEast().getLngDeg() || - // cross date line bounds - getNorthEast().getLngDeg() < getSouthWest().getLngDeg() && - (p.getLngDeg() <= 180 && p.getLngDeg() >= getSouthWest().getLngDeg() || - p.getLngDeg() >= -180 && p.getLngDeg() <= getNorthEast().getLngDeg())); - } - - public boolean containsBounds(Bounds rect) { - return this.contains(rect.getSouthWest()) && this.contains(rect.getNorthEast()) || - rect.contains(this.getSouthWest()) && rect.contains(this.getNorthEast()); - } - -} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/MutableDistance.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/MutableDistance.java deleted file mode 100644 index 33abdb50680..00000000000 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/MutableDistance.java +++ /dev/null @@ -1,34 +0,0 @@ -// ********************************************************************** -// -// -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// -// ********************************************************************** -// -// $Source$ -// $RCSfile$ -// $Revision: 15 $ -// $Date: 2008-04-20 02:18:58 +0200 (Sun, 20 Apr 2008) $ -// $Author: uhl $ -// -// ********************************************************************** - -package com.sap.sailing.domain.common.quadtree.impl; - -/** - * A *really* simple class used as a changable double. - */ -public class MutableDistance { - public double value = 0; - - public MutableDistance(double distance) { - value = distance; - } -} \ No newline at end of file diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/Node.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/Node.java new file mode 100644 index 00000000000..fb0d5aa6026 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/Node.java @@ -0,0 +1,423 @@ +package com.sap.sailing.domain.common.quadtree.impl; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.sap.sailing.domain.common.Bounds; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.impl.BoundsImpl; +import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sailing.domain.common.quadtree.QuadTree; +import com.sap.sse.common.Util; + +/** + * A node in a {@link QuadTree}. There may be internal nodes that have no elements in them but have exactly + * four child nodes, or leaf nodes that have no children but contain item elements. + * + * @author Axel Uhl (D043530) + * + * @param + */ +public class Node { + // TODO remove when done + public static int visitedItems; + public static int visitedNodes; + public static int skippedNodes; + + /** + * Either an array of exactly four child nodes which are then all non-null, or null, + * meaning that this node is a child node, having no children but potentially having items. A node that has children + * has no items. Quadrants are numbered as usual in geometry. See {@link #NE}, {@link #NW}, {@link #SW} and + * {@link #SE}. + */ + private Node[] children; + + private Map items; + + private final Bounds bounds; + + /** + * The maximum number of items to hold in {@link #items}. If {@link #put(Position, Object) adding} an item to this node + * would increase the item collection's size beyond this number, the node is {@link #split() split} into four new leaf + * nodes, and its items are distributed across those new leaf nodes. This number must be a positive integer. + */ + private final int maxItems; + + /** + * The quadrant index in {@link #children} for the north-east subtree + */ + private final int NE = 0; + + /** + * The quadrant index in {@link #children} for the north-west subtree + */ + private final int NW = 1; + + /** + * The quadrant index in {@link #children} for the south-west subtree + */ + private final int SW = 2; + + /** + * The quadrant index in {@link #children} for the south-east subtree + */ + private final int SE = 3; + + /** + * Creates a new node with the bounds as specified. The node starts out empty, as a leaf node that has + * an empty set of items. + * + * @param bounds + * must not have a north latitude less than the south latitude, or an {@link IllegalArgumentException} + * will result + */ + public Node(Bounds bounds, int maxItems) { + if (bounds.getNorthEast().getLatDeg() < bounds.getSouthEast().getLatDeg()) { + throw new IllegalArgumentException("North border of bounds "+bounds+" is further south than its south border"); + } + if (maxItems <= 0) { + throw new IllegalArgumentException("Maximum number of items must be positive but was "+maxItems); + } + this.maxItems = maxItems; + this.bounds = bounds; + items = new HashMap<>(maxItems); + } + + private void split() { + assert children == null; + assert items != null; + createChildren(); + distributeItemsToChildren(); + assert children != null; + assert items == null; + } + + private void distributeItemsToChildren() { + assert items != null; + assert children != null; + final Map myItems = items; + items = null; + for (final Entry item : myItems.entrySet()) { + getChild(item.getKey()).put(item.getKey(), item.getValue()); + } + assert items == null; + } + + private Node getChild(Position key) { + assert children != null; + assert items == null; + assert bounds.contains(key); + for (final Node child : children) { + if (child.bounds.contains(key)) { + return child; + } + } + throw new RuntimeException("Internal error: position "+key+" is within node bounds "+bounds+" but no child contains it"); + } + + /** + * Adds the value to this node and ensures that the node still meets the requirements regarding size. + * If necessary, the node is split with its items distributed across the new children. If a value already existed at + * position key, it is replaced. + * + * @param key + * the position at which to insert value. Must be contained in this node's {@link #bounds}. + * If it is not, an {@link IllegalArgumentException} will be thrown. Must not be null. + * @return the value previously at position key or null if there was no value at that + * position. + */ + public T put(Position key, T value) { + if (value == null) { + throw new NullPointerException("Cannot insert null values into this node"); + } + if (key == null) { + throw new NullPointerException("null keys not allowed"); + } + if (!bounds.contains(key)) { + throw new IllegalArgumentException("key "+key+" must be within this node's bounds "+bounds); + } + final T result; + if (items != null) { + result = items.put(key, value); + if (result == null) { + // the size of this node has increased by one; check size constraint + if (items.size() > maxItems) { + split(); + } + } + } else { + result = getChild(key).put(key, value); + } + return result; + } + + /** + * Removes the element at position key from this node or any child nodes if such an element exists + * + * @return the value removed, or null if no element existed at position key in this node + * or any of its children + */ + public T remove(Position key) { + final T result; + if (key != null) { + if (items != null) { + result = items.remove(key); + } else { + result = getChild(key).remove(key); + } + } else { + result = null; + } + return result; + } + + private void createChildren() { + assert children == null; + @SuppressWarnings("unchecked") + final Node[] newChildren = (Node[]) new Node[4]; + children = newChildren; + final Position middleWest = new DegreePosition((bounds.getSouthWest().getLatDeg() + bounds.getNorthEast().getLatDeg())/2., + bounds.getSouthWest().getLngDeg()); + final Position southCenter = new DegreePosition(bounds.getSouthWest().getLatDeg(), + (bounds.getNorthEast().getLngDeg() + bounds.getSouthWest().getLngDeg()) / 2. - + // adjust for date line crossing if necessary + (bounds.getNorthEast().getLngDeg() >= bounds.getSouthWest().getLngDeg() ? 0. : 360.)); + final Position middleCenter = new DegreePosition(middleWest.getLatDeg(), southCenter.getLngDeg()); + final Position middleEast = new DegreePosition(middleWest.getLatDeg(), bounds.getNorthEast().getLngDeg()); + final Position northCenter = new DegreePosition(bounds.getNorthEast().getLatDeg(), southCenter.getLngDeg()); + children[NE] = new Node(new BoundsImpl(middleCenter, bounds.getNorthEast()), maxItems); + children[NW] = new Node(new BoundsImpl(middleWest, northCenter), maxItems); + children[SW] = new Node(new BoundsImpl(bounds.getSouthWest(), middleCenter), maxItems); + children[SE] = new Node(new BoundsImpl(southCenter, middleEast), maxItems); + assert children != null; + assert children.length == 4; + assert children[NE] != null && children[NW] != null && children[SW] != null && children[SE] != null; + } + + /** + * Remove all elements from this node by either removing all its items locally or by removing all children + * and converting this back into a leaf node. + */ + public void clear() { + if (items != null) { + items.clear(); + } else { + items = new HashMap<>(); + children = null; + } + } + + public static class GetResult { + private final Position position; + private final T value; + private final double distance; + public GetResult(Position position, T value, double distance) { + super(); + this.position = position; + this.value = value; + this.distance = distance; + } + public Position getPosition() { + return position; + } + public T getValue() { + return value; + } + public double getDistance() { + return distance; + } + @Override + public String toString() { + return "GetResult [position=" + position + ", value=" + value + ", distance=" + distance + "]"; + } + } + + /** + * Get the value nearest to point. If the node is empty, null is returned. Distance is + * calculated using the method {@link QuadTree#getLatLngDistance(Position, Position)} which is an approximation + * only, based on Euklidian geometry with the latitude/longitude values. + *

+ * + * If this is a leaf node, the nearest key by the definition above is used to determine the corresponding value and + * return it. Otherwise, the children are traversed. For the first child, the nearest key is determined recursively. + * Other children only need to be traversed if their bounds are closer to point than the key found so + * far. + * + * @param withinDistance + * a key is only considered if it has less than this {@link QuadTree#getLatLngDistance(Position, Position) + * distance} to point + */ + public GetResult get(Position point, double withinDistance) { + assert (items == null) != (children == null); + visitedNodes++; + GetResult result = null; + double minDistance = withinDistance; + if (items != null) { + for (final Entry item : items.entrySet()) { + double itemDistanceToPoint = QuadTree.getLatLngDistance(point, item.getKey()); + visitedItems++; + if (itemDistanceToPoint < minDistance) { + result = new GetResult(item.getKey(), item.getValue(), itemDistanceToPoint); + minDistance = itemDistanceToPoint; + } + } + } else { + // Traverse children in order of ascending distance, making it more likely to find good, near + // candidates early, hence enabling skipping more children, investigating fewer items. However, + // doing the full java.util.Collections / Arrays sort thing with Comparators and such is way too + // expensive as measurements have shown, and the overhead for just the four elements is too high. + // It is much more efficient to traverse the small children array multiple times and in each pass + // remembering the next minimal child distance so that during the next pass those children can be + // inspected. This process repeats until all children have been handled, taking at most four passes. + final double[] childDistanceToPoint = new double[4]; + double minChildDistanceToPoint = Double.MAX_VALUE; // minimal distance of those children not yet done + for (int i=0; i<4; i++) { + childDistanceToPoint[i] = children[i].getDistance(point); + if (childDistanceToPoint[i] < minChildDistanceToPoint) { + minChildDistanceToPoint = childDistanceToPoint[i]; + } + } + final boolean done[] = new boolean[4]; // have we handled that child already (skipped or searched)? + int doneCount = 0; + while (doneCount < 4) { + double nextMinChildDistanceToPoint = Double.MAX_VALUE; + for (int i=0; doneCount<4 && i<4; i++) { + if (!done[i]) { + if (childDistanceToPoint[i] == minChildDistanceToPoint) { + final Node child = children[i]; + // If we have a possible result already, only investigate the child node if it is nearer to point + // than the result candidate and not an empty leaf node (which can be checked more quickly than + // performing the rather expensive distance calculation) + if (!child.isEmptyLeaf() && childDistanceToPoint[i] < minDistance) { + assert minDistance <= withinDistance; + final GetResult childResult = child.get(point, minDistance); + if (childResult != null) { + if (childResult.getDistance() < minDistance) { + result = childResult; + minDistance = childResult.getDistance(); + } + } + } else { + skippedNodes++; + } + done[i] = true; + doneCount++; + } else { + if (childDistanceToPoint[i] < nextMinChildDistanceToPoint) { + nextMinChildDistanceToPoint = childDistanceToPoint[i]; // the distance to handle in the next pass + } + } + } + } + minChildDistanceToPoint = nextMinChildDistanceToPoint; + } + } + return result; + } + + /** + * Get the value nearest to point. If the node is empty, null is returned. Distance is + * calculated using the method {@link QuadTree#getLatLngDistance(Position, Position)} which is an approximation + * only, based on Euklidian geometry with the latitude/longitude values. + *

+ * + * If this is a leaf node, the nearest key by the definition above is used to determine the corresponding value and + * return it. Otherwise, the children are traversed. For the first child, the nearest key is determined recursively. + * Other children only need to be traversed if their bounds are closer to point than the key found so + * far. + */ + public GetResult get(Position point) { + return get(point, Double.MAX_VALUE); + } + + /** + * To avoid expensive distance checks, a shortcut can be to check whether this node is an empty + * leaf node. This is the case if {@link #items} is not null (indicating a leaf node) + * but empty. + */ + private boolean isEmptyLeaf() { + return items != null && items.isEmpty(); + } + + /** + * Computes a "distance" of this node's {@link #bounds} to the point based on the distance definition + * provided by {@link QuadTree#getLatLngDistance(Position, Position)}. If point is + * {@link Bounds#contains(Position) contained} in this node's {@link #bounds}, the distance returned is + * 0. Otherwise, the distance to the nearest border of this node's {@link #bounds} is determined. + */ + protected double getDistance(Position point) { + final double result; + if (bounds.contains(point)) { + result = 0; + } else { + // Find out the point on the border defined by bounds that is nearest to point. + final double latDegNearestOnBorder = + point.getLatDeg() > bounds.getNorthEast().getLatDeg() ? bounds.getNorthEast().getLatDeg() : + point.getLatDeg() < bounds.getSouthWest().getLatDeg() ? bounds.getSouthWest().getLatDeg() : point.getLatDeg(); + // Now construct a Bounds object of zero latitude span at point's latitude and with the longitude span + // copied from this Node's bounds. If these bounds contain point, use point's longitude as it is spanned by + // this node's bounds. Otherwise, extend the bounds to contain point, then check whether the west or east border + // was changed to contain point; point was closer to the border that was changed to include point + final Bounds boundsAtPointLat = new BoundsImpl(new DegreePosition(point.getLatDeg(), bounds.getSouthWest().getLngDeg()), + new DegreePosition(point.getLatDeg(), bounds.getNorthEast().getLngDeg())); + final double lngDegNearestOnBorder; + if (boundsAtPointLat.contains(point)) { + lngDegNearestOnBorder = point.getLngDeg(); + } else { + final Bounds boundsAtPointLatExtendedToIncludePoint = boundsAtPointLat.extend(point); + if (boundsAtPointLatExtendedToIncludePoint.getSouthWest().getLngDeg() == bounds.getSouthWest().getLngDeg()) { + lngDegNearestOnBorder = bounds.getNorthEast().getLngDeg(); + } else { + lngDegNearestOnBorder = bounds.getSouthWest().getLngDeg(); + } + } + result = QuadTree.getLatLngDistance(point, new DegreePosition(latDegNearestOnBorder, lngDegNearestOnBorder)); + } + return result; + } + + /** + * Fetches all values within the bounds specified. Always returns a non-null iterable + * which may, however, be empty. + * + * @param bounds + * It is permissible for bounds to not even intersect with this node's {@link #bounds}. + * Then, however, the result will be empty. + */ + public Iterable get(Bounds bounds) { + final Iterable result; + if (this.bounds.intersects(bounds)) { + Set preResult = new HashSet<>(); + if (items != null) { + if (bounds.contains(this.bounds)) { + // all items must be contained, so no per-item check is required + preResult.addAll(items.values()); + } else { + for (final Entry item : items.entrySet()) { + if (bounds.contains(item.getKey())) { + preResult.add(item.getValue()); + } + } + } + } else { + for (final Node child : children) { + Util.addAll(child.get(bounds), preResult); + } + } + result = preResult; + } else { + result = Collections.emptySet(); + } + return result; + } + + @Override + public String toString() { + return ""+bounds+": "+(items==null?0:items.size())+" items in node, "+ + (children==null?0:children.length)+" child nodes"; + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/QuadTreeLeaf.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/QuadTreeLeaf.java deleted file mode 100644 index 1ea4950e23f..00000000000 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/QuadTreeLeaf.java +++ /dev/null @@ -1,55 +0,0 @@ -// ********************************************************************** -// -// -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// -// ********************************************************************** -// -// $Source: -// /cvs/distapps/openmap/src/openmap/com/bbn/openmap/util/quadtree/QuadTreeLeaf.java,v -// $ -// $RCSfile$ -// $Revision: 45 $ -// $Date: 2008-06-08 22:04:43 +0200 (Sun, 08 Jun 2008) $ -// $Author: uhl $ -// -// ********************************************************************** - -package com.sap.sailing.domain.common.quadtree.impl; - -import java.io.Serializable; - -import com.sap.sailing.domain.common.Position; - -public class QuadTreeLeaf implements Serializable { - - static final long serialVersionUID = 7885745536157252519L; - - private Position point; - private T object; - - public QuadTreeLeaf(Position point, T obj) { - this.point = point; - this.object = obj; - } - - public Position getPoint() { - return point; - } - - public T getObject() { - return object; - } - - public String toString() { - return "QuadTreeLeaf at (" + point.getLatDeg() + ", " + point.getLngDeg() + ") with object " + getObject(); - } - -} \ No newline at end of file diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/QuadTreeNode.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/QuadTreeNode.java deleted file mode 100644 index ee6229d64a6..00000000000 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/quadtree/impl/QuadTreeNode.java +++ /dev/null @@ -1,407 +0,0 @@ -// ********************************************************************** -// -// -// -// BBN Technologies -// 10 Moulton Street -// Cambridge, MA 02138 -// (617) 873-8000 -// -// Copyright (C) BBNT Solutions LLC. All rights reserved. -// -// -// ********************************************************************** -// -// $Source$ -// $RCSfile$ -// $Revision: 101 $ -// $Date: 2008-07-09 23:09:42 +0200 (Wed, 09 Jul 2008) $ -// $Author: axel.uhl $ -// -// ********************************************************************** - -package com.sap.sailing.domain.common.quadtree.impl; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Iterator; -import java.util.Vector; - -import com.sap.sailing.domain.common.Position; -import com.sap.sailing.domain.common.impl.DegreePosition; -import com.sap.sailing.domain.common.quadtree.QuadTree; - -/** - * The QuadTreeNode is the part of the QuadTree that either holds - * children nodes, or objects as leaves. Currently, the nodes that - * have children do not hold items that span across children - * boundaries, since this was designed to handle point data. - */ -public class QuadTreeNode implements Serializable { - - static final long serialVersionUID = -6111633198469889444L; - - private final static int NORTHWEST = 0; - private final static int NORTHEAST = 1; - private final static int SOUTHEAST = 2; - private final static int SOUTHWEST = 3; - public final static double NO_MIN_SIZE = -1; - - private Vector> items; - private QuadTreeNode[] children; - private int maxItems; - private double minSize; - private Bounds bounds; - - /** - * Added to avoid problems when a node is completely filled with a - * single point value. - */ - private boolean allTheSamePoint; - private Position firstPoint; - - /** - * Constructor to use if you are going to store the objects in - * lat/lon space, and there is really no smallest node size. - * - * @param maximumItems number of items to hold in a node before - * splitting itself into four children and redispensing the - * items into them. - */ - public QuadTreeNode(Bounds rect, int maximumItems) { - this(rect, maximumItems, NO_MIN_SIZE); - } - - /** - * Constructor to use if you are going to store the objects in x/y - * space, and there is a smallest node size because you don't want - * the nodes to be smaller than a group of pixels. - * - * @param north northern border of node coverage. - * @param west western border of node coverage. - * @param south southern border of node coverage. - * @param east eastern border of node coverage. - * @param maximumItems number of items to hold in a node before - * splitting itself into four children and redispensing the - * items into them. - * @param minimumSize the minimum difference between the - * boundaries of the node. - */ - public QuadTreeNode(Bounds rect, int maximumItems, double minimumSize) { - bounds = rect; - maxItems = maximumItems; - minSize = minimumSize; - items = new Vector>(); - } - - /** Return true if the node has children. */ - public boolean hasChildren() { - if (children != null) - return true; - else - return false; - } - - /** - * This method splits the node into four children, and disperses - * the items into the children. The split only happens if the - * boundary size of the node is larger than the minimum size (if - * we care). The items in this node are cleared after they are put - * into the children. - */ - @SuppressWarnings("unchecked") - protected void split() { - // Make sure we're bigger than the minimum, if we care, - if (minSize != NO_MIN_SIZE) { - if (Math.abs(bounds.getNorthEast().getLatDeg() - bounds.getSouthWest().getLatDeg()) < minSize - && Math.abs(bounds.getNorthEast().getLngDeg() - bounds.getSouthWest().getLngDeg()) < minSize) - return; - } - - double nsHalf = (bounds.getNorthEast().getLatDeg() + bounds.getSouthWest().getLatDeg()) / 2.0; - double ewHalf = (bounds.getNorthEast().getLngDeg() + bounds.getSouthWest().getLngDeg()) / 2.0; - children = new QuadTreeNode[4]; - children[NORTHWEST] = new QuadTreeNode(new Bounds(new DegreePosition(nsHalf, bounds.getSouthWest().getLngDeg()), new DegreePosition(bounds.getNorthEast().getLatDeg(), ewHalf)), maxItems); - children[NORTHEAST] = new QuadTreeNode(new Bounds(new DegreePosition(nsHalf, ewHalf), bounds.getNorthEast()), maxItems); - children[SOUTHEAST] = new QuadTreeNode(new Bounds(new DegreePosition(bounds.getSouthWest().getLatDeg(), ewHalf), new DegreePosition(nsHalf, bounds.getNorthEast().getLngDeg())), maxItems); - children[SOUTHWEST] = new QuadTreeNode(new Bounds(bounds.getSouthWest(), new DegreePosition(nsHalf, ewHalf)), maxItems); - Vector> temp = new Vector>(items); - items.removeAllElements(); - for (Iterator> i=temp.iterator(); i.hasNext(); ) { - put(i.next()); - } - } - - /** - * Get the node that covers a certain lat/lon pair. - * - * @param lat up-down location in QuadTree Grid (latitude, y) - * @param lon left-right location in QuadTree Grid (longitude, x) - * @return node if child covers the point, null if the point is - * out of range. - */ - protected QuadTreeNode getChild(Position point) { - if (bounds.contains(point)) { - if (children != null) { - for (int i = 0; i < children.length; i++) { - if (children[i].bounds.contains(point)) - return children[i].getChild(point); - } - } else - return this; // no children, lat, lon here... - } - return null; - } - - /** - * Add a object into the tree at a location. - * - * @param lat up-down location in QuadTree Grid (latitude, y) - * @param lon left-right location in QuadTree Grid (longitude, x) - * @param obj object to add to the tree. - * @return true if the pution worked. - * @throws RuntimeException in case the leaf's lat/lng lies outside of the node's bounds. - * This would typically be caused by the point being outside the whole quad tree's bounds. - */ - public void put(Position point, T obj) { - put(new QuadTreeLeaf(point, obj)); - } - - public void replace(Position point, T newObj) { - boolean inThis = false; - - if (children == null) { - inThis = true; - } else { - QuadTreeNode child = getChild(point); - if (child == null) { - inThis = true; - } else { - child.replace(point, newObj); - } - } - - if (inThis) { - items.clear(); - items.add(new QuadTreeLeaf(point, newObj)); - } - } - - /** - * Add a QuadTreeLeaf into the tree at a location. - * - * @param leaf object-location composite - * @return true if the pution worked. - * @throws RuntimeException in case the leaf's lat/lng lies outside of the node's bounds. - * This would typically be caused by the point being outside the whole quad tree's bounds. - */ - public void put(QuadTreeLeaf leaf) { - if (children == null) { - this.items.addElement(leaf); - if (this.items.size() == 1) { - this.allTheSamePoint = true; - this.firstPoint = leaf.getPoint(); - } else { - if (!this.firstPoint.equals(leaf.getPoint())) { - this.allTheSamePoint = false; - } - } - if (this.items.size() > maxItems && !this.allTheSamePoint) { - split(); - } - } else { - QuadTreeNode node = getChild(leaf.getPoint()); - if (node != null) { - node.put(leaf); - } else { - throw new RuntimeException("leaf "+leaf+" not contained in bounds (("+ - bounds.getSouthWest().getLatDeg()+", "+bounds.getSouthWest().getLngDeg()+"), ("+ - bounds.getNorthEast().getLatDeg()+", "+bounds.getNorthEast().getLngDeg()+"))"); - } - } - } - - /** - * Remove a object out of the tree at a location. - * - * @param lat up-down location in QuadTree Grid (latitude, y) - * @param lon left-right location in QuadTree Grid (longitude, x) - * @return the object removed, null if the object not found. - */ - public T remove(Position point, T obj) { - return remove(new QuadTreeLeaf(point, obj)); - } - - /** - * Remove a QuadTreeLeaf out of the tree at a location. - * - * @param leaf object-location composite - * @return the object removed, null if the object not found. - */ - public T remove(QuadTreeLeaf leaf) { - if (children == null) { - // This must be the node that has it... - for (int i = 0; i < items.size(); i++) { - QuadTreeLeaf qtl = items.elementAt(i); - if (leaf.getObject() == qtl.getObject()) { - items.removeElementAt(i); - return qtl.getObject(); - } - } - } else { - QuadTreeNode node = getChild(leaf.getPoint()); - if (node != null) { - return node.remove(leaf); - } - } - return null; - } - - /** Clear the tree below this node. */ - public void clear() { - this.items.removeAllElements(); - if (children != null) { - for (int i = 0; i < children.length; i++) { - children[i].clear(); - } - children = null; - } - } - - /** - * Get an object closest to a point. - * - * @param lat up-down location in QuadTree Grid (latitude, y) - * @param lon left-right location in QuadTree Grid (longitude, x) - * @return the object that matches the best distance, null if no - * object was found. - */ - public T get(Position point) { - return get(point, Double.POSITIVE_INFINITY); - } - - /** - * Get an object closest to a point. If there are children at - * this node, then the children are searched. The children are - * checked first, to see if they are closer than the best distance - * already found. If a closer object is found, bestDistance will - * be updated with a new Double object that has the new distance. - * - * @param lat up-down location in QuadTree Grid (latitude, y) - * @param lon left-right location in QuadTree Grid (longitude, x) - * @param withinDistance maximum get distance. The distance is given - * as the square root of the sum of - * the squares of the latitude and longitude differences, respectively. - * It therefore does not correspond to any distance in meters or - * any euclidian distance at all. However, it should be good enough - * (at least outside the polar regions, and in particular for smaller - * regions), and in particular to find minimum distances. - * @return the object that matches the best distance, null if no - * closer object was found. - */ - public T get(Position point, double withinDistance) { - return get(point, new MutableDistance(withinDistance)); - } - - /** - * Get an object closest to a point. If there are children at - * this node, then the children are searched. The children are - * checked first, to see if they are closer than the best distance - * already found. If a closer object is found, bestDistance will - * be updated with a new Double object that has the new distance. - * @param point location in QuadTree Grid - * @param bestDistance the closest distance of the object found so - * far. The distance is given as the square root of the sum of - * the squares of the latitude and longitude differences, respectively. - * It therefore does not correspond to any distance in meters or - * any euclidian distance at all. However, it should be good enough - * (at least outside the polar regions, and in particular for smaller - * regions), and in particular to find minimum distances. - * - * @return the object that matches the best distance, null if no - * closer object was found. - */ - public T get(Position point, MutableDistance bestDistance) { - T closest = null; - if (children == null) { - // This must be the node that has it... - for (QuadTreeLeaf qtl:items) { - double distance = QuadTree.getLatLngDistance(point, qtl.getPoint()); - - if (distance < bestDistance.value) { - bestDistance.value = distance; - closest = qtl.getObject(); - } - } - return closest; - } else { - // Check the distance of the bounds of the children, - // versus the bestDistance. If there is a boundary that - // is closer, then it is possible that another node has an - // object that is closer. - for (int i = 0; i < children.length; i++) { - double childDistance = borderDistance(children[i].bounds, point); - if (childDistance < bestDistance.value) { - T test = children[i].get(point, bestDistance); - if (test != null) - closest = test; - } - } - } - return closest; - } - - /** - * A utility method to figure out the closest distance of a bound's border - * to a point. If the point is inside the bounds, return 0. - * - * @return closest distance to the point. - */ - private static double borderDistance(Bounds bounds, Position point) { - - double nsdistance; - double ewdistance; - - if (bounds.getSouthWest().getLatDeg() <= point.getLatDeg() && point.getLatDeg() <= bounds.getNorthEast().getLatDeg()) { - nsdistance = 0; - } else { - nsdistance = Math.min((Math.abs(point.getLatDeg() - bounds.getNorthEast().getLatDeg())), (Math.abs(point.getLatDeg() - - bounds.getSouthWest().getLatDeg()))); - } - - if (bounds.getSouthWest().getLngDeg() <= point.getLngDeg() && point.getLngDeg() <= bounds.getNorthEast().getLngDeg()) { - ewdistance = 0; - } else { - ewdistance = Math.min((Math.abs(point.getLngDeg() - bounds.getNorthEast().getLngDeg())), - (Math.abs(point.getLngDeg() - bounds.getSouthWest().getLngDeg()))); - } - - double distance = Math.sqrt(nsdistance*nsdistance + ewdistance*ewdistance); - return distance; - } - - /** - * Get all the objects within a bounding box. - * - * @param rect boundary of area to fill. - * @param vector current vector of objects. - * @return updated Vector of objects. - */ - public Collection get(Bounds rect, Collection vector) { - if (children == null) { - for (Iterator> i=items.iterator(); i.hasNext(); ) { - QuadTreeLeaf qtl = i.next(); - if (rect.contains(new DegreePosition(qtl.getPoint().getLatDeg(), qtl.getPoint().getLngDeg()))) { - vector.add(qtl.getObject()); - } - } - } else { - for (int i = 0; i < children.length; i++) { - if (children[i].bounds.containsBounds(rect)) { - children[i].get(rect, vector); - } - } - } - return vector; - } -} \ No newline at end of file diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/PositionTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/PositionTest.java index 1d3ab650c1a..8302305296e 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/PositionTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/PositionTest.java @@ -20,6 +20,14 @@ import com.sap.sailing.domain.common.tracking.impl.CompactGPSFixMovingImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; public class PositionTest { + @Test + public void testDistanceAcrossDateline() { + Position p1 = new DegreePosition(0, 179); + Position p2 = new DegreePosition(0, -179); + assertEquals(120., p1.getDistance(p2).getNauticalMiles(), 0.1); + assertEquals(120., p2.getDistance(p1).getNauticalMiles(), 0.1); + } + @Test public void testEqualityBetweenCompactAndVerbosePosition() { Position p1 = new DegreePosition(49.2, 008.3); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/QuadTreeTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/QuadTreeTest.java index d557698c362..1092a109018 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/QuadTreeTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/QuadTreeTest.java @@ -1,39 +1,1189 @@ package com.sap.sailing.domain.test; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; +import com.sap.sailing.domain.common.Bounds; import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.impl.BoundsImpl; import com.sap.sailing.domain.common.impl.DegreePosition; import com.sap.sailing.domain.common.quadtree.QuadTree; -import com.sap.sailing.domain.common.quadtree.impl.QuadTreeNode; +import com.sap.sailing.domain.common.quadtree.impl.Node; +import com.sap.sailing.domain.test.measurements.Measurement; +import com.sap.sailing.domain.test.measurements.MeasurementCase; +import com.sap.sailing.domain.test.measurements.MeasurementXMLFile; +import com.sap.sse.common.Util; public class QuadTreeTest { private class GLatLngQuadTree extends QuadTree { private static final long serialVersionUID = 386138477174564517L; - public GLatLngQuadTree(Position southWest, Position northEast, int i) { - super(southWest, northEast, i); + public GLatLngQuadTree(Position southWest, Position northEast, int maxItems) { + super(southWest, northEast, maxItems); } - public void put(Position x) { - super.put(x, x); + public Position put(Position x) { + return super.put(x, x); } } + + private DegreePosition p1; + private DegreePosition p2; + private DegreePosition p3; + private GLatLngQuadTree quadtree; + private static MeasurementXMLFile performanceReport; + private static MeasurementCase performanceReportCase; + + @BeforeClass + public static void setUpMeasurement() { + performanceReport = new MeasurementXMLFile(QuadTreeTest.class); + performanceReportCase = performanceReport.addCase(QuadTreeTest.class.getSimpleName()); + } - private static class QuadTreeWithPublicGetTop extends QuadTree { - private static final long serialVersionUID = -783622065160380333L; - @Override - public QuadTreeNode getTop() { - return super.getTop(); - } + @Before + public void setUp() { + quadtree = new GLatLngQuadTree(new DegreePosition(49, + 7), new DegreePosition(51, 9), /* maxItems */30); + quadtree.put(new DegreePosition(50.88505000000001, 7.995520000000001)); + quadtree.put(new DegreePosition(50.884930000000004, 7.996440000000001)); + quadtree.put(new DegreePosition(50.884840000000004, 7.99666)); + quadtree.put(new DegreePosition(50.8843, 7.997490000000001)); + quadtree.put(new DegreePosition(50.884240000000005, 7.997730000000001)); + quadtree.put(new DegreePosition(50.88423, 7.997980000000001)); + quadtree.put(new DegreePosition(50.8847, 7.999010000000001)); + quadtree.put(new DegreePosition(50.884600000000006, 7.999130000000001)); + quadtree.put(new DegreePosition(50.88448, 7.99938)); + quadtree.put(new DegreePosition(50.88421, 8.00014)); + quadtree.put(new DegreePosition(50.88382000000001, 8.00174)); + quadtree.put(new DegreePosition(50.88355000000001, 8.00263)); + quadtree.put(new DegreePosition(50.883570000000006, 8.00309)); + quadtree.put(new DegreePosition(50.883700000000005, 8.003530000000001)); + quadtree.put(new DegreePosition(50.88212000000001, 8.00539)); + quadtree.put(new DegreePosition(50.881620000000005, 8.006260000000001)); + quadtree.put(new DegreePosition(50.881080000000004, 8.007610000000001)); + quadtree.put(new DegreePosition(50.88103, 8.007900000000001)); + quadtree.put(new DegreePosition(50.88103, 8.009030000000001)); + quadtree.put(new DegreePosition(50.880880000000005, 8.009640000000001)); + quadtree.put(new DegreePosition(50.88047, 8.010860000000001)); + quadtree.put(new DegreePosition(50.880030000000005, 8.012500000000001)); + quadtree.put(new DegreePosition(50.87866, 8.016810000000001)); + quadtree.put(new DegreePosition(50.87832, 8.017790000000002)); + quadtree.put(new DegreePosition(50.878240000000005, 8.01793)); + quadtree.put(new DegreePosition(50.878150000000005, 8.01795)); + quadtree.put(new DegreePosition(50.87803, 8.01782)); + quadtree.put(new DegreePosition(50.87776, 8.01717)); + quadtree.put(new DegreePosition(50.8774, 8.01654)); + quadtree.put(new DegreePosition(50.87709, 8.01622)); + quadtree.put(new DegreePosition(50.87585000000001, 8.013850000000001)); + quadtree.put(new DegreePosition(50.87538000000001, 8.01304)); + quadtree.put(new DegreePosition(50.87402, 8.01111)); + quadtree.put(new DegreePosition(50.87028, 8.003960000000001)); + quadtree.put(new DegreePosition(50.869670000000006, 8.003160000000001)); + quadtree.put(new DegreePosition(50.86925, 8.002780000000001)); + quadtree.put(new DegreePosition(50.86858, 8.00244)); + quadtree.put(new DegreePosition(50.868, 8.002310000000001)); + quadtree.put(new DegreePosition(50.86739000000001, 8.00237)); + quadtree.put(new DegreePosition(50.867070000000005, 8.00248)); + quadtree.put(new DegreePosition(50.86674000000001, 8.00267)); + quadtree.put(new DegreePosition(50.865950000000005, 8.00333)); + quadtree.put(new DegreePosition(50.86545, 8.00398)); + quadtree.put(new DegreePosition(50.86459000000001, 8.0053)); + quadtree.put(new DegreePosition(50.86424, 8.00577)); + quadtree.put(new DegreePosition(50.863870000000006, 8.00618)); + quadtree.put(new DegreePosition(50.86352, 8.0065)); + quadtree.put(new DegreePosition(50.862970000000004, 8.006820000000001)); + quadtree.put(new DegreePosition(50.862370000000006, 8.00703)); + quadtree.put(new DegreePosition(50.86110000000001, 8.00722)); + quadtree.put(new DegreePosition(50.86061, 8.00721)); + quadtree.put(new DegreePosition(50.859860000000005, 8.00711)); + quadtree.put(new DegreePosition(50.85918, 8.006920000000001)); + quadtree.put(new DegreePosition(50.85824, 8.006120000000001)); + quadtree.put(new DegreePosition(50.85784, 8.005640000000001)); + quadtree.put(new DegreePosition(50.85757, 8.0052)); + quadtree.put(new DegreePosition(50.85752, 8.00496)); + quadtree.put(new DegreePosition(50.85752, 8.00463)); + quadtree.put(new DegreePosition(50.85963, 8.00209)); + quadtree.put(new DegreePosition(50.86046, 8.0008)); + quadtree.put(new DegreePosition(50.86081, 8.00008)); + quadtree.put(new DegreePosition(50.86113, 7.999230000000001)); + quadtree.put(new DegreePosition(50.86128, 7.998690000000001)); + quadtree.put(new DegreePosition(50.861430000000006, 7.997870000000001)); + quadtree.put(new DegreePosition(50.86149, 7.99706)); + quadtree.put(new DegreePosition(50.86149, 7.996150000000001)); + quadtree.put(new DegreePosition(50.86144, 7.9955300000000005)); + quadtree.put(new DegreePosition(50.86130000000001, 7.99476)); + quadtree.put(new DegreePosition(50.86106, 7.993900000000001)); + quadtree.put(new DegreePosition(50.860220000000005, 7.991490000000001)); + quadtree.put(new DegreePosition(50.859970000000004, 7.990360000000001)); + quadtree.put(new DegreePosition(50.859930000000006, 7.987780000000001)); + quadtree.put(new DegreePosition(50.859970000000004, 7.98737)); + quadtree.put(new DegreePosition(50.86059, 7.984820000000001)); + quadtree.put(new DegreePosition(50.86065000000001, 7.984260000000001)); + quadtree.put(new DegreePosition(50.860620000000004, 7.98359)); + quadtree.put(new DegreePosition(50.8605, 7.9831900000000005)); + quadtree.put(new DegreePosition(50.860310000000005, 7.98284)); + quadtree.put(new DegreePosition(50.86001, 7.982540000000001)); + quadtree.put(new DegreePosition(50.85971000000001, 7.982450000000001)); + quadtree.put(new DegreePosition(50.859410000000004, 7.98251)); + quadtree.put(new DegreePosition(50.85918, 7.982670000000001)); + quadtree.put(new DegreePosition(50.85898, 7.98291)); + quadtree.put(new DegreePosition(50.858790000000006, 7.983370000000001)); + quadtree.put(new DegreePosition(50.858520000000006, 7.9846)); + quadtree.put(new DegreePosition(50.8584, 7.98488)); + quadtree.put(new DegreePosition(50.858140000000006, 7.9851600000000005)); + quadtree.put(new DegreePosition(50.85756000000001, 7.9855100000000006)); + quadtree.put(new DegreePosition(50.85616, 7.985920000000001)); + quadtree.put(new DegreePosition(50.85548000000001, 7.98603)); + quadtree.put(new DegreePosition(50.85210000000001, 7.9863100000000005)); + quadtree.put(new DegreePosition(50.850970000000004, 7.98662)); + quadtree.put(new DegreePosition(50.849230000000006, 7.98739)); + quadtree.put(new DegreePosition(50.849030000000006, 7.98758)); + quadtree.put(new DegreePosition(50.84798000000001, 7.988300000000001)); + quadtree.put(new DegreePosition(50.84763, 7.988600000000001)); + quadtree.put(new DegreePosition(50.84695000000001, 7.989240000000001)); + quadtree.put(new DegreePosition(50.84591, 7.9903900000000005)); + quadtree.put(new DegreePosition(50.84514, 7.99143)); + quadtree.put(new DegreePosition(50.844370000000005, 7.992660000000001)); + quadtree.put(new DegreePosition(50.84355000000001, 7.994140000000001)); + quadtree.put(new DegreePosition(50.842800000000004, 7.9958800000000005)); + quadtree.put(new DegreePosition(50.84174, 7.99898)); + quadtree.put(new DegreePosition(50.84141, 7.9998700000000005)); + quadtree.put(new DegreePosition(50.84085, 8.00121)); + quadtree.put(new DegreePosition(50.84001000000001, 8.00285)); + quadtree.put(new DegreePosition(50.83823, 8.00586)); + quadtree.put(new DegreePosition(50.83747, 8.00736)); + quadtree.put(new DegreePosition(50.83702, 8.008410000000001)); + quadtree.put(new DegreePosition(50.83662, 8.00956)); + quadtree.put(new DegreePosition(50.83628, 8.01093)); + quadtree.put(new DegreePosition(50.83605000000001, 8.012160000000002)); + quadtree.put(new DegreePosition(50.83545, 8.016810000000001)); + quadtree.put(new DegreePosition(50.83491, 8.01938)); + quadtree.put(new DegreePosition(50.834250000000004, 8.02161)); + quadtree.put(new DegreePosition(50.83332000000001, 8.025210000000001)); + quadtree.put(new DegreePosition(50.8331, 8.0264)); + quadtree.put(new DegreePosition(50.83299, 8.027230000000001)); + quadtree.put(new DegreePosition(50.832890000000006, 8.028220000000001)); + quadtree.put(new DegreePosition(50.832820000000005, 8.0296)); + quadtree.put(new DegreePosition(50.83283, 8.030740000000002)); + quadtree.put(new DegreePosition(50.832950000000004, 8.03252)); + quadtree.put(new DegreePosition(50.833180000000006, 8.034790000000001)); + quadtree.put(new DegreePosition(50.833200000000005, 8.036140000000001)); + quadtree.put(new DegreePosition(50.83316000000001, 8.03739)); + quadtree.put(new DegreePosition(50.83312, 8.03801)); + quadtree.put(new DegreePosition(50.83299, 8.03907)); + quadtree.put(new DegreePosition(50.832730000000005, 8.04087)); + quadtree.put(new DegreePosition(50.83243, 8.042290000000001)); + quadtree.put(new DegreePosition(50.831880000000005, 8.04424)); + quadtree.put(new DegreePosition(50.83072000000001, 8.047070000000001)); + quadtree.put(new DegreePosition(50.8286, 8.051340000000001)); + quadtree.put(new DegreePosition(50.82793, 8.052610000000001)); + quadtree.put(new DegreePosition(50.827650000000006, 8.053410000000001)); + quadtree.put(new DegreePosition(50.827290000000005, 8.054680000000001)); + quadtree.put(new DegreePosition(50.82674, 8.05762)); + quadtree.put(new DegreePosition(50.826620000000005, 8.05882)); + quadtree.put(new DegreePosition(50.826550000000005, 8.06226)); + quadtree.put(new DegreePosition(50.82645, 8.0639)); + quadtree.put(new DegreePosition(50.8263, 8.065420000000001)); + quadtree.put(new DegreePosition(50.82591000000001, 8.06756)); + quadtree.put(new DegreePosition(50.825540000000004, 8.06884)); + quadtree.put(new DegreePosition(50.82486, 8.070490000000001)); + quadtree.put(new DegreePosition(50.82444, 8.07141)); + quadtree.put(new DegreePosition(50.82368, 8.07266)); + quadtree.put(new DegreePosition(50.821760000000005, 8.075130000000001)); + quadtree.put(new DegreePosition(50.821020000000004, 8.07614)); + quadtree.put(new DegreePosition(50.8205, 8.077)); + quadtree.put(new DegreePosition(50.819950000000006, 8.078240000000001)); + quadtree.put(new DegreePosition(50.81955000000001, 8.079450000000001)); + quadtree.put(new DegreePosition(50.819120000000005, 8.08103)); + quadtree.put(new DegreePosition(50.81859000000001, 8.08351)); + quadtree.put(new DegreePosition(50.818130000000004, 8.08783)); + quadtree.put(new DegreePosition(50.81796000000001, 8.088840000000001)); + quadtree.put(new DegreePosition(50.81774000000001, 8.08971)); + quadtree.put(new DegreePosition(50.817420000000006, 8.090670000000001)); + quadtree.put(new DegreePosition(50.81671000000001, 8.09238)); + quadtree.put(new DegreePosition(50.81647, 8.09285)); + quadtree.put(new DegreePosition(50.81557, 8.094370000000001)); + quadtree.put(new DegreePosition(50.814960000000006, 8.09521)); + quadtree.put(new DegreePosition(50.81427000000001, 8.09603)); + quadtree.put(new DegreePosition(50.81369, 8.0966)); + quadtree.put(new DegreePosition(50.81291, 8.09722)); + quadtree.put(new DegreePosition(50.81228, 8.09763)); + quadtree.put(new DegreePosition(50.81022, 8.098590000000002)); + quadtree.put(new DegreePosition(50.80885000000001, 8.098980000000001)); + quadtree.put(new DegreePosition(50.806900000000006, 8.09918)); + quadtree.put(new DegreePosition(50.805350000000004, 8.09904)); + quadtree.put(new DegreePosition(50.804460000000006, 8.098790000000001)); + quadtree.put(new DegreePosition(50.803180000000005, 8.09833)); + quadtree.put(new DegreePosition(50.79974000000001, 8.09685)); + quadtree.put(new DegreePosition(50.798950000000005, 8.09665)); + quadtree.put(new DegreePosition(50.797990000000006, 8.09664)); + quadtree.put(new DegreePosition(50.79683000000001, 8.096760000000002)); + quadtree.put(new DegreePosition(50.795730000000006, 8.09699)); + quadtree.put(new DegreePosition(50.794630000000005, 8.097520000000001)); + quadtree.put(new DegreePosition(50.79238, 8.099340000000002)); + quadtree.put(new DegreePosition(50.79153, 8.10016)); + quadtree.put(new DegreePosition(50.79068, 8.10111)); + quadtree.put(new DegreePosition(50.789970000000004, 8.10195)); + quadtree.put(new DegreePosition(50.78891, 8.103380000000001)); + quadtree.put(new DegreePosition(50.78833, 8.104230000000001)); + quadtree.put(new DegreePosition(50.78759, 8.10539)); + quadtree.put(new DegreePosition(50.786970000000004, 8.10646)); + quadtree.put(new DegreePosition(50.78605, 8.10823)); + quadtree.put(new DegreePosition(50.78566000000001, 8.10905)); + quadtree.put(new DegreePosition(50.784890000000004, 8.11107)); + quadtree.put(new DegreePosition(50.784670000000006, 8.11194)); + quadtree.put(new DegreePosition(50.78437, 8.11344)); + quadtree.put(new DegreePosition(50.784200000000006, 8.11463)); + quadtree.put(new DegreePosition(50.78407000000001, 8.11609)); + quadtree.put(new DegreePosition(50.78407000000001, 8.11761)); + quadtree.put(new DegreePosition(50.78412, 8.118820000000001)); + quadtree.put(new DegreePosition(50.784240000000004, 8.11996)); + quadtree.put(new DegreePosition(50.78457, 8.121500000000001)); + quadtree.put(new DegreePosition(50.785250000000005, 8.12428)); + quadtree.put(new DegreePosition(50.78555, 8.125720000000001)); + quadtree.put(new DegreePosition(50.78586000000001, 8.12766)); + quadtree.put(new DegreePosition(50.786060000000006, 8.129610000000001)); + quadtree.put(new DegreePosition(50.78614, 8.13101)); + quadtree.put(new DegreePosition(50.78609, 8.13326)); + quadtree.put(new DegreePosition(50.78598, 8.13451)); + quadtree.put(new DegreePosition(50.78578, 8.135900000000001)); + quadtree.put(new DegreePosition(50.7854, 8.137880000000001)); + quadtree.put(new DegreePosition(50.78511, 8.13907)); + quadtree.put(new DegreePosition(50.784330000000004, 8.14145)); + quadtree.put(new DegreePosition(50.783840000000005, 8.14282)); + quadtree.put(new DegreePosition(50.78352, 8.143510000000001)); + quadtree.put(new DegreePosition(50.78285, 8.1446)); + quadtree.put(new DegreePosition(50.781650000000006, 8.14638)); + quadtree.put(new DegreePosition(50.781330000000004, 8.146920000000001)); + quadtree.put(new DegreePosition(50.780280000000005, 8.148060000000001)); + quadtree.put(new DegreePosition(50.77908000000001, 8.149090000000001)); + quadtree.put(new DegreePosition(50.7781, 8.14973)); + quadtree.put(new DegreePosition(50.77716, 8.150160000000001)); + quadtree.put(new DegreePosition(50.77579, 8.15053)); + quadtree.put(new DegreePosition(50.773810000000005, 8.150770000000001)); + quadtree.put(new DegreePosition(50.772470000000006, 8.15085)); + quadtree.put(new DegreePosition(50.77046000000001, 8.15074)); + quadtree.put(new DegreePosition(50.76778, 8.15074)); + quadtree.put(new DegreePosition(50.76690000000001, 8.15079)); + quadtree.put(new DegreePosition(50.76615, 8.15093)); + quadtree.put(new DegreePosition(50.76543, 8.15116)); + quadtree.put(new DegreePosition(50.764480000000006, 8.151670000000001)); + quadtree.put(new DegreePosition(50.763690000000004, 8.15222)); + quadtree.put(new DegreePosition(50.76299, 8.152890000000001)); + quadtree.put(new DegreePosition(50.76243, 8.15352)); + quadtree.put(new DegreePosition(50.76185, 8.15432)); + quadtree.put(new DegreePosition(50.761190000000006, 8.15549)); + quadtree.put(new DegreePosition(50.760670000000005, 8.1567)); + quadtree.put(new DegreePosition(50.76019, 8.15832)); + quadtree.put(new DegreePosition(50.759910000000005, 8.15996)); + quadtree.put(new DegreePosition(50.75983, 8.16092)); + quadtree.put(new DegreePosition(50.75974, 8.16243)); + quadtree.put(new DegreePosition(50.759780000000006, 8.164000000000001)); + quadtree.put(new DegreePosition(50.75992, 8.16568)); + quadtree.put(new DegreePosition(50.75997, 8.168050000000001)); + quadtree.put(new DegreePosition(50.75992, 8.16923)); + quadtree.put(new DegreePosition(50.759820000000005, 8.170480000000001)); + quadtree.put(new DegreePosition(50.75959, 8.172130000000001)); + quadtree.put(new DegreePosition(50.759190000000004, 8.17365)); + quadtree.put(new DegreePosition(50.75893000000001, 8.17436)); + quadtree.put(new DegreePosition(50.75638000000001, 8.18037)); + quadtree.put(new DegreePosition(50.755810000000004, 8.181840000000001)); + quadtree.put(new DegreePosition(50.755410000000005, 8.18307)); + quadtree.put(new DegreePosition(50.755160000000004, 8.184000000000001)); + quadtree.put(new DegreePosition(50.75482, 8.185960000000001)); + quadtree.put(new DegreePosition(50.75464, 8.18824)); + quadtree.put(new DegreePosition(50.75457, 8.19096)); + quadtree.put(new DegreePosition(50.754670000000004, 8.193750000000001)); + quadtree.put(new DegreePosition(50.75482, 8.19589)); + quadtree.put(new DegreePosition(50.75533, 8.20124)); + quadtree.put(new DegreePosition(50.75542, 8.202910000000001)); + quadtree.put(new DegreePosition(50.755390000000006, 8.20532)); + quadtree.put(new DegreePosition(50.75526000000001, 8.206850000000001)); + quadtree.put(new DegreePosition(50.75502, 8.20803)); + quadtree.put(new DegreePosition(50.75486, 8.20864)); + quadtree.put(new DegreePosition(50.75448, 8.209750000000001)); + quadtree.put(new DegreePosition(50.75424, 8.210320000000001)); + quadtree.put(new DegreePosition(50.75347000000001, 8.211730000000001)); + quadtree.put(new DegreePosition(50.75301, 8.21236)); + quadtree.put(new DegreePosition(50.75206000000001, 8.213370000000001)); + quadtree.put(new DegreePosition(50.74982000000001, 8.215440000000001)); + quadtree.put(new DegreePosition(50.748900000000006, 8.21657)); + quadtree.put(new DegreePosition(50.74851, 8.21718)); + quadtree.put(new DegreePosition(50.748200000000004, 8.21775)); + quadtree.put(new DegreePosition(50.74777, 8.21879)); + quadtree.put(new DegreePosition(50.7475, 8.21968)); + quadtree.put(new DegreePosition(50.747240000000005, 8.220880000000001)); + quadtree.put(new DegreePosition(50.7471, 8.22189)); + quadtree.put(new DegreePosition(50.74703, 8.222710000000001)); + quadtree.put(new DegreePosition(50.746990000000004, 8.22573)); + quadtree.put(new DegreePosition(50.74696, 8.22653)); + quadtree.put(new DegreePosition(50.74687, 8.22747)); + quadtree.put(new DegreePosition(50.746680000000005, 8.228530000000001)); + quadtree.put(new DegreePosition(50.746410000000004, 8.22976)); + quadtree.put(new DegreePosition(50.74609, 8.23095)); + quadtree.put(new DegreePosition(50.74515, 8.23367)); + quadtree.put(new DegreePosition(50.744620000000005, 8.235650000000001)); + quadtree.put(new DegreePosition(50.744310000000006, 8.237150000000002)); + quadtree.put(new DegreePosition(50.744150000000005, 8.238480000000001)); + quadtree.put(new DegreePosition(50.7441, 8.240540000000001)); + quadtree.put(new DegreePosition(50.74418000000001, 8.24193)); + quadtree.put(new DegreePosition(50.74445000000001, 8.24365)); + quadtree.put(new DegreePosition(50.745020000000004, 8.245940000000001)); + quadtree.put(new DegreePosition(50.74539000000001, 8.24769)); + quadtree.put(new DegreePosition(50.74557, 8.24881)); + quadtree.put(new DegreePosition(50.74562, 8.249590000000001)); + quadtree.put(new DegreePosition(50.7456, 8.250290000000001)); + quadtree.put(new DegreePosition(50.74542, 8.25223)); + quadtree.put(new DegreePosition(50.74519, 8.253340000000001)); + quadtree.put(new DegreePosition(50.7449, 8.2543)); + quadtree.put(new DegreePosition(50.74461, 8.25505)); + quadtree.put(new DegreePosition(50.74306000000001, 8.25831)); + quadtree.put(new DegreePosition(50.74279000000001, 8.25904)); + quadtree.put(new DegreePosition(50.74255, 8.25988)); + quadtree.put(new DegreePosition(50.742270000000005, 8.2612)); + quadtree.put(new DegreePosition(50.74213, 8.262070000000001)); + quadtree.put(new DegreePosition(50.742070000000005, 8.26314)); + quadtree.put(new DegreePosition(50.742090000000005, 8.26567)); + quadtree.put(new DegreePosition(50.741980000000005, 8.26735)); + quadtree.put(new DegreePosition(50.74181, 8.2687)); + quadtree.put(new DegreePosition(50.741670000000006, 8.26931)); + quadtree.put(new DegreePosition(50.741080000000004, 8.27088)); + quadtree.put(new DegreePosition(50.74072, 8.27158)); + quadtree.put(new DegreePosition(50.740030000000004, 8.27257)); + quadtree.put(new DegreePosition(50.73962, 8.273000000000001)); + quadtree.put(new DegreePosition(50.73875, 8.27365)); + quadtree.put(new DegreePosition(50.73783, 8.27405)); + quadtree.put(new DegreePosition(50.73745, 8.27416)); + quadtree.put(new DegreePosition(50.736830000000005, 8.27424)); + quadtree.put(new DegreePosition(50.734120000000004, 8.274090000000001)); + quadtree.put(new DegreePosition(50.73353, 8.27411)); + quadtree.put(new DegreePosition(50.732890000000005, 8.27424)); + quadtree.put(new DegreePosition(50.73174, 8.274790000000001)); + quadtree.put(new DegreePosition(50.73114, 8.27524)); + quadtree.put(new DegreePosition(50.7306, 8.27574)); + quadtree.put(new DegreePosition(50.72831000000001, 8.27865)); + quadtree.put(new DegreePosition(50.727430000000005, 8.279480000000001)); + quadtree.put(new DegreePosition(50.72471, 8.28134)); + quadtree.put(new DegreePosition(50.72368, 8.282210000000001)); + quadtree.put(new DegreePosition(50.7229, 8.28307)); + quadtree.put(new DegreePosition(50.72126, 8.28542)); + quadtree.put(new DegreePosition(50.72023, 8.28669)); + quadtree.put(new DegreePosition(50.71963, 8.28725)); + quadtree.put(new DegreePosition(50.71885, 8.287880000000001)); + quadtree.put(new DegreePosition(50.718120000000006, 8.28832)); + quadtree.put(new DegreePosition(50.7173, 8.2887)); + quadtree.put(new DegreePosition(50.71656, 8.28897)); + quadtree.put(new DegreePosition(50.71553, 8.28916)); + quadtree.put(new DegreePosition(50.71408, 8.28923)); + quadtree.put(new DegreePosition(50.713060000000006, 8.28913)); + quadtree.put(new DegreePosition(50.709050000000005, 8.28805)); + quadtree.put(new DegreePosition(50.70792, 8.28781)); + quadtree.put(new DegreePosition(50.70673000000001, 8.28772)); + quadtree.put(new DegreePosition(50.705130000000004, 8.28782)); + quadtree.put(new DegreePosition(50.70335000000001, 8.28827)); + quadtree.put(new DegreePosition(50.70219, 8.28876)); + quadtree.put(new DegreePosition(50.70096, 8.289520000000001)); + quadtree.put(new DegreePosition(50.697030000000005, 8.29296)); + quadtree.put(new DegreePosition(50.69567000000001, 8.294)); + quadtree.put(new DegreePosition(50.69485, 8.294540000000001)); + quadtree.put(new DegreePosition(50.69411, 8.29495)); + quadtree.put(new DegreePosition(50.6933, 8.295300000000001)); + quadtree.put(new DegreePosition(50.692690000000006, 8.295490000000001)); + quadtree.put(new DegreePosition(50.692040000000006, 8.29561)); + quadtree.put(new DegreePosition(50.69153000000001, 8.29564)); + quadtree.put(new DegreePosition(50.69035, 8.295390000000001)); + quadtree.put(new DegreePosition(50.68981, 8.29517)); + quadtree.put(new DegreePosition(50.68932, 8.2949)); + quadtree.put(new DegreePosition(50.688970000000005, 8.29465)); + quadtree.put(new DegreePosition(50.68847, 8.29418)); + quadtree.put(new DegreePosition(50.687760000000004, 8.293230000000001)); + quadtree.put(new DegreePosition(50.68713, 8.29218)); + quadtree.put(new DegreePosition(50.68657, 8.29096)); + quadtree.put(new DegreePosition(50.68558, 8.289000000000001)); + quadtree.put(new DegreePosition(50.684940000000005, 8.28805)); + quadtree.put(new DegreePosition(50.684430000000006, 8.28739)); + quadtree.put(new DegreePosition(50.682970000000005, 8.2859)); + quadtree.put(new DegreePosition(50.68198, 8.28515)); + quadtree.put(new DegreePosition(50.68065000000001, 8.28434)); + quadtree.put(new DegreePosition(50.679410000000004, 8.28377)); + quadtree.put(new DegreePosition(50.67868000000001, 8.28353)); + quadtree.put(new DegreePosition(50.67734, 8.283330000000001)); + quadtree.put(new DegreePosition(50.676190000000005, 8.28331)); + quadtree.put(new DegreePosition(50.674110000000006, 8.28378)); + quadtree.put(new DegreePosition(50.672760000000004, 8.28443)); + quadtree.put(new DegreePosition(50.67183000000001, 8.28505)); + quadtree.put(new DegreePosition(50.671130000000005, 8.28561)); + quadtree.put(new DegreePosition(50.67058, 8.286140000000001)); + quadtree.put(new DegreePosition(50.66993, 8.28687)); + quadtree.put(new DegreePosition(50.66884, 8.28832)); + quadtree.put(new DegreePosition(50.66789000000001, 8.28984)); + quadtree.put(new DegreePosition(50.667030000000004, 8.291440000000001)); + quadtree.put(new DegreePosition(50.66601000000001, 8.29364)); + quadtree.put(new DegreePosition(50.665350000000004, 8.295240000000002)); + quadtree.put(new DegreePosition(50.66480000000001, 8.29676)); + quadtree.put(new DegreePosition(50.66442000000001, 8.29808)); + quadtree.put(new DegreePosition(50.66405, 8.299660000000001)); + quadtree.put(new DegreePosition(50.663720000000005, 8.30133)); + quadtree.put(new DegreePosition(50.66330000000001, 8.304300000000001)); + quadtree.put(new DegreePosition(50.66290000000001, 8.307960000000001)); + quadtree.put(new DegreePosition(50.662670000000006, 8.309560000000001)); + quadtree.put(new DegreePosition(50.6623, 8.31123)); + quadtree.put(new DegreePosition(50.66174, 8.313260000000001)); + quadtree.put(new DegreePosition(50.660970000000006, 8.315370000000001)); + quadtree.put(new DegreePosition(50.660320000000006, 8.316650000000001)); + quadtree.put(new DegreePosition(50.659740000000006, 8.317590000000001)); + quadtree.put(new DegreePosition(50.65899, 8.318570000000001)); + quadtree.put(new DegreePosition(50.658210000000004, 8.3193)); + quadtree.put(new DegreePosition(50.657070000000004, 8.31994)); + quadtree.put(new DegreePosition(50.65578000000001, 8.320300000000001)); + quadtree.put(new DegreePosition(50.65391, 8.320400000000001)); + quadtree.put(new DegreePosition(50.65328, 8.320500000000001)); + quadtree.put(new DegreePosition(50.65240000000001, 8.32074)); + quadtree.put(new DegreePosition(50.65128000000001, 8.32118)); + quadtree.put(new DegreePosition(50.65091, 8.32137)); + quadtree.put(new DegreePosition(50.6465, 8.32409)); + quadtree.put(new DegreePosition(50.645360000000004, 8.32454)); + quadtree.put(new DegreePosition(50.644740000000006, 8.32469)); + quadtree.put(new DegreePosition(50.64193, 8.32482)); + quadtree.put(new DegreePosition(50.639920000000004, 8.32511)); + quadtree.put(new DegreePosition(50.63812, 8.325650000000001)); + quadtree.put(new DegreePosition(50.63673000000001, 8.326400000000001)); + quadtree.put(new DegreePosition(50.635740000000006, 8.32704)); + quadtree.put(new DegreePosition(50.634570000000004, 8.32797)); + quadtree.put(new DegreePosition(50.63354, 8.32891)); + quadtree.put(new DegreePosition(50.63253, 8.32995)); + quadtree.put(new DegreePosition(50.629650000000005, 8.33336)); + quadtree.put(new DegreePosition(50.62903000000001, 8.33422)); + quadtree.put(new DegreePosition(50.628550000000004, 8.335)); + quadtree.put(new DegreePosition(50.62765, 8.33667)); + quadtree.put(new DegreePosition(50.627250000000004, 8.33755)); + quadtree.put(new DegreePosition(50.626760000000004, 8.33876)); + quadtree.put(new DegreePosition(50.62648, 8.33961)); + quadtree.put(new DegreePosition(50.62586, 8.341890000000001)); + quadtree.put(new DegreePosition(50.62556000000001, 8.34319)); + quadtree.put(new DegreePosition(50.62519, 8.34521)); + quadtree.put(new DegreePosition(50.624990000000004, 8.34656)); + quadtree.put(new DegreePosition(50.62485, 8.34781)); + quadtree.put(new DegreePosition(50.6246, 8.3511)); + quadtree.put(new DegreePosition(50.62435000000001, 8.352910000000001)); + quadtree.put(new DegreePosition(50.624050000000004, 8.3544)); + quadtree.put(new DegreePosition(50.623810000000006, 8.35543)); + quadtree.put(new DegreePosition(50.62366, 8.35593)); + quadtree.put(new DegreePosition(50.622240000000005, 8.359910000000001)); + quadtree.put(new DegreePosition(50.621770000000005, 8.36156)); + quadtree.put(new DegreePosition(50.62156, 8.362480000000001)); + quadtree.put(new DegreePosition(50.621230000000004, 8.3644)); + quadtree.put(new DegreePosition(50.62078, 8.36975)); + quadtree.put(new DegreePosition(50.620520000000006, 8.37114)); + quadtree.put(new DegreePosition(50.620160000000006, 8.37249)); + quadtree.put(new DegreePosition(50.61988, 8.373320000000001)); + quadtree.put(new DegreePosition(50.61932, 8.374690000000001)); + quadtree.put(new DegreePosition(50.61887, 8.375950000000001)); + quadtree.put(new DegreePosition(50.618570000000005, 8.37725)); + quadtree.put(new DegreePosition(50.61827, 8.37898)); + quadtree.put(new DegreePosition(50.618170000000006, 8.380270000000001)); + quadtree.put(new DegreePosition(50.61816, 8.382190000000001)); + quadtree.put(new DegreePosition(50.618520000000004, 8.389460000000001)); + quadtree.put(new DegreePosition(50.618570000000005, 8.39309)); + quadtree.put(new DegreePosition(50.618500000000004, 8.394480000000001)); + quadtree.put(new DegreePosition(50.618410000000004, 8.395470000000001)); + quadtree.put(new DegreePosition(50.61824000000001, 8.39675)); + quadtree.put(new DegreePosition(50.618080000000006, 8.39764)); + quadtree.put(new DegreePosition(50.61777000000001, 8.39906)); + quadtree.put(new DegreePosition(50.61713, 8.40116)); + quadtree.put(new DegreePosition(50.61679, 8.40215)); + quadtree.put(new DegreePosition(50.612660000000005, 8.413)); + quadtree.put(new DegreePosition(50.61168000000001, 8.415470000000001)); + quadtree.put(new DegreePosition(50.611430000000006, 8.41623)); + quadtree.put(new DegreePosition(50.61102, 8.41787)); + quadtree.put(new DegreePosition(50.61056000000001, 8.42032)); + quadtree.put(new DegreePosition(50.61019, 8.4238)); + quadtree.put(new DegreePosition(50.60992, 8.42535)); + quadtree.put(new DegreePosition(50.60947, 8.42707)); + quadtree.put(new DegreePosition(50.60904000000001, 8.42833)); + quadtree.put(new DegreePosition(50.60857000000001, 8.42956)); + quadtree.put(new DegreePosition(50.60792000000001, 8.43158)); + quadtree.put(new DegreePosition(50.60761, 8.432680000000001)); + quadtree.put(new DegreePosition(50.60723, 8.434370000000001)); + quadtree.put(new DegreePosition(50.60701, 8.43645)); + quadtree.put(new DegreePosition(50.60698000000001, 8.43796)); + quadtree.put(new DegreePosition(50.6071, 8.44045)); + quadtree.put(new DegreePosition(50.60718000000001, 8.443100000000001)); + quadtree.put(new DegreePosition(50.60717, 8.444220000000001)); + quadtree.put(new DegreePosition(50.607020000000006, 8.446140000000002)); + quadtree.put(new DegreePosition(50.606770000000004, 8.44772)); + quadtree.put(new DegreePosition(50.60647, 8.44902)); + quadtree.put(new DegreePosition(50.606100000000005, 8.450230000000001)); + quadtree.put(new DegreePosition(50.60551, 8.45195)); + quadtree.put(new DegreePosition(50.605030000000006, 8.45358)); + quadtree.put(new DegreePosition(50.60465000000001, 8.45495)); + quadtree.put(new DegreePosition(50.60445000000001, 8.455950000000001)); + quadtree.put(new DegreePosition(50.60427000000001, 8.457230000000001)); + quadtree.put(new DegreePosition(50.60421, 8.458060000000001)); + quadtree.put(new DegreePosition(50.60419, 8.45945)); + quadtree.put(new DegreePosition(50.6043, 8.46292)); + quadtree.put(new DegreePosition(50.604290000000006, 8.46471)); + quadtree.put(new DegreePosition(50.60416000000001, 8.4664)); + quadtree.put(new DegreePosition(50.603930000000005, 8.468)); + quadtree.put(new DegreePosition(50.603790000000004, 8.46873)); + quadtree.put(new DegreePosition(50.603570000000005, 8.469650000000001)); + quadtree.put(new DegreePosition(50.60318, 8.471)); + quadtree.put(new DegreePosition(50.60242, 8.473030000000001)); + quadtree.put(new DegreePosition(50.60193, 8.474110000000001)); + quadtree.put(new DegreePosition(50.60146, 8.47493)); + quadtree.put(new DegreePosition(50.600730000000006, 8.47606)); + quadtree.put(new DegreePosition(50.599160000000005, 8.478340000000001)); + quadtree.put(new DegreePosition(50.59787000000001, 8.480580000000002)); + quadtree.put(new DegreePosition(50.59725, 8.48202)); + quadtree.put(new DegreePosition(50.59673, 8.48366)); + quadtree.put(new DegreePosition(50.596270000000004, 8.48583)); + quadtree.put(new DegreePosition(50.59617, 8.48643)); + quadtree.put(new DegreePosition(50.596000000000004, 8.48804)); + quadtree.put(new DegreePosition(50.59592000000001, 8.490260000000001)); + quadtree.put(new DegreePosition(50.59588, 8.49361)); + quadtree.put(new DegreePosition(50.59581000000001, 8.49463)); + quadtree.put(new DegreePosition(50.595710000000004, 8.49549)); + quadtree.put(new DegreePosition(50.59539, 8.49712)); + quadtree.put(new DegreePosition(50.59505000000001, 8.49849)); + quadtree.put(new DegreePosition(50.594030000000004, 8.50145)); + quadtree.put(new DegreePosition(50.59357000000001, 8.50289)); + quadtree.put(new DegreePosition(50.593340000000005, 8.50379)); + quadtree.put(new DegreePosition(50.593160000000005, 8.50468)); + quadtree.put(new DegreePosition(50.59292000000001, 8.506120000000001)); + quadtree.put(new DegreePosition(50.59279, 8.50716)); + quadtree.put(new DegreePosition(50.592740000000006, 8.50793)); + quadtree.put(new DegreePosition(50.592740000000006, 8.50988)); + quadtree.put(new DegreePosition(50.59282, 8.51248)); + quadtree.put(new DegreePosition(50.59273, 8.513850000000001)); + quadtree.put(new DegreePosition(50.59245000000001, 8.5157)); + quadtree.put(new DegreePosition(50.592110000000005, 8.51736)); + quadtree.put(new DegreePosition(50.59109, 8.52072)); + quadtree.put(new DegreePosition(50.58995, 8.52393)); + quadtree.put(new DegreePosition(50.58919, 8.525780000000001)); + quadtree.put(new DegreePosition(50.588350000000005, 8.52753)); + quadtree.put(new DegreePosition(50.586940000000006, 8.53031)); + quadtree.put(new DegreePosition(50.585660000000004, 8.5327)); + quadtree.put(new DegreePosition(50.58467, 8.534270000000001)); + quadtree.put(new DegreePosition(50.582950000000004, 8.53668)); + quadtree.put(new DegreePosition(50.58055, 8.539750000000002)); + quadtree.put(new DegreePosition(50.57909, 8.541250000000002)); + quadtree.put(new DegreePosition(50.578230000000005, 8.542060000000001)); + quadtree.put(new DegreePosition(50.57721, 8.542910000000001)); + quadtree.put(new DegreePosition(50.57509, 8.544360000000001)); + quadtree.put(new DegreePosition(50.572190000000006, 8.546000000000001)); + quadtree.put(new DegreePosition(50.56996, 8.54697)); + quadtree.put(new DegreePosition(50.567350000000005, 8.548210000000001)); + quadtree.put(new DegreePosition(50.566590000000005, 8.548670000000001)); + quadtree.put(new DegreePosition(50.565740000000005, 8.5493)); + quadtree.put(new DegreePosition(50.56519, 8.54981)); + quadtree.put(new DegreePosition(50.56466, 8.55035)); + quadtree.put(new DegreePosition(50.56418000000001, 8.551010000000002)); + quadtree.put(new DegreePosition(50.56376, 8.551630000000001)); + quadtree.put(new DegreePosition(50.56293, 8.55311)); + quadtree.put(new DegreePosition(50.56206, 8.55527)); + quadtree.put(new DegreePosition(50.56136000000001, 8.55738)); + quadtree.put(new DegreePosition(50.56071000000001, 8.55915)); + quadtree.put(new DegreePosition(50.560230000000004, 8.560160000000002)); + quadtree.put(new DegreePosition(50.55978, 8.560970000000001)); + quadtree.put(new DegreePosition(50.55922, 8.56179)); + quadtree.put(new DegreePosition(50.558910000000004, 8.56215)); + quadtree.put(new DegreePosition(50.55834, 8.562700000000001)); + quadtree.put(new DegreePosition(50.55731, 8.56347)); + quadtree.put(new DegreePosition(50.55677000000001, 8.56377)); + quadtree.put(new DegreePosition(50.55624, 8.563960000000002)); + quadtree.put(new DegreePosition(50.55556000000001, 8.564110000000001)); + quadtree.put(new DegreePosition(50.55353, 8.564390000000001)); + quadtree.put(new DegreePosition(50.552040000000005, 8.56466)); + quadtree.put(new DegreePosition(50.55109, 8.56494)); + quadtree.put(new DegreePosition(50.550160000000005, 8.56536)); + quadtree.put(new DegreePosition(50.549730000000004, 8.565620000000001)); + quadtree.put(new DegreePosition(50.54919, 8.56601)); + quadtree.put(new DegreePosition(50.548460000000006, 8.56667)); + quadtree.put(new DegreePosition(50.54798, 8.567250000000001)); + quadtree.put(new DegreePosition(50.5469, 8.56872)); + quadtree.put(new DegreePosition(50.54536, 8.57126)); + quadtree.put(new DegreePosition(50.542260000000006, 8.576590000000001)); + quadtree.put(new DegreePosition(50.541430000000005, 8.577720000000001)); + quadtree.put(new DegreePosition(50.540580000000006, 8.57877)); + quadtree.put(new DegreePosition(50.539480000000005, 8.57994)); + quadtree.put(new DegreePosition(50.537870000000005, 8.58139)); + quadtree.put(new DegreePosition(50.53676, 8.582270000000001)); + quadtree.put(new DegreePosition(50.534110000000005, 8.58411)); + quadtree.put(new DegreePosition(50.53333000000001, 8.58478)); + quadtree.put(new DegreePosition(50.53266000000001, 8.585450000000002)); + quadtree.put(new DegreePosition(50.5317, 8.586540000000001)); + quadtree.put(new DegreePosition(50.53099, 8.587610000000002)); + quadtree.put(new DegreePosition(50.53056, 8.58835)); + quadtree.put(new DegreePosition(50.530080000000005, 8.58932)); + quadtree.put(new DegreePosition(50.52947, 8.590900000000001)); + quadtree.put(new DegreePosition(50.529050000000005, 8.592310000000001)); + quadtree.put(new DegreePosition(50.528800000000004, 8.593430000000001)); + quadtree.put(new DegreePosition(50.528620000000004, 8.594510000000001)); + quadtree.put(new DegreePosition(50.52828, 8.597700000000001)); + quadtree.put(new DegreePosition(50.527750000000005, 8.60692)); + quadtree.put(new DegreePosition(50.52731000000001, 8.61212)); + quadtree.put(new DegreePosition(50.526300000000006, 8.62259)); + quadtree.put(new DegreePosition(50.525800000000004, 8.626420000000001)); + quadtree.put(new DegreePosition(50.52514000000001, 8.630510000000001)); + quadtree.put(new DegreePosition(50.52481, 8.63277)); + quadtree.put(new DegreePosition(50.524010000000004, 8.6376)); + quadtree.put(new DegreePosition(50.52364000000001, 8.64067)); + quadtree.put(new DegreePosition(50.522420000000004, 8.645380000000001)); + quadtree.put(new DegreePosition(50.52181, 8.64794)); + quadtree.put(new DegreePosition(50.521530000000006, 8.648950000000001)); + quadtree.put(new DegreePosition(50.52031, 8.654100000000001)); + quadtree.put(new DegreePosition(50.51888, 8.65944)); + quadtree.put(new DegreePosition(50.51749, 8.66398)); + quadtree.put(new DegreePosition(50.51699000000001, 8.66531)); + quadtree.put(new DegreePosition(50.516650000000006, 8.666110000000002)); + quadtree.put(new DegreePosition(50.515150000000006, 8.66932)); + quadtree.put(new DegreePosition(50.5146, 8.67041)); + quadtree.put(new DegreePosition(50.513670000000005, 8.6721)); + quadtree.put(new DegreePosition(50.51285000000001, 8.673440000000001)); + quadtree.put(new DegreePosition(50.511810000000004, 8.674930000000002)); + quadtree.put(new DegreePosition(50.510630000000006, 8.67633)); + quadtree.put(new DegreePosition(50.50940000000001, 8.677700000000002)); + quadtree.put(new DegreePosition(50.508810000000004, 8.67824)); + quadtree.put(new DegreePosition(50.50750000000001, 8.67932)); + quadtree.put(new DegreePosition(50.50681, 8.679810000000002)); + quadtree.put(new DegreePosition(50.50526000000001, 8.680760000000001)); + quadtree.put(new DegreePosition(50.504470000000005, 8.68116)); + quadtree.put(new DegreePosition(50.50274, 8.681830000000001)); + quadtree.put(new DegreePosition(50.50198, 8.682070000000001)); + quadtree.put(new DegreePosition(50.498810000000006, 8.682690000000001)); + quadtree.put(new DegreePosition(50.49728, 8.68313)); + quadtree.put(new DegreePosition(50.49476000000001, 8.68368)); + quadtree.put(new DegreePosition(50.49369, 8.684050000000001)); + quadtree.put(new DegreePosition(50.49269, 8.68449)); + quadtree.put(new DegreePosition(50.49157, 8.68506)); + quadtree.put(new DegreePosition(50.490520000000004, 8.685740000000001)); + quadtree.put(new DegreePosition(50.48989, 8.68622)); + quadtree.put(new DegreePosition(50.48901000000001, 8.686950000000001)); + quadtree.put(new DegreePosition(50.488040000000005, 8.687940000000001)); + quadtree.put(new DegreePosition(50.487010000000005, 8.68913)); + quadtree.put(new DegreePosition(50.48583000000001, 8.69068)); + quadtree.put(new DegreePosition(50.484260000000006, 8.69318)); + quadtree.put(new DegreePosition(50.483340000000005, 8.69505)); + quadtree.put(new DegreePosition(50.48272000000001, 8.69658)); + quadtree.put(new DegreePosition(50.482110000000006, 8.698260000000001)); + quadtree.put(new DegreePosition(50.481390000000005, 8.70049)); + quadtree.put(new DegreePosition(50.48093, 8.70208)); + quadtree.put(new DegreePosition(50.48021000000001, 8.705020000000001)); + quadtree.put(new DegreePosition(50.47822000000001, 8.71437)); + quadtree.put(new DegreePosition(50.477940000000004, 8.715430000000001)); + quadtree.put(new DegreePosition(50.47721000000001, 8.717260000000001)); + quadtree.put(new DegreePosition(50.47652, 8.718820000000001)); + quadtree.put(new DegreePosition(50.476240000000004, 8.71929)); + quadtree.put(new DegreePosition(50.475660000000005, 8.72009)); + quadtree.put(new DegreePosition(50.47426, 8.72159)); + quadtree.put(new DegreePosition(50.47375, 8.722000000000001)); + quadtree.put(new DegreePosition(50.47307000000001, 8.7224)); + quadtree.put(new DegreePosition(50.472390000000004, 8.72273)); + quadtree.put(new DegreePosition(50.47173, 8.72295)); + quadtree.put(new DegreePosition(50.471050000000005, 8.723090000000001)); + quadtree.put(new DegreePosition(50.46989000000001, 8.723080000000001)); + quadtree.put(new DegreePosition(50.46876, 8.72295)); + quadtree.put(new DegreePosition(50.466840000000005, 8.72241)); + quadtree.put(new DegreePosition(50.465230000000005, 8.721820000000001)); + quadtree.put(new DegreePosition(50.46338, 8.72098)); + quadtree.put(new DegreePosition(50.463100000000004, 8.72091)); + quadtree.put(new DegreePosition(50.461200000000005, 8.71997)); + quadtree.put(new DegreePosition(50.46023, 8.71925)); + quadtree.put(new DegreePosition(50.459410000000005, 8.718570000000001)); + quadtree.put(new DegreePosition(50.458600000000004, 8.7178)); + quadtree.put(new DegreePosition(50.45769000000001, 8.716790000000001)); + quadtree.put(new DegreePosition(50.456610000000005, 8.71546)); + quadtree.put(new DegreePosition(50.455490000000005, 8.7139)); + quadtree.put(new DegreePosition(50.45445, 8.712250000000001)); + quadtree.put(new DegreePosition(50.45373000000001, 8.710980000000001)); + quadtree.put(new DegreePosition(50.45327, 8.71006)); + quadtree.put(new DegreePosition(50.45239, 8.70799)); + quadtree.put(new DegreePosition(50.44941000000001, 8.70059)); + quadtree.put(new DegreePosition(50.448820000000005, 8.69945)); + quadtree.put(new DegreePosition(50.448460000000004, 8.69888)); + quadtree.put(new DegreePosition(50.447900000000004, 8.69806)); + quadtree.put(new DegreePosition(50.44698, 8.69688)); + quadtree.put(new DegreePosition(50.44641000000001, 8.6963)); + quadtree.put(new DegreePosition(50.44548, 8.695500000000001)); + quadtree.put(new DegreePosition(50.44501, 8.695160000000001)); + quadtree.put(new DegreePosition(50.44411, 8.69472)); + quadtree.put(new DegreePosition(50.44333, 8.69443)); + quadtree.put(new DegreePosition(50.44202000000001, 8.694180000000001)); + quadtree.put(new DegreePosition(50.44145, 8.694170000000002)); + quadtree.put(new DegreePosition(50.440560000000005, 8.69425)); + quadtree.put(new DegreePosition(50.432640000000006, 8.69574)); + quadtree.put(new DegreePosition(50.42264, 8.697370000000001)); + quadtree.put(new DegreePosition(50.405300000000004, 8.70054)); + quadtree.put(new DegreePosition(50.395720000000004, 8.70219)); + quadtree.put(new DegreePosition(50.391580000000005, 8.70298)); + quadtree.put(new DegreePosition(50.38085, 8.7048)); + quadtree.put(new DegreePosition(50.375750000000004, 8.70561)); + quadtree.put(new DegreePosition(50.374950000000005, 8.70569)); + quadtree.put(new DegreePosition(50.373850000000004, 8.70564)); + quadtree.put(new DegreePosition(50.37259, 8.705400000000001)); + quadtree.put(new DegreePosition(50.37050000000001, 8.70457)); + quadtree.put(new DegreePosition(50.369170000000004, 8.70387)); + quadtree.put(new DegreePosition(50.367610000000006, 8.702910000000001)); + quadtree.put(new DegreePosition(50.36612, 8.7018)); + quadtree.put(new DegreePosition(50.36075, 8.6972)); + quadtree.put(new DegreePosition(50.35831, 8.69533)); + quadtree.put(new DegreePosition(50.356950000000005, 8.69443)); + quadtree.put(new DegreePosition(50.35558, 8.69372)); + quadtree.put(new DegreePosition(50.354400000000005, 8.69335)); + quadtree.put(new DegreePosition(50.35246, 8.69284)); + quadtree.put(new DegreePosition(50.35105, 8.692620000000002)); + quadtree.put(new DegreePosition(50.350170000000006, 8.69257)); + quadtree.put(new DegreePosition(50.34955, 8.692580000000001)); + quadtree.put(new DegreePosition(50.34857, 8.69275)); + quadtree.put(new DegreePosition(50.346230000000006, 8.693470000000001)); + quadtree.put(new DegreePosition(50.341210000000004, 8.69532)); + quadtree.put(new DegreePosition(50.34002, 8.695680000000001)); + quadtree.put(new DegreePosition(50.33867000000001, 8.695910000000001)); + quadtree.put(new DegreePosition(50.33753, 8.69594)); + quadtree.put(new DegreePosition(50.3361, 8.695860000000001)); + quadtree.put(new DegreePosition(50.333580000000005, 8.69542)); + quadtree.put(new DegreePosition(50.32048, 8.69252)); + quadtree.put(new DegreePosition(50.31851, 8.69196)); + quadtree.put(new DegreePosition(50.31781, 8.6917)); + quadtree.put(new DegreePosition(50.31709000000001, 8.69139)); + quadtree.put(new DegreePosition(50.31595, 8.690760000000001)); + quadtree.put(new DegreePosition(50.314600000000006, 8.68979)); + quadtree.put(new DegreePosition(50.31338, 8.68871)); + quadtree.put(new DegreePosition(50.31116, 8.68621)); + quadtree.put(new DegreePosition(50.30666, 8.680890000000002)); + quadtree.put(new DegreePosition(50.3034, 8.67722)); + quadtree.put(new DegreePosition(50.302640000000004, 8.67643)); + quadtree.put(new DegreePosition(50.301930000000006, 8.675830000000001)); + quadtree.put(new DegreePosition(50.30136, 8.675410000000001)); + quadtree.put(new DegreePosition(50.30044, 8.67488)); + quadtree.put(new DegreePosition(50.298860000000005, 8.674140000000001)); + quadtree.put(new DegreePosition(50.29008, 8.67112)); + quadtree.put(new DegreePosition(50.286120000000004, 8.669820000000001)); + quadtree.put(new DegreePosition(50.27376, 8.665550000000001)); + quadtree.put(new DegreePosition(50.26568, 8.662920000000002)); + quadtree.put(new DegreePosition(50.26428000000001, 8.662640000000001)); + quadtree.put(new DegreePosition(50.26334000000001, 8.662560000000001)); + quadtree.put(new DegreePosition(50.248900000000006, 8.662740000000001)); + quadtree.put(new DegreePosition(50.24667, 8.662730000000002)); + quadtree.put(new DegreePosition(50.231930000000006, 8.662970000000001)); + quadtree.put(new DegreePosition(50.21923, 8.6631)); + quadtree.put(new DegreePosition(50.21822, 8.66305)); + quadtree.put(new DegreePosition(50.21732, 8.66291)); + quadtree.put(new DegreePosition(50.216240000000006, 8.66267)); + quadtree.put(new DegreePosition(50.215270000000004, 8.662370000000001)); + quadtree.put(new DegreePosition(50.214200000000005, 8.66192)); + quadtree.put(new DegreePosition(50.21316, 8.661370000000002)); + quadtree.put(new DegreePosition(50.21162, 8.660350000000001)); + quadtree.put(new DegreePosition(50.210660000000004, 8.659600000000001)); + quadtree.put(new DegreePosition(50.209430000000005, 8.65841)); + quadtree.put(new DegreePosition(50.20864, 8.6575)); + quadtree.put(new DegreePosition(50.208090000000006, 8.656830000000001)); + quadtree.put(new DegreePosition(50.206920000000004, 8.65522)); + quadtree.put(new DegreePosition(50.206500000000005, 8.65456)); + quadtree.put(new DegreePosition(50.20488, 8.651760000000001)); + quadtree.put(new DegreePosition(50.203190000000006, 8.649080000000001)); + quadtree.put(new DegreePosition(50.19881, 8.64192)); + quadtree.put(new DegreePosition(50.196600000000004, 8.637440000000002)); + quadtree.put(new DegreePosition(50.188770000000005, 8.6239)); + quadtree.put(new DegreePosition(50.18795, 8.62259)); + quadtree.put(new DegreePosition(50.187070000000006, 8.621360000000001)); + quadtree.put(new DegreePosition(50.18627000000001, 8.6204)); + quadtree.put(new DegreePosition(50.185120000000005, 8.619190000000001)); + quadtree.put(new DegreePosition(50.18388, 8.61808)); + quadtree.put(new DegreePosition(50.182770000000005, 8.61726)); + quadtree.put(new DegreePosition(50.18178, 8.61665)); + quadtree.put(new DegreePosition(50.17159, 8.61101)); + quadtree.put(new DegreePosition(50.16395000000001, 8.606710000000001)); + quadtree.put(new DegreePosition(50.15317, 8.600760000000001)); + quadtree.put(new DegreePosition(50.149210000000004, 8.598640000000001)); + quadtree.put(new DegreePosition(50.14303, 8.59515)); + quadtree.put(new DegreePosition(50.13889, 8.592960000000001)); + quadtree.put(new DegreePosition(50.13496000000001, 8.590810000000001)); + quadtree.put(new DegreePosition(50.1332, 8.590190000000002)); + quadtree.put(new DegreePosition(50.13172, 8.58994)); + quadtree.put(new DegreePosition(50.13055000000001, 8.58993)); + quadtree.put(new DegreePosition(50.129450000000006, 8.59008)); + quadtree.put(new DegreePosition(50.12838000000001, 8.590340000000001)); + quadtree.put(new DegreePosition(50.12713, 8.59083)); + quadtree.put(new DegreePosition(50.12621000000001, 8.591320000000001)); + quadtree.put(new DegreePosition(50.118970000000004, 8.595970000000001)); + quadtree.put(new DegreePosition(50.10857000000001, 8.60274)); + quadtree.put(new DegreePosition(50.105970000000006, 8.604600000000001)); + quadtree.put(new DegreePosition(50.105050000000006, 8.605410000000001)); + quadtree.put(new DegreePosition(50.104200000000006, 8.60622)); + quadtree.put(new DegreePosition(50.10295000000001, 8.607560000000001)); + quadtree.put(new DegreePosition(50.10038, 8.61049)); + quadtree.put(new DegreePosition(50.09879, 8.61238)); + quadtree.put(new DegreePosition(50.09743, 8.61368)); + quadtree.put(new DegreePosition(50.09572000000001, 8.6151)); + quadtree.put(new DegreePosition(50.09489000000001, 8.61561)); + quadtree.put(new DegreePosition(50.093360000000004, 8.616290000000001)); + quadtree.put(new DegreePosition(50.09149000000001, 8.616940000000001)); + quadtree.put(new DegreePosition(50.087880000000006, 8.617780000000002)); + quadtree.put(new DegreePosition(50.08559, 8.618160000000001)); + quadtree.put(new DegreePosition(50.08471, 8.61824)); + quadtree.put(new DegreePosition(50.083000000000006, 8.61814)); + quadtree.put(new DegreePosition(50.081680000000006, 8.617930000000001)); + quadtree.put(new DegreePosition(50.080400000000004, 8.617560000000001)); + quadtree.put(new DegreePosition(50.0797, 8.6173)); + quadtree.put(new DegreePosition(50.07835000000001, 8.61668)); + quadtree.put(new DegreePosition(50.06631, 8.61067)); + quadtree.put(new DegreePosition(50.06239, 8.608640000000001)); + quadtree.put(new DegreePosition(50.05212, 8.60364)); + quadtree.put(new DegreePosition(50.03866000000001, 8.596810000000001)); + quadtree.put(new DegreePosition(50.03486, 8.59505)); + quadtree.put(new DegreePosition(50.033010000000004, 8.5943)); + quadtree.put(new DegreePosition(50.03032, 8.59347)); + quadtree.put(new DegreePosition(50.02763, 8.59284)); + quadtree.put(new DegreePosition(50.025240000000004, 8.59252)); + quadtree.put(new DegreePosition(50.024260000000005, 8.59247)); + quadtree.put(new DegreePosition(50.02208, 8.59247)); + quadtree.put(new DegreePosition(50.020790000000005, 8.592550000000001)); + quadtree.put(new DegreePosition(50.019270000000006, 8.59271)); + quadtree.put(new DegreePosition(50.016510000000004, 8.593240000000002)); + quadtree.put(new DegreePosition(49.983160000000005, 8.60124)); + quadtree.put(new DegreePosition(49.976580000000006, 8.60275)); + quadtree.put(new DegreePosition(49.97316000000001, 8.60363)); + quadtree.put(new DegreePosition(49.96228000000001, 8.60614)); + quadtree.put(new DegreePosition(49.95414, 8.60811)); + quadtree.put(new DegreePosition(49.95309, 8.608310000000001)); + quadtree.put(new DegreePosition(49.95217, 8.60857)); + quadtree.put(new DegreePosition(49.948350000000005, 8.609440000000001)); + quadtree.put(new DegreePosition(49.943200000000004, 8.610750000000001)); + quadtree.put(new DegreePosition(49.941720000000004, 8.611040000000001)); + quadtree.put(new DegreePosition(49.935280000000006, 8.612530000000001)); + quadtree.put(new DegreePosition(49.933550000000004, 8.6128)); + quadtree.put(new DegreePosition(49.93207, 8.612960000000001)); + quadtree.put(new DegreePosition(49.93084, 8.61302)); + quadtree.put(new DegreePosition(49.928740000000005, 8.61299)); + quadtree.put(new DegreePosition(49.926950000000005, 8.61283)); + quadtree.put(new DegreePosition(49.92591, 8.61269)); + quadtree.put(new DegreePosition(49.92389000000001, 8.612260000000001)); + quadtree.put(new DegreePosition(49.92083, 8.6113)); + quadtree.put(new DegreePosition(49.91532, 8.609390000000001)); + quadtree.put(new DegreePosition(49.914170000000006, 8.60905)); + quadtree.put(new DegreePosition(49.91042, 8.60819)); + quadtree.put(new DegreePosition(49.89902000000001, 8.60598)); + quadtree.put(new DegreePosition(49.89663, 8.605450000000001)); + quadtree.put(new DegreePosition(49.887750000000004, 8.603710000000001)); + quadtree.put(new DegreePosition(49.886900000000004, 8.603610000000002)); + quadtree.put(new DegreePosition(49.88288000000001, 8.60288)); + quadtree.put(new DegreePosition(49.87717000000001, 8.60196)); + quadtree.put(new DegreePosition(49.874700000000004, 8.60147)); + quadtree.put(new DegreePosition(49.87281, 8.60119)); + quadtree.put(new DegreePosition(49.870450000000005, 8.60072)); + quadtree.put(new DegreePosition(49.86542000000001, 8.599530000000001)); + quadtree.put(new DegreePosition(49.86164, 8.59872)); + quadtree.put(new DegreePosition(49.861450000000005, 8.59861)); + quadtree.put(new DegreePosition(49.86047000000001, 8.598360000000001)); + quadtree.put(new DegreePosition(49.857470000000006, 8.597240000000001)); + quadtree.put(new DegreePosition(49.85718000000001, 8.59717)); + quadtree.put(new DegreePosition(49.85662000000001, 8.597150000000001)); + quadtree.put(new DegreePosition(49.856350000000006, 8.59721)); + quadtree.put(new DegreePosition(49.85586000000001, 8.59744)); + quadtree.put(new DegreePosition(49.85559000000001, 8.597660000000001)); + quadtree.put(new DegreePosition(49.855250000000005, 8.598090000000001)); + quadtree.put(new DegreePosition(49.854940000000006, 8.59862)); + quadtree.put(new DegreePosition(49.85474000000001, 8.599110000000001)); + quadtree.put(new DegreePosition(49.85452, 8.599860000000001)); + quadtree.put(new DegreePosition(49.85405, 8.60206)); + quadtree.put(new DegreePosition(49.8539, 8.602490000000001)); + quadtree.put(new DegreePosition(49.85325, 8.603750000000002)); + quadtree.put(new DegreePosition(49.851670000000006, 8.605870000000001)); + quadtree.put(new DegreePosition(49.85031000000001, 8.6079)); + quadtree.put(new DegreePosition(49.84915, 8.609850000000002)); + quadtree.put(new DegreePosition(49.846590000000006, 8.61508)); + quadtree.put(new DegreePosition(49.84149000000001, 8.626510000000001)); + quadtree.put(new DegreePosition(49.840500000000006, 8.62828)); + quadtree.put(new DegreePosition(49.839980000000004, 8.62898)); + quadtree.put(new DegreePosition(49.838530000000006, 8.63066)); + quadtree.put(new DegreePosition(49.83744, 8.6317)); + quadtree.put(new DegreePosition(49.83612, 8.632670000000001)); + quadtree.put(new DegreePosition(49.83462, 8.63345)); + quadtree.put(new DegreePosition(49.83399000000001, 8.63371)); + quadtree.put(new DegreePosition(49.832080000000005, 8.63414)); + quadtree.put(new DegreePosition(49.831320000000005, 8.63423)); + quadtree.put(new DegreePosition(49.830540000000006, 8.6342)); + quadtree.put(new DegreePosition(49.82978000000001, 8.63409)); + quadtree.put(new DegreePosition(49.82876, 8.633780000000002)); + quadtree.put(new DegreePosition(49.82734000000001, 8.633180000000001)); + quadtree.put(new DegreePosition(49.82462, 8.63161)); + quadtree.put(new DegreePosition(49.821630000000006, 8.62977)); + quadtree.put(new DegreePosition(49.820370000000004, 8.6292)); + quadtree.put(new DegreePosition(49.81908000000001, 8.62875)); + quadtree.put(new DegreePosition(49.81687, 8.62841)); + quadtree.put(new DegreePosition(49.81134, 8.62866)); + quadtree.put(new DegreePosition(49.81027, 8.62861)); + quadtree.put(new DegreePosition(49.80881, 8.62828)); + quadtree.put(new DegreePosition(49.80682, 8.627690000000001)); + quadtree.put(new DegreePosition(49.80575, 8.62719)); + quadtree.put(new DegreePosition(49.804100000000005, 8.62627)); + quadtree.put(new DegreePosition(49.80192, 8.624780000000001)); + quadtree.put(new DegreePosition(49.79887, 8.622520000000002)); + quadtree.put(new DegreePosition(49.797380000000004, 8.62151)); + quadtree.put(new DegreePosition(49.796110000000006, 8.620750000000001)); + quadtree.put(new DegreePosition(49.79467, 8.62005)); + quadtree.put(new DegreePosition(49.79345000000001, 8.619520000000001)); + quadtree.put(new DegreePosition(49.792060000000006, 8.61903)); + quadtree.put(new DegreePosition(49.79064, 8.61869)); + quadtree.put(new DegreePosition(49.78909, 8.618390000000002)); + quadtree.put(new DegreePosition(49.78412, 8.61762)); + quadtree.put(new DegreePosition(49.78295000000001, 8.61738)); + quadtree.put(new DegreePosition(49.78119, 8.61692)); + quadtree.put(new DegreePosition(49.77975000000001, 8.616380000000001)); + quadtree.put(new DegreePosition(49.778780000000005, 8.61593)); + quadtree.put(new DegreePosition(49.777640000000005, 8.61528)); + quadtree.put(new DegreePosition(49.77610000000001, 8.61415)); + quadtree.put(new DegreePosition(49.77506, 8.613190000000001)); + quadtree.put(new DegreePosition(49.77357000000001, 8.611600000000001)); + quadtree.put(new DegreePosition(49.77299000000001, 8.61087)); + quadtree.put(new DegreePosition(49.770830000000004, 8.607850000000001)); + quadtree.put(new DegreePosition(49.76859, 8.604610000000001)); + quadtree.put(new DegreePosition(49.768170000000005, 8.60405)); + quadtree.put(new DegreePosition(49.76608, 8.60152)); + quadtree.put(new DegreePosition(49.764790000000005, 8.60018)); + quadtree.put(new DegreePosition(49.762150000000005, 8.59793)); + quadtree.put(new DegreePosition(49.76151, 8.597430000000001)); + quadtree.put(new DegreePosition(49.76024, 8.59665)); + quadtree.put(new DegreePosition(49.757780000000004, 8.59553)); + quadtree.put(new DegreePosition(49.756260000000005, 8.59491)); + quadtree.put(new DegreePosition(49.75267, 8.59369)); + quadtree.put(new DegreePosition(49.75119, 8.593290000000001)); + quadtree.put(new DegreePosition(49.74869, 8.59272)); + quadtree.put(new DegreePosition(49.745580000000004, 8.592160000000002)); + quadtree.put(new DegreePosition(49.742180000000005, 8.59171)); + quadtree.put(new DegreePosition(49.739290000000004, 8.59154)); + quadtree.put(new DegreePosition(49.735220000000005, 8.591550000000002)); + quadtree.put(new DegreePosition(49.73221, 8.59176)); + quadtree.put(new DegreePosition(49.72905, 8.59223)); + quadtree.put(new DegreePosition(49.72579, 8.592830000000001)); + quadtree.put(new DegreePosition(49.722390000000004, 8.59373)); + quadtree.put(new DegreePosition(49.715450000000004, 8.59572)); + quadtree.put(new DegreePosition(49.705760000000005, 8.599260000000001)); + quadtree.put(new DegreePosition(49.6989, 8.602160000000001)); + quadtree.put(new DegreePosition(49.698060000000005, 8.602400000000001)); + quadtree.put(new DegreePosition(49.695820000000005, 8.602820000000001)); + quadtree.put(new DegreePosition(49.693780000000004, 8.602960000000001)); + quadtree.put(new DegreePosition(49.69301, 8.602960000000001)); + quadtree.put(new DegreePosition(49.6916, 8.602860000000002)); + quadtree.put(new DegreePosition(49.69035, 8.602640000000001)); + quadtree.put(new DegreePosition(49.689150000000005, 8.60234)); + quadtree.put(new DegreePosition(49.68645, 8.60135)); + quadtree.put(new DegreePosition(49.68348, 8.600140000000001)); + quadtree.put(new DegreePosition(49.68186000000001, 8.599680000000001)); + quadtree.put(new DegreePosition(49.67985, 8.599250000000001)); + quadtree.put(new DegreePosition(49.678070000000005, 8.59914)); + quadtree.put(new DegreePosition(49.676970000000004, 8.599160000000001)); + quadtree.put(new DegreePosition(49.67475, 8.59946)); + quadtree.put(new DegreePosition(49.672610000000006, 8.60003)); + quadtree.put(new DegreePosition(49.669450000000005, 8.6013)); + quadtree.put(new DegreePosition(49.667790000000004, 8.60214)); + quadtree.put(new DegreePosition(49.6655, 8.60356)); + quadtree.put(new DegreePosition(49.66145, 8.60621)); + quadtree.put(new DegreePosition(49.65959, 8.607330000000001)); + quadtree.put(new DegreePosition(49.657700000000006, 8.6083)); + quadtree.put(new DegreePosition(49.65603, 8.60891)); + quadtree.put(new DegreePosition(49.65431, 8.609340000000001)); + quadtree.put(new DegreePosition(49.65194, 8.60959)); + quadtree.put(new DegreePosition(49.649770000000004, 8.609620000000001)); + quadtree.put(new DegreePosition(49.64312, 8.609250000000001)); + quadtree.put(new DegreePosition(49.64190000000001, 8.60926)); + quadtree.put(new DegreePosition(49.64029000000001, 8.609380000000002)); + quadtree.put(new DegreePosition(49.63906, 8.609530000000001)); + quadtree.put(new DegreePosition(49.63758000000001, 8.60983)); + quadtree.put(new DegreePosition(49.63456000000001, 8.610570000000001)); + quadtree.put(new DegreePosition(49.632870000000004, 8.61125)); + quadtree.put(new DegreePosition(49.630630000000004, 8.612340000000001)); + quadtree.put(new DegreePosition(49.62894000000001, 8.61344)); + quadtree.put(new DegreePosition(49.627930000000006, 8.61416)); + quadtree.put(new DegreePosition(49.62348, 8.61804)); + quadtree.put(new DegreePosition(49.622220000000006, 8.61931)); + quadtree.put(new DegreePosition(49.618030000000005, 8.623240000000001)); + quadtree.put(new DegreePosition(49.6152, 8.6256)); + quadtree.put(new DegreePosition(49.61211, 8.627540000000002)); + quadtree.put(new DegreePosition(49.61057, 8.62833)); + quadtree.put(new DegreePosition(49.60898, 8.62899)); + quadtree.put(new DegreePosition(49.607150000000004, 8.629620000000001)); + quadtree.put(new DegreePosition(49.604940000000006, 8.630170000000001)); + quadtree.put(new DegreePosition(49.603770000000004, 8.63035)); + quadtree.put(new DegreePosition(49.60065, 8.630640000000001)); + quadtree.put(new DegreePosition(49.59897, 8.63086)); + quadtree.put(new DegreePosition(49.59581000000001, 8.63113)); + quadtree.put(new DegreePosition(49.59308000000001, 8.63165)); + quadtree.put(new DegreePosition(49.59147, 8.63212)); + quadtree.put(new DegreePosition(49.58559, 8.634110000000002)); + quadtree.put(new DegreePosition(49.58408000000001, 8.634540000000001)); + quadtree.put(new DegreePosition(49.582060000000006, 8.635010000000001)); + quadtree.put(new DegreePosition(49.580670000000005, 8.635200000000001)); + quadtree.put(new DegreePosition(49.57885, 8.635330000000002)); + quadtree.put(new DegreePosition(49.57715, 8.63531)); + quadtree.put(new DegreePosition(49.57417, 8.6349)); + quadtree.put(new DegreePosition(49.572190000000006, 8.63455)); + quadtree.put(new DegreePosition(49.570730000000005, 8.63413)); + quadtree.put(new DegreePosition(49.568430000000006, 8.6333)); + quadtree.put(new DegreePosition(49.565090000000005, 8.63171)); + quadtree.put(new DegreePosition(49.560050000000004, 8.62922)); + quadtree.put(new DegreePosition(49.55922, 8.62894)); + quadtree.put(new DegreePosition(49.55603000000001, 8.628010000000002)); + quadtree.put(new DegreePosition(49.55425, 8.62767)); + quadtree.put(new DegreePosition(49.55111, 8.62743)); + quadtree.put(new DegreePosition(49.548930000000006, 8.62748)); + quadtree.put(new DegreePosition(49.548120000000004, 8.62757)); + quadtree.put(new DegreePosition(49.54666, 8.62784)); + quadtree.put(new DegreePosition(49.54466000000001, 8.62827)); + quadtree.put(new DegreePosition(49.54215000000001, 8.62898)); + quadtree.put(new DegreePosition(49.539440000000006, 8.62991)); + quadtree.put(new DegreePosition(49.537850000000006, 8.63052)); + quadtree.put(new DegreePosition(49.52872000000001, 8.63442)); + quadtree.put(new DegreePosition(49.527300000000004, 8.63508)); + quadtree.put(new DegreePosition(49.52526, 8.635860000000001)); + quadtree.put(new DegreePosition(49.52337000000001, 8.636510000000001)); + quadtree.put(new DegreePosition(49.52058, 8.637360000000001)); + quadtree.put(new DegreePosition(49.518550000000005, 8.637910000000002)); + quadtree.put(new DegreePosition(49.51503, 8.638770000000001)); + quadtree.put(new DegreePosition(49.51098, 8.639330000000001)); + quadtree.put(new DegreePosition(49.50845, 8.63959)); + quadtree.put(new DegreePosition(49.50417, 8.639740000000002)); + quadtree.put(new DegreePosition(49.499810000000004, 8.63963)); + quadtree.put(new DegreePosition(49.49546, 8.63912)); + quadtree.put(new DegreePosition(49.49306000000001, 8.638910000000001)); + quadtree.put(new DegreePosition(49.490320000000004, 8.638760000000001)); + quadtree.put(new DegreePosition(49.48669, 8.63865)); + quadtree.put(new DegreePosition(49.484480000000005, 8.638760000000001)); + quadtree.put(new DegreePosition(49.48073, 8.639330000000001)); + quadtree.put(new DegreePosition(49.4776, 8.640130000000001)); + quadtree.put(new DegreePosition(49.476310000000005, 8.64052)); + quadtree.put(new DegreePosition(49.468500000000006, 8.64342)); + quadtree.put(new DegreePosition(49.464470000000006, 8.64483)); + quadtree.put(new DegreePosition(49.461290000000005, 8.64577)); + quadtree.put(new DegreePosition(49.458690000000004, 8.64629)); + quadtree.put(new DegreePosition(49.457530000000006, 8.646460000000001)); + quadtree.put(new DegreePosition(49.455380000000005, 8.64666)); + quadtree.put(new DegreePosition(49.453050000000005, 8.64668)); + quadtree.put(new DegreePosition(49.451750000000004, 8.64661)); + quadtree.put(new DegreePosition(49.450430000000004, 8.64647)); + quadtree.put(new DegreePosition(49.44711, 8.64578)); + quadtree.put(new DegreePosition(49.445350000000005, 8.6453)); + quadtree.put(new DegreePosition(49.44398, 8.64478)); + quadtree.put(new DegreePosition(49.44091, 8.64338)); + quadtree.put(new DegreePosition(49.439840000000004, 8.64282)); + quadtree.put(new DegreePosition(49.438340000000004, 8.64193)); + quadtree.put(new DegreePosition(49.43139000000001, 8.63724)); + quadtree.put(new DegreePosition(49.42933000000001, 8.636080000000002)); + quadtree.put(new DegreePosition(49.427890000000005, 8.63537)); + quadtree.put(new DegreePosition(49.426460000000006, 8.634820000000001)); + quadtree.put(new DegreePosition(49.42436000000001, 8.634160000000001)); + quadtree.put(new DegreePosition(49.422200000000004, 8.63371)); + quadtree.put(new DegreePosition(49.42033000000001, 8.633500000000002)); + quadtree.put(new DegreePosition(49.41946, 8.63347)); + quadtree.put(new DegreePosition(49.41798000000001, 8.63348)); + quadtree.put(new DegreePosition(49.415710000000004, 8.633700000000001)); + quadtree.put(new DegreePosition(49.41463, 8.6339)); + quadtree.put(new DegreePosition(49.412670000000006, 8.63437)); + quadtree.put(new DegreePosition(49.411120000000004, 8.6349)); + quadtree.put(new DegreePosition(49.40739000000001, 8.636330000000001)); + quadtree.put(new DegreePosition(49.40572, 8.636800000000001)); + quadtree.put(new DegreePosition(49.39164, 8.63865)); + quadtree.put(new DegreePosition(49.39021, 8.63879)); + quadtree.put(new DegreePosition(49.38855, 8.638720000000001)); + quadtree.put(new DegreePosition(49.38721, 8.638480000000001)); + quadtree.put(new DegreePosition(49.38656, 8.638290000000001)); + quadtree.put(new DegreePosition(49.38440000000001, 8.63746)); + quadtree.put(new DegreePosition(49.37805, 8.63387)); + quadtree.put(new DegreePosition(49.376940000000005, 8.63334)); + quadtree.put(new DegreePosition(49.376000000000005, 8.63297)); + quadtree.put(new DegreePosition(49.37500000000001, 8.63269)); + quadtree.put(new DegreePosition(49.373780000000004, 8.632480000000001)); + quadtree.put(new DegreePosition(49.36988, 8.63222)); + quadtree.put(new DegreePosition(49.36872, 8.632190000000001)); + quadtree.put(new DegreePosition(49.364360000000005, 8.631910000000001)); + quadtree.put(new DegreePosition(49.35228000000001, 8.63127)); + quadtree.put(new DegreePosition(49.34911, 8.631160000000001)); + quadtree.put(new DegreePosition(49.33944, 8.63067)); + quadtree.put(new DegreePosition(49.31497, 8.62917)); + quadtree.put(new DegreePosition(49.312200000000004, 8.62892)); + quadtree.put(new DegreePosition(49.31073000000001, 8.628670000000001)); + quadtree.put(new DegreePosition(49.303380000000004, 8.626940000000001)); + quadtree.put(new DegreePosition(49.30293, 8.62654)); + quadtree.put(new DegreePosition(49.30285000000001, 8.62644)); + quadtree.put(new DegreePosition(49.302690000000005, 8.62608)); + quadtree.put(new DegreePosition(49.30268, 8.62584)); + quadtree.put(new DegreePosition(49.30299, 8.62268)); + quadtree.put(new DegreePosition(49.30303000000001, 8.622010000000001)); + quadtree.put(new DegreePosition(49.30299, 8.621730000000001)); + quadtree.put(new DegreePosition(49.30293, 8.6216)); + quadtree.put(new DegreePosition(49.30274000000001, 8.62147)); + quadtree.put(new DegreePosition(49.30238000000001, 8.62139)); + quadtree.put(new DegreePosition(49.302290000000006, 8.621310000000001)); + quadtree.put(new DegreePosition(49.301950000000005, 8.62127)); + quadtree.put(new DegreePosition(49.30187, 8.62279)); + quadtree.put(new DegreePosition(49.30172, 8.62456)); + quadtree.put(new DegreePosition(49.30134, 8.62697)); + quadtree.put(new DegreePosition(49.30116, 8.627690000000001)); + quadtree.put(new DegreePosition(49.30053, 8.629800000000001)); + quadtree.put(new DegreePosition(49.299820000000004, 8.63142)); + quadtree.put(new DegreePosition(49.29916, 8.6327)); + quadtree.put(new DegreePosition(49.299530000000004, 8.63279)); + quadtree.put(new DegreePosition(49.30006, 8.63272)); + quadtree.put(new DegreePosition(49.30068000000001, 8.63277)); + quadtree.put(new DegreePosition(49.30082, 8.63283)); + quadtree.put(new DegreePosition(49.301050000000004, 8.633040000000001)); + quadtree.put(new DegreePosition(49.300340000000006, 8.634780000000001)); + quadtree.put(new DegreePosition(49.29995, 8.63593)); + quadtree.put(new DegreePosition(49.299690000000005, 8.63723)); + quadtree.put(new DegreePosition(49.299600000000005, 8.638200000000001)); + quadtree.put(new DegreePosition(49.29963, 8.63973)); + quadtree.put(new DegreePosition(49.299710000000005, 8.64104)); + quadtree.put(new DegreePosition(49.29831, 8.643080000000001)); + quadtree.put(new DegreePosition(49.29796, 8.64334)); + quadtree.put(new DegreePosition(49.297920000000005, 8.643450000000001)); + quadtree.put(new DegreePosition(49.297920000000005, 8.643590000000001)); + quadtree.put(new DegreePosition(49.29798, 8.64389)); + quadtree.put(new DegreePosition(49.299420000000005, 8.646180000000001)); + quadtree.put(new DegreePosition(49.299580000000006, 8.64652)); + quadtree.put(new DegreePosition(49.29955, 8.646640000000001)); + quadtree.put(new DegreePosition(49.29957, 8.64677)); + quadtree.put(new DegreePosition(49.299710000000005, 8.64681)); + quadtree.put(new DegreePosition(49.29977, 8.646730000000002)); + quadtree.put(new DegreePosition(49.299780000000005, 8.646640000000001)); + quadtree.put(new DegreePosition(49.299690000000005, 8.64648)); + quadtree.put(new DegreePosition(49.2997, 8.64638)); + quadtree.put(new DegreePosition(49.29992000000001, 8.64586)); + quadtree.put(new DegreePosition(49.29995, 8.64563)); + quadtree.put(new DegreePosition(49.300790000000006, 8.644)); + quadtree.put(new DegreePosition(49.301120000000004, 8.643650000000001)); + quadtree.put(new DegreePosition(49.301390000000005, 8.64348)); + quadtree.put(new DegreePosition(49.30283000000001, 8.642980000000001)); + quadtree.put(new DegreePosition(49.30346, 8.642560000000001)); + quadtree.put(new DegreePosition(49.30378, 8.64241)); + quadtree.put(new DegreePosition(49.309740000000005, 8.64105)); + quadtree.put(new DegreePosition(49.309760000000004, 8.64207)); + quadtree.put(new DegreePosition(49.309140000000006, 8.64212)); + quadtree.put(new DegreePosition(49.309140000000006, 8.643880000000001)); + quadtree.put(new DegreePosition(49.30917, 8.64403)); + quadtree.put(new DegreePosition(49.30923000000001, 8.644110000000001)); + quadtree.put(new DegreePosition(49.30937, 8.644110000000001)); + + p1 = new DegreePosition(50.47498691278631, 8.701171875); + p2 = new DegreePosition(50.47149085139956, 8.7066650390625); + p3 = new DegreePosition(50.47848271564207, 8.7066650390625); } @Test public void testNoNPEDuringSecondPutInSameLeaf() { - final QuadTreeWithPublicGetTop qt = new QuadTreeWithPublicGetTop(); + final QuadTree qt = new QuadTree(); final Position p = new DegreePosition(0, 0); final NullPointerException[] npe = new NullPointerException[1]; final boolean[] stop = new boolean[1]; @@ -72,1132 +1222,6 @@ public class QuadTreeTest { @Test public void testDistance() { - GLatLngQuadTree quadtree = new GLatLngQuadTree(new DegreePosition(49.29, - 7.9), new DegreePosition(50.88506, 8.75), /* maxItems */30); - quadtree.put(new DegreePosition(50.88505000000001, 7.995520000000001)); - quadtree.put(new DegreePosition(50.884930000000004, 7.996440000000001)); - quadtree.put(new DegreePosition(50.884840000000004, 7.99666)); - quadtree.put(new DegreePosition(50.8843, 7.997490000000001)); - quadtree.put(new DegreePosition(50.884240000000005, 7.997730000000001)); - quadtree.put(new DegreePosition(50.88423, 7.997980000000001)); - quadtree.put(new DegreePosition(50.8847, 7.999010000000001)); - quadtree.put(new DegreePosition(50.884600000000006, 7.999130000000001)); - quadtree.put(new DegreePosition(50.88448, 7.99938)); - quadtree.put(new DegreePosition(50.88421, 8.00014)); - quadtree.put(new DegreePosition(50.88382000000001, 8.00174)); - quadtree.put(new DegreePosition(50.88355000000001, 8.00263)); - quadtree.put(new DegreePosition(50.883570000000006, 8.00309)); - quadtree.put(new DegreePosition(50.883700000000005, 8.003530000000001)); - quadtree.put(new DegreePosition(50.88212000000001, 8.00539)); - quadtree.put(new DegreePosition(50.881620000000005, 8.006260000000001)); - quadtree.put(new DegreePosition(50.881080000000004, 8.007610000000001)); - quadtree.put(new DegreePosition(50.88103, 8.007900000000001)); - quadtree.put(new DegreePosition(50.88103, 8.009030000000001)); - quadtree.put(new DegreePosition(50.880880000000005, 8.009640000000001)); - quadtree.put(new DegreePosition(50.88047, 8.010860000000001)); - quadtree.put(new DegreePosition(50.880030000000005, 8.012500000000001)); - quadtree.put(new DegreePosition(50.87866, 8.016810000000001)); - quadtree.put(new DegreePosition(50.87832, 8.017790000000002)); - quadtree.put(new DegreePosition(50.878240000000005, 8.01793)); - quadtree.put(new DegreePosition(50.878150000000005, 8.01795)); - quadtree.put(new DegreePosition(50.87803, 8.01782)); - quadtree.put(new DegreePosition(50.87776, 8.01717)); - quadtree.put(new DegreePosition(50.8774, 8.01654)); - quadtree.put(new DegreePosition(50.87709, 8.01622)); - quadtree.put(new DegreePosition(50.87585000000001, 8.013850000000001)); - quadtree.put(new DegreePosition(50.87538000000001, 8.01304)); - quadtree.put(new DegreePosition(50.87402, 8.01111)); - quadtree.put(new DegreePosition(50.87028, 8.003960000000001)); - quadtree.put(new DegreePosition(50.869670000000006, 8.003160000000001)); - quadtree.put(new DegreePosition(50.86925, 8.002780000000001)); - quadtree.put(new DegreePosition(50.86858, 8.00244)); - quadtree.put(new DegreePosition(50.868, 8.002310000000001)); - quadtree.put(new DegreePosition(50.86739000000001, 8.00237)); - quadtree.put(new DegreePosition(50.867070000000005, 8.00248)); - quadtree.put(new DegreePosition(50.86674000000001, 8.00267)); - quadtree.put(new DegreePosition(50.865950000000005, 8.00333)); - quadtree.put(new DegreePosition(50.86545, 8.00398)); - quadtree.put(new DegreePosition(50.86459000000001, 8.0053)); - quadtree.put(new DegreePosition(50.86424, 8.00577)); - quadtree.put(new DegreePosition(50.863870000000006, 8.00618)); - quadtree.put(new DegreePosition(50.86352, 8.0065)); - quadtree.put(new DegreePosition(50.862970000000004, 8.006820000000001)); - quadtree.put(new DegreePosition(50.862370000000006, 8.00703)); - quadtree.put(new DegreePosition(50.86110000000001, 8.00722)); - quadtree.put(new DegreePosition(50.86061, 8.00721)); - quadtree.put(new DegreePosition(50.859860000000005, 8.00711)); - quadtree.put(new DegreePosition(50.85918, 8.006920000000001)); - quadtree.put(new DegreePosition(50.85824, 8.006120000000001)); - quadtree.put(new DegreePosition(50.85784, 8.005640000000001)); - quadtree.put(new DegreePosition(50.85757, 8.0052)); - quadtree.put(new DegreePosition(50.85752, 8.00496)); - quadtree.put(new DegreePosition(50.85752, 8.00463)); - quadtree.put(new DegreePosition(50.85963, 8.00209)); - quadtree.put(new DegreePosition(50.86046, 8.0008)); - quadtree.put(new DegreePosition(50.86081, 8.00008)); - quadtree.put(new DegreePosition(50.86113, 7.999230000000001)); - quadtree.put(new DegreePosition(50.86128, 7.998690000000001)); - quadtree.put(new DegreePosition(50.861430000000006, 7.997870000000001)); - quadtree.put(new DegreePosition(50.86149, 7.99706)); - quadtree.put(new DegreePosition(50.86149, 7.996150000000001)); - quadtree.put(new DegreePosition(50.86144, 7.9955300000000005)); - quadtree.put(new DegreePosition(50.86130000000001, 7.99476)); - quadtree.put(new DegreePosition(50.86106, 7.993900000000001)); - quadtree.put(new DegreePosition(50.860220000000005, 7.991490000000001)); - quadtree.put(new DegreePosition(50.859970000000004, 7.990360000000001)); - quadtree.put(new DegreePosition(50.859930000000006, 7.987780000000001)); - quadtree.put(new DegreePosition(50.859970000000004, 7.98737)); - quadtree.put(new DegreePosition(50.86059, 7.984820000000001)); - quadtree.put(new DegreePosition(50.86065000000001, 7.984260000000001)); - quadtree.put(new DegreePosition(50.860620000000004, 7.98359)); - quadtree.put(new DegreePosition(50.8605, 7.9831900000000005)); - quadtree.put(new DegreePosition(50.860310000000005, 7.98284)); - quadtree.put(new DegreePosition(50.86001, 7.982540000000001)); - quadtree.put(new DegreePosition(50.85971000000001, 7.982450000000001)); - quadtree.put(new DegreePosition(50.859410000000004, 7.98251)); - quadtree.put(new DegreePosition(50.85918, 7.982670000000001)); - quadtree.put(new DegreePosition(50.85898, 7.98291)); - quadtree.put(new DegreePosition(50.858790000000006, 7.983370000000001)); - quadtree.put(new DegreePosition(50.858520000000006, 7.9846)); - quadtree.put(new DegreePosition(50.8584, 7.98488)); - quadtree.put(new DegreePosition(50.858140000000006, 7.9851600000000005)); - quadtree.put(new DegreePosition(50.85756000000001, 7.9855100000000006)); - quadtree.put(new DegreePosition(50.85616, 7.985920000000001)); - quadtree.put(new DegreePosition(50.85548000000001, 7.98603)); - quadtree.put(new DegreePosition(50.85210000000001, 7.9863100000000005)); - quadtree.put(new DegreePosition(50.850970000000004, 7.98662)); - quadtree.put(new DegreePosition(50.849230000000006, 7.98739)); - quadtree.put(new DegreePosition(50.849030000000006, 7.98758)); - quadtree.put(new DegreePosition(50.84798000000001, 7.988300000000001)); - quadtree.put(new DegreePosition(50.84763, 7.988600000000001)); - quadtree.put(new DegreePosition(50.84695000000001, 7.989240000000001)); - quadtree.put(new DegreePosition(50.84591, 7.9903900000000005)); - quadtree.put(new DegreePosition(50.84514, 7.99143)); - quadtree.put(new DegreePosition(50.844370000000005, 7.992660000000001)); - quadtree.put(new DegreePosition(50.84355000000001, 7.994140000000001)); - quadtree.put(new DegreePosition(50.842800000000004, 7.9958800000000005)); - quadtree.put(new DegreePosition(50.84174, 7.99898)); - quadtree.put(new DegreePosition(50.84141, 7.9998700000000005)); - quadtree.put(new DegreePosition(50.84085, 8.00121)); - quadtree.put(new DegreePosition(50.84001000000001, 8.00285)); - quadtree.put(new DegreePosition(50.83823, 8.00586)); - quadtree.put(new DegreePosition(50.83747, 8.00736)); - quadtree.put(new DegreePosition(50.83702, 8.008410000000001)); - quadtree.put(new DegreePosition(50.83662, 8.00956)); - quadtree.put(new DegreePosition(50.83628, 8.01093)); - quadtree.put(new DegreePosition(50.83605000000001, 8.012160000000002)); - quadtree.put(new DegreePosition(50.83545, 8.016810000000001)); - quadtree.put(new DegreePosition(50.83491, 8.01938)); - quadtree.put(new DegreePosition(50.834250000000004, 8.02161)); - quadtree.put(new DegreePosition(50.83332000000001, 8.025210000000001)); - quadtree.put(new DegreePosition(50.8331, 8.0264)); - quadtree.put(new DegreePosition(50.83299, 8.027230000000001)); - quadtree.put(new DegreePosition(50.832890000000006, 8.028220000000001)); - quadtree.put(new DegreePosition(50.832820000000005, 8.0296)); - quadtree.put(new DegreePosition(50.83283, 8.030740000000002)); - quadtree.put(new DegreePosition(50.832950000000004, 8.03252)); - quadtree.put(new DegreePosition(50.833180000000006, 8.034790000000001)); - quadtree.put(new DegreePosition(50.833200000000005, 8.036140000000001)); - quadtree.put(new DegreePosition(50.83316000000001, 8.03739)); - quadtree.put(new DegreePosition(50.83312, 8.03801)); - quadtree.put(new DegreePosition(50.83299, 8.03907)); - quadtree.put(new DegreePosition(50.832730000000005, 8.04087)); - quadtree.put(new DegreePosition(50.83243, 8.042290000000001)); - quadtree.put(new DegreePosition(50.831880000000005, 8.04424)); - quadtree.put(new DegreePosition(50.83072000000001, 8.047070000000001)); - quadtree.put(new DegreePosition(50.8286, 8.051340000000001)); - quadtree.put(new DegreePosition(50.82793, 8.052610000000001)); - quadtree.put(new DegreePosition(50.827650000000006, 8.053410000000001)); - quadtree.put(new DegreePosition(50.827290000000005, 8.054680000000001)); - quadtree.put(new DegreePosition(50.82674, 8.05762)); - quadtree.put(new DegreePosition(50.826620000000005, 8.05882)); - quadtree.put(new DegreePosition(50.826550000000005, 8.06226)); - quadtree.put(new DegreePosition(50.82645, 8.0639)); - quadtree.put(new DegreePosition(50.8263, 8.065420000000001)); - quadtree.put(new DegreePosition(50.82591000000001, 8.06756)); - quadtree.put(new DegreePosition(50.825540000000004, 8.06884)); - quadtree.put(new DegreePosition(50.82486, 8.070490000000001)); - quadtree.put(new DegreePosition(50.82444, 8.07141)); - quadtree.put(new DegreePosition(50.82368, 8.07266)); - quadtree.put(new DegreePosition(50.821760000000005, 8.075130000000001)); - quadtree.put(new DegreePosition(50.821020000000004, 8.07614)); - quadtree.put(new DegreePosition(50.8205, 8.077)); - quadtree.put(new DegreePosition(50.819950000000006, 8.078240000000001)); - quadtree.put(new DegreePosition(50.81955000000001, 8.079450000000001)); - quadtree.put(new DegreePosition(50.819120000000005, 8.08103)); - quadtree.put(new DegreePosition(50.81859000000001, 8.08351)); - quadtree.put(new DegreePosition(50.818130000000004, 8.08783)); - quadtree.put(new DegreePosition(50.81796000000001, 8.088840000000001)); - quadtree.put(new DegreePosition(50.81774000000001, 8.08971)); - quadtree.put(new DegreePosition(50.817420000000006, 8.090670000000001)); - quadtree.put(new DegreePosition(50.81671000000001, 8.09238)); - quadtree.put(new DegreePosition(50.81647, 8.09285)); - quadtree.put(new DegreePosition(50.81557, 8.094370000000001)); - quadtree.put(new DegreePosition(50.814960000000006, 8.09521)); - quadtree.put(new DegreePosition(50.81427000000001, 8.09603)); - quadtree.put(new DegreePosition(50.81369, 8.0966)); - quadtree.put(new DegreePosition(50.81291, 8.09722)); - quadtree.put(new DegreePosition(50.81228, 8.09763)); - quadtree.put(new DegreePosition(50.81022, 8.098590000000002)); - quadtree.put(new DegreePosition(50.80885000000001, 8.098980000000001)); - quadtree.put(new DegreePosition(50.806900000000006, 8.09918)); - quadtree.put(new DegreePosition(50.805350000000004, 8.09904)); - quadtree.put(new DegreePosition(50.804460000000006, 8.098790000000001)); - quadtree.put(new DegreePosition(50.803180000000005, 8.09833)); - quadtree.put(new DegreePosition(50.79974000000001, 8.09685)); - quadtree.put(new DegreePosition(50.798950000000005, 8.09665)); - quadtree.put(new DegreePosition(50.797990000000006, 8.09664)); - quadtree.put(new DegreePosition(50.79683000000001, 8.096760000000002)); - quadtree.put(new DegreePosition(50.795730000000006, 8.09699)); - quadtree.put(new DegreePosition(50.794630000000005, 8.097520000000001)); - quadtree.put(new DegreePosition(50.79238, 8.099340000000002)); - quadtree.put(new DegreePosition(50.79153, 8.10016)); - quadtree.put(new DegreePosition(50.79068, 8.10111)); - quadtree.put(new DegreePosition(50.789970000000004, 8.10195)); - quadtree.put(new DegreePosition(50.78891, 8.103380000000001)); - quadtree.put(new DegreePosition(50.78833, 8.104230000000001)); - quadtree.put(new DegreePosition(50.78759, 8.10539)); - quadtree.put(new DegreePosition(50.786970000000004, 8.10646)); - quadtree.put(new DegreePosition(50.78605, 8.10823)); - quadtree.put(new DegreePosition(50.78566000000001, 8.10905)); - quadtree.put(new DegreePosition(50.784890000000004, 8.11107)); - quadtree.put(new DegreePosition(50.784670000000006, 8.11194)); - quadtree.put(new DegreePosition(50.78437, 8.11344)); - quadtree.put(new DegreePosition(50.784200000000006, 8.11463)); - quadtree.put(new DegreePosition(50.78407000000001, 8.11609)); - quadtree.put(new DegreePosition(50.78407000000001, 8.11761)); - quadtree.put(new DegreePosition(50.78412, 8.118820000000001)); - quadtree.put(new DegreePosition(50.784240000000004, 8.11996)); - quadtree.put(new DegreePosition(50.78457, 8.121500000000001)); - quadtree.put(new DegreePosition(50.785250000000005, 8.12428)); - quadtree.put(new DegreePosition(50.78555, 8.125720000000001)); - quadtree.put(new DegreePosition(50.78586000000001, 8.12766)); - quadtree.put(new DegreePosition(50.786060000000006, 8.129610000000001)); - quadtree.put(new DegreePosition(50.78614, 8.13101)); - quadtree.put(new DegreePosition(50.78609, 8.13326)); - quadtree.put(new DegreePosition(50.78598, 8.13451)); - quadtree.put(new DegreePosition(50.78578, 8.135900000000001)); - quadtree.put(new DegreePosition(50.7854, 8.137880000000001)); - quadtree.put(new DegreePosition(50.78511, 8.13907)); - quadtree.put(new DegreePosition(50.784330000000004, 8.14145)); - quadtree.put(new DegreePosition(50.783840000000005, 8.14282)); - quadtree.put(new DegreePosition(50.78352, 8.143510000000001)); - quadtree.put(new DegreePosition(50.78285, 8.1446)); - quadtree.put(new DegreePosition(50.781650000000006, 8.14638)); - quadtree.put(new DegreePosition(50.781330000000004, 8.146920000000001)); - quadtree.put(new DegreePosition(50.780280000000005, 8.148060000000001)); - quadtree.put(new DegreePosition(50.77908000000001, 8.149090000000001)); - quadtree.put(new DegreePosition(50.7781, 8.14973)); - quadtree.put(new DegreePosition(50.77716, 8.150160000000001)); - quadtree.put(new DegreePosition(50.77579, 8.15053)); - quadtree.put(new DegreePosition(50.773810000000005, 8.150770000000001)); - quadtree.put(new DegreePosition(50.772470000000006, 8.15085)); - quadtree.put(new DegreePosition(50.77046000000001, 8.15074)); - quadtree.put(new DegreePosition(50.76778, 8.15074)); - quadtree.put(new DegreePosition(50.76690000000001, 8.15079)); - quadtree.put(new DegreePosition(50.76615, 8.15093)); - quadtree.put(new DegreePosition(50.76543, 8.15116)); - quadtree.put(new DegreePosition(50.764480000000006, 8.151670000000001)); - quadtree.put(new DegreePosition(50.763690000000004, 8.15222)); - quadtree.put(new DegreePosition(50.76299, 8.152890000000001)); - quadtree.put(new DegreePosition(50.76243, 8.15352)); - quadtree.put(new DegreePosition(50.76185, 8.15432)); - quadtree.put(new DegreePosition(50.761190000000006, 8.15549)); - quadtree.put(new DegreePosition(50.760670000000005, 8.1567)); - quadtree.put(new DegreePosition(50.76019, 8.15832)); - quadtree.put(new DegreePosition(50.759910000000005, 8.15996)); - quadtree.put(new DegreePosition(50.75983, 8.16092)); - quadtree.put(new DegreePosition(50.75974, 8.16243)); - quadtree.put(new DegreePosition(50.759780000000006, 8.164000000000001)); - quadtree.put(new DegreePosition(50.75992, 8.16568)); - quadtree.put(new DegreePosition(50.75997, 8.168050000000001)); - quadtree.put(new DegreePosition(50.75992, 8.16923)); - quadtree.put(new DegreePosition(50.759820000000005, 8.170480000000001)); - quadtree.put(new DegreePosition(50.75959, 8.172130000000001)); - quadtree.put(new DegreePosition(50.759190000000004, 8.17365)); - quadtree.put(new DegreePosition(50.75893000000001, 8.17436)); - quadtree.put(new DegreePosition(50.75638000000001, 8.18037)); - quadtree.put(new DegreePosition(50.755810000000004, 8.181840000000001)); - quadtree.put(new DegreePosition(50.755410000000005, 8.18307)); - quadtree.put(new DegreePosition(50.755160000000004, 8.184000000000001)); - quadtree.put(new DegreePosition(50.75482, 8.185960000000001)); - quadtree.put(new DegreePosition(50.75464, 8.18824)); - quadtree.put(new DegreePosition(50.75457, 8.19096)); - quadtree.put(new DegreePosition(50.754670000000004, 8.193750000000001)); - quadtree.put(new DegreePosition(50.75482, 8.19589)); - quadtree.put(new DegreePosition(50.75533, 8.20124)); - quadtree.put(new DegreePosition(50.75542, 8.202910000000001)); - quadtree.put(new DegreePosition(50.755390000000006, 8.20532)); - quadtree.put(new DegreePosition(50.75526000000001, 8.206850000000001)); - quadtree.put(new DegreePosition(50.75502, 8.20803)); - quadtree.put(new DegreePosition(50.75486, 8.20864)); - quadtree.put(new DegreePosition(50.75448, 8.209750000000001)); - quadtree.put(new DegreePosition(50.75424, 8.210320000000001)); - quadtree.put(new DegreePosition(50.75347000000001, 8.211730000000001)); - quadtree.put(new DegreePosition(50.75301, 8.21236)); - quadtree.put(new DegreePosition(50.75206000000001, 8.213370000000001)); - quadtree.put(new DegreePosition(50.74982000000001, 8.215440000000001)); - quadtree.put(new DegreePosition(50.748900000000006, 8.21657)); - quadtree.put(new DegreePosition(50.74851, 8.21718)); - quadtree.put(new DegreePosition(50.748200000000004, 8.21775)); - quadtree.put(new DegreePosition(50.74777, 8.21879)); - quadtree.put(new DegreePosition(50.7475, 8.21968)); - quadtree.put(new DegreePosition(50.747240000000005, 8.220880000000001)); - quadtree.put(new DegreePosition(50.7471, 8.22189)); - quadtree.put(new DegreePosition(50.74703, 8.222710000000001)); - quadtree.put(new DegreePosition(50.746990000000004, 8.22573)); - quadtree.put(new DegreePosition(50.74696, 8.22653)); - quadtree.put(new DegreePosition(50.74687, 8.22747)); - quadtree.put(new DegreePosition(50.746680000000005, 8.228530000000001)); - quadtree.put(new DegreePosition(50.746410000000004, 8.22976)); - quadtree.put(new DegreePosition(50.74609, 8.23095)); - quadtree.put(new DegreePosition(50.74515, 8.23367)); - quadtree.put(new DegreePosition(50.744620000000005, 8.235650000000001)); - quadtree.put(new DegreePosition(50.744310000000006, 8.237150000000002)); - quadtree.put(new DegreePosition(50.744150000000005, 8.238480000000001)); - quadtree.put(new DegreePosition(50.7441, 8.240540000000001)); - quadtree.put(new DegreePosition(50.74418000000001, 8.24193)); - quadtree.put(new DegreePosition(50.74445000000001, 8.24365)); - quadtree.put(new DegreePosition(50.745020000000004, 8.245940000000001)); - quadtree.put(new DegreePosition(50.74539000000001, 8.24769)); - quadtree.put(new DegreePosition(50.74557, 8.24881)); - quadtree.put(new DegreePosition(50.74562, 8.249590000000001)); - quadtree.put(new DegreePosition(50.7456, 8.250290000000001)); - quadtree.put(new DegreePosition(50.74542, 8.25223)); - quadtree.put(new DegreePosition(50.74519, 8.253340000000001)); - quadtree.put(new DegreePosition(50.7449, 8.2543)); - quadtree.put(new DegreePosition(50.74461, 8.25505)); - quadtree.put(new DegreePosition(50.74306000000001, 8.25831)); - quadtree.put(new DegreePosition(50.74279000000001, 8.25904)); - quadtree.put(new DegreePosition(50.74255, 8.25988)); - quadtree.put(new DegreePosition(50.742270000000005, 8.2612)); - quadtree.put(new DegreePosition(50.74213, 8.262070000000001)); - quadtree.put(new DegreePosition(50.742070000000005, 8.26314)); - quadtree.put(new DegreePosition(50.742090000000005, 8.26567)); - quadtree.put(new DegreePosition(50.741980000000005, 8.26735)); - quadtree.put(new DegreePosition(50.74181, 8.2687)); - quadtree.put(new DegreePosition(50.741670000000006, 8.26931)); - quadtree.put(new DegreePosition(50.741080000000004, 8.27088)); - quadtree.put(new DegreePosition(50.74072, 8.27158)); - quadtree.put(new DegreePosition(50.740030000000004, 8.27257)); - quadtree.put(new DegreePosition(50.73962, 8.273000000000001)); - quadtree.put(new DegreePosition(50.73875, 8.27365)); - quadtree.put(new DegreePosition(50.73783, 8.27405)); - quadtree.put(new DegreePosition(50.73745, 8.27416)); - quadtree.put(new DegreePosition(50.736830000000005, 8.27424)); - quadtree.put(new DegreePosition(50.734120000000004, 8.274090000000001)); - quadtree.put(new DegreePosition(50.73353, 8.27411)); - quadtree.put(new DegreePosition(50.732890000000005, 8.27424)); - quadtree.put(new DegreePosition(50.73174, 8.274790000000001)); - quadtree.put(new DegreePosition(50.73114, 8.27524)); - quadtree.put(new DegreePosition(50.7306, 8.27574)); - quadtree.put(new DegreePosition(50.72831000000001, 8.27865)); - quadtree.put(new DegreePosition(50.727430000000005, 8.279480000000001)); - quadtree.put(new DegreePosition(50.72471, 8.28134)); - quadtree.put(new DegreePosition(50.72368, 8.282210000000001)); - quadtree.put(new DegreePosition(50.7229, 8.28307)); - quadtree.put(new DegreePosition(50.72126, 8.28542)); - quadtree.put(new DegreePosition(50.72023, 8.28669)); - quadtree.put(new DegreePosition(50.71963, 8.28725)); - quadtree.put(new DegreePosition(50.71885, 8.287880000000001)); - quadtree.put(new DegreePosition(50.718120000000006, 8.28832)); - quadtree.put(new DegreePosition(50.7173, 8.2887)); - quadtree.put(new DegreePosition(50.71656, 8.28897)); - quadtree.put(new DegreePosition(50.71553, 8.28916)); - quadtree.put(new DegreePosition(50.71408, 8.28923)); - quadtree.put(new DegreePosition(50.713060000000006, 8.28913)); - quadtree.put(new DegreePosition(50.709050000000005, 8.28805)); - quadtree.put(new DegreePosition(50.70792, 8.28781)); - quadtree.put(new DegreePosition(50.70673000000001, 8.28772)); - quadtree.put(new DegreePosition(50.705130000000004, 8.28782)); - quadtree.put(new DegreePosition(50.70335000000001, 8.28827)); - quadtree.put(new DegreePosition(50.70219, 8.28876)); - quadtree.put(new DegreePosition(50.70096, 8.289520000000001)); - quadtree.put(new DegreePosition(50.697030000000005, 8.29296)); - quadtree.put(new DegreePosition(50.69567000000001, 8.294)); - quadtree.put(new DegreePosition(50.69485, 8.294540000000001)); - quadtree.put(new DegreePosition(50.69411, 8.29495)); - quadtree.put(new DegreePosition(50.6933, 8.295300000000001)); - quadtree.put(new DegreePosition(50.692690000000006, 8.295490000000001)); - quadtree.put(new DegreePosition(50.692040000000006, 8.29561)); - quadtree.put(new DegreePosition(50.69153000000001, 8.29564)); - quadtree.put(new DegreePosition(50.69035, 8.295390000000001)); - quadtree.put(new DegreePosition(50.68981, 8.29517)); - quadtree.put(new DegreePosition(50.68932, 8.2949)); - quadtree.put(new DegreePosition(50.688970000000005, 8.29465)); - quadtree.put(new DegreePosition(50.68847, 8.29418)); - quadtree.put(new DegreePosition(50.687760000000004, 8.293230000000001)); - quadtree.put(new DegreePosition(50.68713, 8.29218)); - quadtree.put(new DegreePosition(50.68657, 8.29096)); - quadtree.put(new DegreePosition(50.68558, 8.289000000000001)); - quadtree.put(new DegreePosition(50.684940000000005, 8.28805)); - quadtree.put(new DegreePosition(50.684430000000006, 8.28739)); - quadtree.put(new DegreePosition(50.682970000000005, 8.2859)); - quadtree.put(new DegreePosition(50.68198, 8.28515)); - quadtree.put(new DegreePosition(50.68065000000001, 8.28434)); - quadtree.put(new DegreePosition(50.679410000000004, 8.28377)); - quadtree.put(new DegreePosition(50.67868000000001, 8.28353)); - quadtree.put(new DegreePosition(50.67734, 8.283330000000001)); - quadtree.put(new DegreePosition(50.676190000000005, 8.28331)); - quadtree.put(new DegreePosition(50.674110000000006, 8.28378)); - quadtree.put(new DegreePosition(50.672760000000004, 8.28443)); - quadtree.put(new DegreePosition(50.67183000000001, 8.28505)); - quadtree.put(new DegreePosition(50.671130000000005, 8.28561)); - quadtree.put(new DegreePosition(50.67058, 8.286140000000001)); - quadtree.put(new DegreePosition(50.66993, 8.28687)); - quadtree.put(new DegreePosition(50.66884, 8.28832)); - quadtree.put(new DegreePosition(50.66789000000001, 8.28984)); - quadtree.put(new DegreePosition(50.667030000000004, 8.291440000000001)); - quadtree.put(new DegreePosition(50.66601000000001, 8.29364)); - quadtree.put(new DegreePosition(50.665350000000004, 8.295240000000002)); - quadtree.put(new DegreePosition(50.66480000000001, 8.29676)); - quadtree.put(new DegreePosition(50.66442000000001, 8.29808)); - quadtree.put(new DegreePosition(50.66405, 8.299660000000001)); - quadtree.put(new DegreePosition(50.663720000000005, 8.30133)); - quadtree.put(new DegreePosition(50.66330000000001, 8.304300000000001)); - quadtree.put(new DegreePosition(50.66290000000001, 8.307960000000001)); - quadtree.put(new DegreePosition(50.662670000000006, 8.309560000000001)); - quadtree.put(new DegreePosition(50.6623, 8.31123)); - quadtree.put(new DegreePosition(50.66174, 8.313260000000001)); - quadtree.put(new DegreePosition(50.660970000000006, 8.315370000000001)); - quadtree.put(new DegreePosition(50.660320000000006, 8.316650000000001)); - quadtree.put(new DegreePosition(50.659740000000006, 8.317590000000001)); - quadtree.put(new DegreePosition(50.65899, 8.318570000000001)); - quadtree.put(new DegreePosition(50.658210000000004, 8.3193)); - quadtree.put(new DegreePosition(50.657070000000004, 8.31994)); - quadtree.put(new DegreePosition(50.65578000000001, 8.320300000000001)); - quadtree.put(new DegreePosition(50.65391, 8.320400000000001)); - quadtree.put(new DegreePosition(50.65328, 8.320500000000001)); - quadtree.put(new DegreePosition(50.65240000000001, 8.32074)); - quadtree.put(new DegreePosition(50.65128000000001, 8.32118)); - quadtree.put(new DegreePosition(50.65091, 8.32137)); - quadtree.put(new DegreePosition(50.6465, 8.32409)); - quadtree.put(new DegreePosition(50.645360000000004, 8.32454)); - quadtree.put(new DegreePosition(50.644740000000006, 8.32469)); - quadtree.put(new DegreePosition(50.64193, 8.32482)); - quadtree.put(new DegreePosition(50.639920000000004, 8.32511)); - quadtree.put(new DegreePosition(50.63812, 8.325650000000001)); - quadtree.put(new DegreePosition(50.63673000000001, 8.326400000000001)); - quadtree.put(new DegreePosition(50.635740000000006, 8.32704)); - quadtree.put(new DegreePosition(50.634570000000004, 8.32797)); - quadtree.put(new DegreePosition(50.63354, 8.32891)); - quadtree.put(new DegreePosition(50.63253, 8.32995)); - quadtree.put(new DegreePosition(50.629650000000005, 8.33336)); - quadtree.put(new DegreePosition(50.62903000000001, 8.33422)); - quadtree.put(new DegreePosition(50.628550000000004, 8.335)); - quadtree.put(new DegreePosition(50.62765, 8.33667)); - quadtree.put(new DegreePosition(50.627250000000004, 8.33755)); - quadtree.put(new DegreePosition(50.626760000000004, 8.33876)); - quadtree.put(new DegreePosition(50.62648, 8.33961)); - quadtree.put(new DegreePosition(50.62586, 8.341890000000001)); - quadtree.put(new DegreePosition(50.62556000000001, 8.34319)); - quadtree.put(new DegreePosition(50.62519, 8.34521)); - quadtree.put(new DegreePosition(50.624990000000004, 8.34656)); - quadtree.put(new DegreePosition(50.62485, 8.34781)); - quadtree.put(new DegreePosition(50.6246, 8.3511)); - quadtree.put(new DegreePosition(50.62435000000001, 8.352910000000001)); - quadtree.put(new DegreePosition(50.624050000000004, 8.3544)); - quadtree.put(new DegreePosition(50.623810000000006, 8.35543)); - quadtree.put(new DegreePosition(50.62366, 8.35593)); - quadtree.put(new DegreePosition(50.622240000000005, 8.359910000000001)); - quadtree.put(new DegreePosition(50.621770000000005, 8.36156)); - quadtree.put(new DegreePosition(50.62156, 8.362480000000001)); - quadtree.put(new DegreePosition(50.621230000000004, 8.3644)); - quadtree.put(new DegreePosition(50.62078, 8.36975)); - quadtree.put(new DegreePosition(50.620520000000006, 8.37114)); - quadtree.put(new DegreePosition(50.620160000000006, 8.37249)); - quadtree.put(new DegreePosition(50.61988, 8.373320000000001)); - quadtree.put(new DegreePosition(50.61932, 8.374690000000001)); - quadtree.put(new DegreePosition(50.61887, 8.375950000000001)); - quadtree.put(new DegreePosition(50.618570000000005, 8.37725)); - quadtree.put(new DegreePosition(50.61827, 8.37898)); - quadtree.put(new DegreePosition(50.618170000000006, 8.380270000000001)); - quadtree.put(new DegreePosition(50.61816, 8.382190000000001)); - quadtree.put(new DegreePosition(50.618520000000004, 8.389460000000001)); - quadtree.put(new DegreePosition(50.618570000000005, 8.39309)); - quadtree.put(new DegreePosition(50.618500000000004, 8.394480000000001)); - quadtree.put(new DegreePosition(50.618410000000004, 8.395470000000001)); - quadtree.put(new DegreePosition(50.61824000000001, 8.39675)); - quadtree.put(new DegreePosition(50.618080000000006, 8.39764)); - quadtree.put(new DegreePosition(50.61777000000001, 8.39906)); - quadtree.put(new DegreePosition(50.61713, 8.40116)); - quadtree.put(new DegreePosition(50.61679, 8.40215)); - quadtree.put(new DegreePosition(50.612660000000005, 8.413)); - quadtree.put(new DegreePosition(50.61168000000001, 8.415470000000001)); - quadtree.put(new DegreePosition(50.611430000000006, 8.41623)); - quadtree.put(new DegreePosition(50.61102, 8.41787)); - quadtree.put(new DegreePosition(50.61056000000001, 8.42032)); - quadtree.put(new DegreePosition(50.61019, 8.4238)); - quadtree.put(new DegreePosition(50.60992, 8.42535)); - quadtree.put(new DegreePosition(50.60947, 8.42707)); - quadtree.put(new DegreePosition(50.60904000000001, 8.42833)); - quadtree.put(new DegreePosition(50.60857000000001, 8.42956)); - quadtree.put(new DegreePosition(50.60792000000001, 8.43158)); - quadtree.put(new DegreePosition(50.60761, 8.432680000000001)); - quadtree.put(new DegreePosition(50.60723, 8.434370000000001)); - quadtree.put(new DegreePosition(50.60701, 8.43645)); - quadtree.put(new DegreePosition(50.60698000000001, 8.43796)); - quadtree.put(new DegreePosition(50.6071, 8.44045)); - quadtree.put(new DegreePosition(50.60718000000001, 8.443100000000001)); - quadtree.put(new DegreePosition(50.60717, 8.444220000000001)); - quadtree.put(new DegreePosition(50.607020000000006, 8.446140000000002)); - quadtree.put(new DegreePosition(50.606770000000004, 8.44772)); - quadtree.put(new DegreePosition(50.60647, 8.44902)); - quadtree.put(new DegreePosition(50.606100000000005, 8.450230000000001)); - quadtree.put(new DegreePosition(50.60551, 8.45195)); - quadtree.put(new DegreePosition(50.605030000000006, 8.45358)); - quadtree.put(new DegreePosition(50.60465000000001, 8.45495)); - quadtree.put(new DegreePosition(50.60445000000001, 8.455950000000001)); - quadtree.put(new DegreePosition(50.60427000000001, 8.457230000000001)); - quadtree.put(new DegreePosition(50.60421, 8.458060000000001)); - quadtree.put(new DegreePosition(50.60419, 8.45945)); - quadtree.put(new DegreePosition(50.6043, 8.46292)); - quadtree.put(new DegreePosition(50.604290000000006, 8.46471)); - quadtree.put(new DegreePosition(50.60416000000001, 8.4664)); - quadtree.put(new DegreePosition(50.603930000000005, 8.468)); - quadtree.put(new DegreePosition(50.603790000000004, 8.46873)); - quadtree.put(new DegreePosition(50.603570000000005, 8.469650000000001)); - quadtree.put(new DegreePosition(50.60318, 8.471)); - quadtree.put(new DegreePosition(50.60242, 8.473030000000001)); - quadtree.put(new DegreePosition(50.60193, 8.474110000000001)); - quadtree.put(new DegreePosition(50.60146, 8.47493)); - quadtree.put(new DegreePosition(50.600730000000006, 8.47606)); - quadtree.put(new DegreePosition(50.599160000000005, 8.478340000000001)); - quadtree.put(new DegreePosition(50.59787000000001, 8.480580000000002)); - quadtree.put(new DegreePosition(50.59725, 8.48202)); - quadtree.put(new DegreePosition(50.59673, 8.48366)); - quadtree.put(new DegreePosition(50.596270000000004, 8.48583)); - quadtree.put(new DegreePosition(50.59617, 8.48643)); - quadtree.put(new DegreePosition(50.596000000000004, 8.48804)); - quadtree.put(new DegreePosition(50.59592000000001, 8.490260000000001)); - quadtree.put(new DegreePosition(50.59588, 8.49361)); - quadtree.put(new DegreePosition(50.59581000000001, 8.49463)); - quadtree.put(new DegreePosition(50.595710000000004, 8.49549)); - quadtree.put(new DegreePosition(50.59539, 8.49712)); - quadtree.put(new DegreePosition(50.59505000000001, 8.49849)); - quadtree.put(new DegreePosition(50.594030000000004, 8.50145)); - quadtree.put(new DegreePosition(50.59357000000001, 8.50289)); - quadtree.put(new DegreePosition(50.593340000000005, 8.50379)); - quadtree.put(new DegreePosition(50.593160000000005, 8.50468)); - quadtree.put(new DegreePosition(50.59292000000001, 8.506120000000001)); - quadtree.put(new DegreePosition(50.59279, 8.50716)); - quadtree.put(new DegreePosition(50.592740000000006, 8.50793)); - quadtree.put(new DegreePosition(50.592740000000006, 8.50988)); - quadtree.put(new DegreePosition(50.59282, 8.51248)); - quadtree.put(new DegreePosition(50.59273, 8.513850000000001)); - quadtree.put(new DegreePosition(50.59245000000001, 8.5157)); - quadtree.put(new DegreePosition(50.592110000000005, 8.51736)); - quadtree.put(new DegreePosition(50.59109, 8.52072)); - quadtree.put(new DegreePosition(50.58995, 8.52393)); - quadtree.put(new DegreePosition(50.58919, 8.525780000000001)); - quadtree.put(new DegreePosition(50.588350000000005, 8.52753)); - quadtree.put(new DegreePosition(50.586940000000006, 8.53031)); - quadtree.put(new DegreePosition(50.585660000000004, 8.5327)); - quadtree.put(new DegreePosition(50.58467, 8.534270000000001)); - quadtree.put(new DegreePosition(50.582950000000004, 8.53668)); - quadtree.put(new DegreePosition(50.58055, 8.539750000000002)); - quadtree.put(new DegreePosition(50.57909, 8.541250000000002)); - quadtree.put(new DegreePosition(50.578230000000005, 8.542060000000001)); - quadtree.put(new DegreePosition(50.57721, 8.542910000000001)); - quadtree.put(new DegreePosition(50.57509, 8.544360000000001)); - quadtree.put(new DegreePosition(50.572190000000006, 8.546000000000001)); - quadtree.put(new DegreePosition(50.56996, 8.54697)); - quadtree.put(new DegreePosition(50.567350000000005, 8.548210000000001)); - quadtree.put(new DegreePosition(50.566590000000005, 8.548670000000001)); - quadtree.put(new DegreePosition(50.565740000000005, 8.5493)); - quadtree.put(new DegreePosition(50.56519, 8.54981)); - quadtree.put(new DegreePosition(50.56466, 8.55035)); - quadtree.put(new DegreePosition(50.56418000000001, 8.551010000000002)); - quadtree.put(new DegreePosition(50.56376, 8.551630000000001)); - quadtree.put(new DegreePosition(50.56293, 8.55311)); - quadtree.put(new DegreePosition(50.56206, 8.55527)); - quadtree.put(new DegreePosition(50.56136000000001, 8.55738)); - quadtree.put(new DegreePosition(50.56071000000001, 8.55915)); - quadtree.put(new DegreePosition(50.560230000000004, 8.560160000000002)); - quadtree.put(new DegreePosition(50.55978, 8.560970000000001)); - quadtree.put(new DegreePosition(50.55922, 8.56179)); - quadtree.put(new DegreePosition(50.558910000000004, 8.56215)); - quadtree.put(new DegreePosition(50.55834, 8.562700000000001)); - quadtree.put(new DegreePosition(50.55731, 8.56347)); - quadtree.put(new DegreePosition(50.55677000000001, 8.56377)); - quadtree.put(new DegreePosition(50.55624, 8.563960000000002)); - quadtree.put(new DegreePosition(50.55556000000001, 8.564110000000001)); - quadtree.put(new DegreePosition(50.55353, 8.564390000000001)); - quadtree.put(new DegreePosition(50.552040000000005, 8.56466)); - quadtree.put(new DegreePosition(50.55109, 8.56494)); - quadtree.put(new DegreePosition(50.550160000000005, 8.56536)); - quadtree.put(new DegreePosition(50.549730000000004, 8.565620000000001)); - quadtree.put(new DegreePosition(50.54919, 8.56601)); - quadtree.put(new DegreePosition(50.548460000000006, 8.56667)); - quadtree.put(new DegreePosition(50.54798, 8.567250000000001)); - quadtree.put(new DegreePosition(50.5469, 8.56872)); - quadtree.put(new DegreePosition(50.54536, 8.57126)); - quadtree.put(new DegreePosition(50.542260000000006, 8.576590000000001)); - quadtree.put(new DegreePosition(50.541430000000005, 8.577720000000001)); - quadtree.put(new DegreePosition(50.540580000000006, 8.57877)); - quadtree.put(new DegreePosition(50.539480000000005, 8.57994)); - quadtree.put(new DegreePosition(50.537870000000005, 8.58139)); - quadtree.put(new DegreePosition(50.53676, 8.582270000000001)); - quadtree.put(new DegreePosition(50.534110000000005, 8.58411)); - quadtree.put(new DegreePosition(50.53333000000001, 8.58478)); - quadtree.put(new DegreePosition(50.53266000000001, 8.585450000000002)); - quadtree.put(new DegreePosition(50.5317, 8.586540000000001)); - quadtree.put(new DegreePosition(50.53099, 8.587610000000002)); - quadtree.put(new DegreePosition(50.53056, 8.58835)); - quadtree.put(new DegreePosition(50.530080000000005, 8.58932)); - quadtree.put(new DegreePosition(50.52947, 8.590900000000001)); - quadtree.put(new DegreePosition(50.529050000000005, 8.592310000000001)); - quadtree.put(new DegreePosition(50.528800000000004, 8.593430000000001)); - quadtree.put(new DegreePosition(50.528620000000004, 8.594510000000001)); - quadtree.put(new DegreePosition(50.52828, 8.597700000000001)); - quadtree.put(new DegreePosition(50.527750000000005, 8.60692)); - quadtree.put(new DegreePosition(50.52731000000001, 8.61212)); - quadtree.put(new DegreePosition(50.526300000000006, 8.62259)); - quadtree.put(new DegreePosition(50.525800000000004, 8.626420000000001)); - quadtree.put(new DegreePosition(50.52514000000001, 8.630510000000001)); - quadtree.put(new DegreePosition(50.52481, 8.63277)); - quadtree.put(new DegreePosition(50.524010000000004, 8.6376)); - quadtree.put(new DegreePosition(50.52364000000001, 8.64067)); - quadtree.put(new DegreePosition(50.522420000000004, 8.645380000000001)); - quadtree.put(new DegreePosition(50.52181, 8.64794)); - quadtree.put(new DegreePosition(50.521530000000006, 8.648950000000001)); - quadtree.put(new DegreePosition(50.52031, 8.654100000000001)); - quadtree.put(new DegreePosition(50.51888, 8.65944)); - quadtree.put(new DegreePosition(50.51749, 8.66398)); - quadtree.put(new DegreePosition(50.51699000000001, 8.66531)); - quadtree.put(new DegreePosition(50.516650000000006, 8.666110000000002)); - quadtree.put(new DegreePosition(50.515150000000006, 8.66932)); - quadtree.put(new DegreePosition(50.5146, 8.67041)); - quadtree.put(new DegreePosition(50.513670000000005, 8.6721)); - quadtree.put(new DegreePosition(50.51285000000001, 8.673440000000001)); - quadtree.put(new DegreePosition(50.511810000000004, 8.674930000000002)); - quadtree.put(new DegreePosition(50.510630000000006, 8.67633)); - quadtree.put(new DegreePosition(50.50940000000001, 8.677700000000002)); - quadtree.put(new DegreePosition(50.508810000000004, 8.67824)); - quadtree.put(new DegreePosition(50.50750000000001, 8.67932)); - quadtree.put(new DegreePosition(50.50681, 8.679810000000002)); - quadtree.put(new DegreePosition(50.50526000000001, 8.680760000000001)); - quadtree.put(new DegreePosition(50.504470000000005, 8.68116)); - quadtree.put(new DegreePosition(50.50274, 8.681830000000001)); - quadtree.put(new DegreePosition(50.50198, 8.682070000000001)); - quadtree.put(new DegreePosition(50.498810000000006, 8.682690000000001)); - quadtree.put(new DegreePosition(50.49728, 8.68313)); - quadtree.put(new DegreePosition(50.49476000000001, 8.68368)); - quadtree.put(new DegreePosition(50.49369, 8.684050000000001)); - quadtree.put(new DegreePosition(50.49269, 8.68449)); - quadtree.put(new DegreePosition(50.49157, 8.68506)); - quadtree.put(new DegreePosition(50.490520000000004, 8.685740000000001)); - quadtree.put(new DegreePosition(50.48989, 8.68622)); - quadtree.put(new DegreePosition(50.48901000000001, 8.686950000000001)); - quadtree.put(new DegreePosition(50.488040000000005, 8.687940000000001)); - quadtree.put(new DegreePosition(50.487010000000005, 8.68913)); - quadtree.put(new DegreePosition(50.48583000000001, 8.69068)); - quadtree.put(new DegreePosition(50.484260000000006, 8.69318)); - quadtree.put(new DegreePosition(50.483340000000005, 8.69505)); - quadtree.put(new DegreePosition(50.48272000000001, 8.69658)); - quadtree.put(new DegreePosition(50.482110000000006, 8.698260000000001)); - quadtree.put(new DegreePosition(50.481390000000005, 8.70049)); - quadtree.put(new DegreePosition(50.48093, 8.70208)); - quadtree.put(new DegreePosition(50.48021000000001, 8.705020000000001)); - quadtree.put(new DegreePosition(50.47822000000001, 8.71437)); - quadtree.put(new DegreePosition(50.477940000000004, 8.715430000000001)); - quadtree.put(new DegreePosition(50.47721000000001, 8.717260000000001)); - quadtree.put(new DegreePosition(50.47652, 8.718820000000001)); - quadtree.put(new DegreePosition(50.476240000000004, 8.71929)); - quadtree.put(new DegreePosition(50.475660000000005, 8.72009)); - quadtree.put(new DegreePosition(50.47426, 8.72159)); - quadtree.put(new DegreePosition(50.47375, 8.722000000000001)); - quadtree.put(new DegreePosition(50.47307000000001, 8.7224)); - quadtree.put(new DegreePosition(50.472390000000004, 8.72273)); - quadtree.put(new DegreePosition(50.47173, 8.72295)); - quadtree.put(new DegreePosition(50.471050000000005, 8.723090000000001)); - quadtree.put(new DegreePosition(50.46989000000001, 8.723080000000001)); - quadtree.put(new DegreePosition(50.46876, 8.72295)); - quadtree.put(new DegreePosition(50.466840000000005, 8.72241)); - quadtree.put(new DegreePosition(50.465230000000005, 8.721820000000001)); - quadtree.put(new DegreePosition(50.46338, 8.72098)); - quadtree.put(new DegreePosition(50.463100000000004, 8.72091)); - quadtree.put(new DegreePosition(50.461200000000005, 8.71997)); - quadtree.put(new DegreePosition(50.46023, 8.71925)); - quadtree.put(new DegreePosition(50.459410000000005, 8.718570000000001)); - quadtree.put(new DegreePosition(50.458600000000004, 8.7178)); - quadtree.put(new DegreePosition(50.45769000000001, 8.716790000000001)); - quadtree.put(new DegreePosition(50.456610000000005, 8.71546)); - quadtree.put(new DegreePosition(50.455490000000005, 8.7139)); - quadtree.put(new DegreePosition(50.45445, 8.712250000000001)); - quadtree.put(new DegreePosition(50.45373000000001, 8.710980000000001)); - quadtree.put(new DegreePosition(50.45327, 8.71006)); - quadtree.put(new DegreePosition(50.45239, 8.70799)); - quadtree.put(new DegreePosition(50.44941000000001, 8.70059)); - quadtree.put(new DegreePosition(50.448820000000005, 8.69945)); - quadtree.put(new DegreePosition(50.448460000000004, 8.69888)); - quadtree.put(new DegreePosition(50.447900000000004, 8.69806)); - quadtree.put(new DegreePosition(50.44698, 8.69688)); - quadtree.put(new DegreePosition(50.44641000000001, 8.6963)); - quadtree.put(new DegreePosition(50.44548, 8.695500000000001)); - quadtree.put(new DegreePosition(50.44501, 8.695160000000001)); - quadtree.put(new DegreePosition(50.44411, 8.69472)); - quadtree.put(new DegreePosition(50.44333, 8.69443)); - quadtree.put(new DegreePosition(50.44202000000001, 8.694180000000001)); - quadtree.put(new DegreePosition(50.44145, 8.694170000000002)); - quadtree.put(new DegreePosition(50.440560000000005, 8.69425)); - quadtree.put(new DegreePosition(50.432640000000006, 8.69574)); - quadtree.put(new DegreePosition(50.42264, 8.697370000000001)); - quadtree.put(new DegreePosition(50.405300000000004, 8.70054)); - quadtree.put(new DegreePosition(50.395720000000004, 8.70219)); - quadtree.put(new DegreePosition(50.391580000000005, 8.70298)); - quadtree.put(new DegreePosition(50.38085, 8.7048)); - quadtree.put(new DegreePosition(50.375750000000004, 8.70561)); - quadtree.put(new DegreePosition(50.374950000000005, 8.70569)); - quadtree.put(new DegreePosition(50.373850000000004, 8.70564)); - quadtree.put(new DegreePosition(50.37259, 8.705400000000001)); - quadtree.put(new DegreePosition(50.37050000000001, 8.70457)); - quadtree.put(new DegreePosition(50.369170000000004, 8.70387)); - quadtree.put(new DegreePosition(50.367610000000006, 8.702910000000001)); - quadtree.put(new DegreePosition(50.36612, 8.7018)); - quadtree.put(new DegreePosition(50.36075, 8.6972)); - quadtree.put(new DegreePosition(50.35831, 8.69533)); - quadtree.put(new DegreePosition(50.356950000000005, 8.69443)); - quadtree.put(new DegreePosition(50.35558, 8.69372)); - quadtree.put(new DegreePosition(50.354400000000005, 8.69335)); - quadtree.put(new DegreePosition(50.35246, 8.69284)); - quadtree.put(new DegreePosition(50.35105, 8.692620000000002)); - quadtree.put(new DegreePosition(50.350170000000006, 8.69257)); - quadtree.put(new DegreePosition(50.34955, 8.692580000000001)); - quadtree.put(new DegreePosition(50.34857, 8.69275)); - quadtree.put(new DegreePosition(50.346230000000006, 8.693470000000001)); - quadtree.put(new DegreePosition(50.341210000000004, 8.69532)); - quadtree.put(new DegreePosition(50.34002, 8.695680000000001)); - quadtree.put(new DegreePosition(50.33867000000001, 8.695910000000001)); - quadtree.put(new DegreePosition(50.33753, 8.69594)); - quadtree.put(new DegreePosition(50.3361, 8.695860000000001)); - quadtree.put(new DegreePosition(50.333580000000005, 8.69542)); - quadtree.put(new DegreePosition(50.32048, 8.69252)); - quadtree.put(new DegreePosition(50.31851, 8.69196)); - quadtree.put(new DegreePosition(50.31781, 8.6917)); - quadtree.put(new DegreePosition(50.31709000000001, 8.69139)); - quadtree.put(new DegreePosition(50.31595, 8.690760000000001)); - quadtree.put(new DegreePosition(50.314600000000006, 8.68979)); - quadtree.put(new DegreePosition(50.31338, 8.68871)); - quadtree.put(new DegreePosition(50.31116, 8.68621)); - quadtree.put(new DegreePosition(50.30666, 8.680890000000002)); - quadtree.put(new DegreePosition(50.3034, 8.67722)); - quadtree.put(new DegreePosition(50.302640000000004, 8.67643)); - quadtree.put(new DegreePosition(50.301930000000006, 8.675830000000001)); - quadtree.put(new DegreePosition(50.30136, 8.675410000000001)); - quadtree.put(new DegreePosition(50.30044, 8.67488)); - quadtree.put(new DegreePosition(50.298860000000005, 8.674140000000001)); - quadtree.put(new DegreePosition(50.29008, 8.67112)); - quadtree.put(new DegreePosition(50.286120000000004, 8.669820000000001)); - quadtree.put(new DegreePosition(50.27376, 8.665550000000001)); - quadtree.put(new DegreePosition(50.26568, 8.662920000000002)); - quadtree.put(new DegreePosition(50.26428000000001, 8.662640000000001)); - quadtree.put(new DegreePosition(50.26334000000001, 8.662560000000001)); - quadtree.put(new DegreePosition(50.248900000000006, 8.662740000000001)); - quadtree.put(new DegreePosition(50.24667, 8.662730000000002)); - quadtree.put(new DegreePosition(50.231930000000006, 8.662970000000001)); - quadtree.put(new DegreePosition(50.21923, 8.6631)); - quadtree.put(new DegreePosition(50.21822, 8.66305)); - quadtree.put(new DegreePosition(50.21732, 8.66291)); - quadtree.put(new DegreePosition(50.216240000000006, 8.66267)); - quadtree.put(new DegreePosition(50.215270000000004, 8.662370000000001)); - quadtree.put(new DegreePosition(50.214200000000005, 8.66192)); - quadtree.put(new DegreePosition(50.21316, 8.661370000000002)); - quadtree.put(new DegreePosition(50.21162, 8.660350000000001)); - quadtree.put(new DegreePosition(50.210660000000004, 8.659600000000001)); - quadtree.put(new DegreePosition(50.209430000000005, 8.65841)); - quadtree.put(new DegreePosition(50.20864, 8.6575)); - quadtree.put(new DegreePosition(50.208090000000006, 8.656830000000001)); - quadtree.put(new DegreePosition(50.206920000000004, 8.65522)); - quadtree.put(new DegreePosition(50.206500000000005, 8.65456)); - quadtree.put(new DegreePosition(50.20488, 8.651760000000001)); - quadtree.put(new DegreePosition(50.203190000000006, 8.649080000000001)); - quadtree.put(new DegreePosition(50.19881, 8.64192)); - quadtree.put(new DegreePosition(50.196600000000004, 8.637440000000002)); - quadtree.put(new DegreePosition(50.188770000000005, 8.6239)); - quadtree.put(new DegreePosition(50.18795, 8.62259)); - quadtree.put(new DegreePosition(50.187070000000006, 8.621360000000001)); - quadtree.put(new DegreePosition(50.18627000000001, 8.6204)); - quadtree.put(new DegreePosition(50.185120000000005, 8.619190000000001)); - quadtree.put(new DegreePosition(50.18388, 8.61808)); - quadtree.put(new DegreePosition(50.182770000000005, 8.61726)); - quadtree.put(new DegreePosition(50.18178, 8.61665)); - quadtree.put(new DegreePosition(50.17159, 8.61101)); - quadtree.put(new DegreePosition(50.16395000000001, 8.606710000000001)); - quadtree.put(new DegreePosition(50.15317, 8.600760000000001)); - quadtree.put(new DegreePosition(50.149210000000004, 8.598640000000001)); - quadtree.put(new DegreePosition(50.14303, 8.59515)); - quadtree.put(new DegreePosition(50.13889, 8.592960000000001)); - quadtree.put(new DegreePosition(50.13496000000001, 8.590810000000001)); - quadtree.put(new DegreePosition(50.1332, 8.590190000000002)); - quadtree.put(new DegreePosition(50.13172, 8.58994)); - quadtree.put(new DegreePosition(50.13055000000001, 8.58993)); - quadtree.put(new DegreePosition(50.129450000000006, 8.59008)); - quadtree.put(new DegreePosition(50.12838000000001, 8.590340000000001)); - quadtree.put(new DegreePosition(50.12713, 8.59083)); - quadtree.put(new DegreePosition(50.12621000000001, 8.591320000000001)); - quadtree.put(new DegreePosition(50.118970000000004, 8.595970000000001)); - quadtree.put(new DegreePosition(50.10857000000001, 8.60274)); - quadtree.put(new DegreePosition(50.105970000000006, 8.604600000000001)); - quadtree.put(new DegreePosition(50.105050000000006, 8.605410000000001)); - quadtree.put(new DegreePosition(50.104200000000006, 8.60622)); - quadtree.put(new DegreePosition(50.10295000000001, 8.607560000000001)); - quadtree.put(new DegreePosition(50.10038, 8.61049)); - quadtree.put(new DegreePosition(50.09879, 8.61238)); - quadtree.put(new DegreePosition(50.09743, 8.61368)); - quadtree.put(new DegreePosition(50.09572000000001, 8.6151)); - quadtree.put(new DegreePosition(50.09489000000001, 8.61561)); - quadtree.put(new DegreePosition(50.093360000000004, 8.616290000000001)); - quadtree.put(new DegreePosition(50.09149000000001, 8.616940000000001)); - quadtree.put(new DegreePosition(50.087880000000006, 8.617780000000002)); - quadtree.put(new DegreePosition(50.08559, 8.618160000000001)); - quadtree.put(new DegreePosition(50.08471, 8.61824)); - quadtree.put(new DegreePosition(50.083000000000006, 8.61814)); - quadtree.put(new DegreePosition(50.081680000000006, 8.617930000000001)); - quadtree.put(new DegreePosition(50.080400000000004, 8.617560000000001)); - quadtree.put(new DegreePosition(50.0797, 8.6173)); - quadtree.put(new DegreePosition(50.07835000000001, 8.61668)); - quadtree.put(new DegreePosition(50.06631, 8.61067)); - quadtree.put(new DegreePosition(50.06239, 8.608640000000001)); - quadtree.put(new DegreePosition(50.05212, 8.60364)); - quadtree.put(new DegreePosition(50.03866000000001, 8.596810000000001)); - quadtree.put(new DegreePosition(50.03486, 8.59505)); - quadtree.put(new DegreePosition(50.033010000000004, 8.5943)); - quadtree.put(new DegreePosition(50.03032, 8.59347)); - quadtree.put(new DegreePosition(50.02763, 8.59284)); - quadtree.put(new DegreePosition(50.025240000000004, 8.59252)); - quadtree.put(new DegreePosition(50.024260000000005, 8.59247)); - quadtree.put(new DegreePosition(50.02208, 8.59247)); - quadtree.put(new DegreePosition(50.020790000000005, 8.592550000000001)); - quadtree.put(new DegreePosition(50.019270000000006, 8.59271)); - quadtree.put(new DegreePosition(50.016510000000004, 8.593240000000002)); - quadtree.put(new DegreePosition(49.983160000000005, 8.60124)); - quadtree.put(new DegreePosition(49.976580000000006, 8.60275)); - quadtree.put(new DegreePosition(49.97316000000001, 8.60363)); - quadtree.put(new DegreePosition(49.96228000000001, 8.60614)); - quadtree.put(new DegreePosition(49.95414, 8.60811)); - quadtree.put(new DegreePosition(49.95309, 8.608310000000001)); - quadtree.put(new DegreePosition(49.95217, 8.60857)); - quadtree.put(new DegreePosition(49.948350000000005, 8.609440000000001)); - quadtree.put(new DegreePosition(49.943200000000004, 8.610750000000001)); - quadtree.put(new DegreePosition(49.941720000000004, 8.611040000000001)); - quadtree.put(new DegreePosition(49.935280000000006, 8.612530000000001)); - quadtree.put(new DegreePosition(49.933550000000004, 8.6128)); - quadtree.put(new DegreePosition(49.93207, 8.612960000000001)); - quadtree.put(new DegreePosition(49.93084, 8.61302)); - quadtree.put(new DegreePosition(49.928740000000005, 8.61299)); - quadtree.put(new DegreePosition(49.926950000000005, 8.61283)); - quadtree.put(new DegreePosition(49.92591, 8.61269)); - quadtree.put(new DegreePosition(49.92389000000001, 8.612260000000001)); - quadtree.put(new DegreePosition(49.92083, 8.6113)); - quadtree.put(new DegreePosition(49.91532, 8.609390000000001)); - quadtree.put(new DegreePosition(49.914170000000006, 8.60905)); - quadtree.put(new DegreePosition(49.91042, 8.60819)); - quadtree.put(new DegreePosition(49.89902000000001, 8.60598)); - quadtree.put(new DegreePosition(49.89663, 8.605450000000001)); - quadtree.put(new DegreePosition(49.887750000000004, 8.603710000000001)); - quadtree.put(new DegreePosition(49.886900000000004, 8.603610000000002)); - quadtree.put(new DegreePosition(49.88288000000001, 8.60288)); - quadtree.put(new DegreePosition(49.87717000000001, 8.60196)); - quadtree.put(new DegreePosition(49.874700000000004, 8.60147)); - quadtree.put(new DegreePosition(49.87281, 8.60119)); - quadtree.put(new DegreePosition(49.870450000000005, 8.60072)); - quadtree.put(new DegreePosition(49.86542000000001, 8.599530000000001)); - quadtree.put(new DegreePosition(49.86164, 8.59872)); - quadtree.put(new DegreePosition(49.861450000000005, 8.59861)); - quadtree.put(new DegreePosition(49.86047000000001, 8.598360000000001)); - quadtree.put(new DegreePosition(49.857470000000006, 8.597240000000001)); - quadtree.put(new DegreePosition(49.85718000000001, 8.59717)); - quadtree.put(new DegreePosition(49.85662000000001, 8.597150000000001)); - quadtree.put(new DegreePosition(49.856350000000006, 8.59721)); - quadtree.put(new DegreePosition(49.85586000000001, 8.59744)); - quadtree.put(new DegreePosition(49.85559000000001, 8.597660000000001)); - quadtree.put(new DegreePosition(49.855250000000005, 8.598090000000001)); - quadtree.put(new DegreePosition(49.854940000000006, 8.59862)); - quadtree.put(new DegreePosition(49.85474000000001, 8.599110000000001)); - quadtree.put(new DegreePosition(49.85452, 8.599860000000001)); - quadtree.put(new DegreePosition(49.85405, 8.60206)); - quadtree.put(new DegreePosition(49.8539, 8.602490000000001)); - quadtree.put(new DegreePosition(49.85325, 8.603750000000002)); - quadtree.put(new DegreePosition(49.851670000000006, 8.605870000000001)); - quadtree.put(new DegreePosition(49.85031000000001, 8.6079)); - quadtree.put(new DegreePosition(49.84915, 8.609850000000002)); - quadtree.put(new DegreePosition(49.846590000000006, 8.61508)); - quadtree.put(new DegreePosition(49.84149000000001, 8.626510000000001)); - quadtree.put(new DegreePosition(49.840500000000006, 8.62828)); - quadtree.put(new DegreePosition(49.839980000000004, 8.62898)); - quadtree.put(new DegreePosition(49.838530000000006, 8.63066)); - quadtree.put(new DegreePosition(49.83744, 8.6317)); - quadtree.put(new DegreePosition(49.83612, 8.632670000000001)); - quadtree.put(new DegreePosition(49.83462, 8.63345)); - quadtree.put(new DegreePosition(49.83399000000001, 8.63371)); - quadtree.put(new DegreePosition(49.832080000000005, 8.63414)); - quadtree.put(new DegreePosition(49.831320000000005, 8.63423)); - quadtree.put(new DegreePosition(49.830540000000006, 8.6342)); - quadtree.put(new DegreePosition(49.82978000000001, 8.63409)); - quadtree.put(new DegreePosition(49.82876, 8.633780000000002)); - quadtree.put(new DegreePosition(49.82734000000001, 8.633180000000001)); - quadtree.put(new DegreePosition(49.82462, 8.63161)); - quadtree.put(new DegreePosition(49.821630000000006, 8.62977)); - quadtree.put(new DegreePosition(49.820370000000004, 8.6292)); - quadtree.put(new DegreePosition(49.81908000000001, 8.62875)); - quadtree.put(new DegreePosition(49.81687, 8.62841)); - quadtree.put(new DegreePosition(49.81134, 8.62866)); - quadtree.put(new DegreePosition(49.81027, 8.62861)); - quadtree.put(new DegreePosition(49.80881, 8.62828)); - quadtree.put(new DegreePosition(49.80682, 8.627690000000001)); - quadtree.put(new DegreePosition(49.80575, 8.62719)); - quadtree.put(new DegreePosition(49.804100000000005, 8.62627)); - quadtree.put(new DegreePosition(49.80192, 8.624780000000001)); - quadtree.put(new DegreePosition(49.79887, 8.622520000000002)); - quadtree.put(new DegreePosition(49.797380000000004, 8.62151)); - quadtree.put(new DegreePosition(49.796110000000006, 8.620750000000001)); - quadtree.put(new DegreePosition(49.79467, 8.62005)); - quadtree.put(new DegreePosition(49.79345000000001, 8.619520000000001)); - quadtree.put(new DegreePosition(49.792060000000006, 8.61903)); - quadtree.put(new DegreePosition(49.79064, 8.61869)); - quadtree.put(new DegreePosition(49.78909, 8.618390000000002)); - quadtree.put(new DegreePosition(49.78412, 8.61762)); - quadtree.put(new DegreePosition(49.78295000000001, 8.61738)); - quadtree.put(new DegreePosition(49.78119, 8.61692)); - quadtree.put(new DegreePosition(49.77975000000001, 8.616380000000001)); - quadtree.put(new DegreePosition(49.778780000000005, 8.61593)); - quadtree.put(new DegreePosition(49.777640000000005, 8.61528)); - quadtree.put(new DegreePosition(49.77610000000001, 8.61415)); - quadtree.put(new DegreePosition(49.77506, 8.613190000000001)); - quadtree.put(new DegreePosition(49.77357000000001, 8.611600000000001)); - quadtree.put(new DegreePosition(49.77299000000001, 8.61087)); - quadtree.put(new DegreePosition(49.770830000000004, 8.607850000000001)); - quadtree.put(new DegreePosition(49.76859, 8.604610000000001)); - quadtree.put(new DegreePosition(49.768170000000005, 8.60405)); - quadtree.put(new DegreePosition(49.76608, 8.60152)); - quadtree.put(new DegreePosition(49.764790000000005, 8.60018)); - quadtree.put(new DegreePosition(49.762150000000005, 8.59793)); - quadtree.put(new DegreePosition(49.76151, 8.597430000000001)); - quadtree.put(new DegreePosition(49.76024, 8.59665)); - quadtree.put(new DegreePosition(49.757780000000004, 8.59553)); - quadtree.put(new DegreePosition(49.756260000000005, 8.59491)); - quadtree.put(new DegreePosition(49.75267, 8.59369)); - quadtree.put(new DegreePosition(49.75119, 8.593290000000001)); - quadtree.put(new DegreePosition(49.74869, 8.59272)); - quadtree.put(new DegreePosition(49.745580000000004, 8.592160000000002)); - quadtree.put(new DegreePosition(49.742180000000005, 8.59171)); - quadtree.put(new DegreePosition(49.739290000000004, 8.59154)); - quadtree.put(new DegreePosition(49.735220000000005, 8.591550000000002)); - quadtree.put(new DegreePosition(49.73221, 8.59176)); - quadtree.put(new DegreePosition(49.72905, 8.59223)); - quadtree.put(new DegreePosition(49.72579, 8.592830000000001)); - quadtree.put(new DegreePosition(49.722390000000004, 8.59373)); - quadtree.put(new DegreePosition(49.715450000000004, 8.59572)); - quadtree.put(new DegreePosition(49.705760000000005, 8.599260000000001)); - quadtree.put(new DegreePosition(49.6989, 8.602160000000001)); - quadtree.put(new DegreePosition(49.698060000000005, 8.602400000000001)); - quadtree.put(new DegreePosition(49.695820000000005, 8.602820000000001)); - quadtree.put(new DegreePosition(49.693780000000004, 8.602960000000001)); - quadtree.put(new DegreePosition(49.69301, 8.602960000000001)); - quadtree.put(new DegreePosition(49.6916, 8.602860000000002)); - quadtree.put(new DegreePosition(49.69035, 8.602640000000001)); - quadtree.put(new DegreePosition(49.689150000000005, 8.60234)); - quadtree.put(new DegreePosition(49.68645, 8.60135)); - quadtree.put(new DegreePosition(49.68348, 8.600140000000001)); - quadtree.put(new DegreePosition(49.68186000000001, 8.599680000000001)); - quadtree.put(new DegreePosition(49.67985, 8.599250000000001)); - quadtree.put(new DegreePosition(49.678070000000005, 8.59914)); - quadtree.put(new DegreePosition(49.676970000000004, 8.599160000000001)); - quadtree.put(new DegreePosition(49.67475, 8.59946)); - quadtree.put(new DegreePosition(49.672610000000006, 8.60003)); - quadtree.put(new DegreePosition(49.669450000000005, 8.6013)); - quadtree.put(new DegreePosition(49.667790000000004, 8.60214)); - quadtree.put(new DegreePosition(49.6655, 8.60356)); - quadtree.put(new DegreePosition(49.66145, 8.60621)); - quadtree.put(new DegreePosition(49.65959, 8.607330000000001)); - quadtree.put(new DegreePosition(49.657700000000006, 8.6083)); - quadtree.put(new DegreePosition(49.65603, 8.60891)); - quadtree.put(new DegreePosition(49.65431, 8.609340000000001)); - quadtree.put(new DegreePosition(49.65194, 8.60959)); - quadtree.put(new DegreePosition(49.649770000000004, 8.609620000000001)); - quadtree.put(new DegreePosition(49.64312, 8.609250000000001)); - quadtree.put(new DegreePosition(49.64190000000001, 8.60926)); - quadtree.put(new DegreePosition(49.64029000000001, 8.609380000000002)); - quadtree.put(new DegreePosition(49.63906, 8.609530000000001)); - quadtree.put(new DegreePosition(49.63758000000001, 8.60983)); - quadtree.put(new DegreePosition(49.63456000000001, 8.610570000000001)); - quadtree.put(new DegreePosition(49.632870000000004, 8.61125)); - quadtree.put(new DegreePosition(49.630630000000004, 8.612340000000001)); - quadtree.put(new DegreePosition(49.62894000000001, 8.61344)); - quadtree.put(new DegreePosition(49.627930000000006, 8.61416)); - quadtree.put(new DegreePosition(49.62348, 8.61804)); - quadtree.put(new DegreePosition(49.622220000000006, 8.61931)); - quadtree.put(new DegreePosition(49.618030000000005, 8.623240000000001)); - quadtree.put(new DegreePosition(49.6152, 8.6256)); - quadtree.put(new DegreePosition(49.61211, 8.627540000000002)); - quadtree.put(new DegreePosition(49.61057, 8.62833)); - quadtree.put(new DegreePosition(49.60898, 8.62899)); - quadtree.put(new DegreePosition(49.607150000000004, 8.629620000000001)); - quadtree.put(new DegreePosition(49.604940000000006, 8.630170000000001)); - quadtree.put(new DegreePosition(49.603770000000004, 8.63035)); - quadtree.put(new DegreePosition(49.60065, 8.630640000000001)); - quadtree.put(new DegreePosition(49.59897, 8.63086)); - quadtree.put(new DegreePosition(49.59581000000001, 8.63113)); - quadtree.put(new DegreePosition(49.59308000000001, 8.63165)); - quadtree.put(new DegreePosition(49.59147, 8.63212)); - quadtree.put(new DegreePosition(49.58559, 8.634110000000002)); - quadtree.put(new DegreePosition(49.58408000000001, 8.634540000000001)); - quadtree.put(new DegreePosition(49.582060000000006, 8.635010000000001)); - quadtree.put(new DegreePosition(49.580670000000005, 8.635200000000001)); - quadtree.put(new DegreePosition(49.57885, 8.635330000000002)); - quadtree.put(new DegreePosition(49.57715, 8.63531)); - quadtree.put(new DegreePosition(49.57417, 8.6349)); - quadtree.put(new DegreePosition(49.572190000000006, 8.63455)); - quadtree.put(new DegreePosition(49.570730000000005, 8.63413)); - quadtree.put(new DegreePosition(49.568430000000006, 8.6333)); - quadtree.put(new DegreePosition(49.565090000000005, 8.63171)); - quadtree.put(new DegreePosition(49.560050000000004, 8.62922)); - quadtree.put(new DegreePosition(49.55922, 8.62894)); - quadtree.put(new DegreePosition(49.55603000000001, 8.628010000000002)); - quadtree.put(new DegreePosition(49.55425, 8.62767)); - quadtree.put(new DegreePosition(49.55111, 8.62743)); - quadtree.put(new DegreePosition(49.548930000000006, 8.62748)); - quadtree.put(new DegreePosition(49.548120000000004, 8.62757)); - quadtree.put(new DegreePosition(49.54666, 8.62784)); - quadtree.put(new DegreePosition(49.54466000000001, 8.62827)); - quadtree.put(new DegreePosition(49.54215000000001, 8.62898)); - quadtree.put(new DegreePosition(49.539440000000006, 8.62991)); - quadtree.put(new DegreePosition(49.537850000000006, 8.63052)); - quadtree.put(new DegreePosition(49.52872000000001, 8.63442)); - quadtree.put(new DegreePosition(49.527300000000004, 8.63508)); - quadtree.put(new DegreePosition(49.52526, 8.635860000000001)); - quadtree.put(new DegreePosition(49.52337000000001, 8.636510000000001)); - quadtree.put(new DegreePosition(49.52058, 8.637360000000001)); - quadtree.put(new DegreePosition(49.518550000000005, 8.637910000000002)); - quadtree.put(new DegreePosition(49.51503, 8.638770000000001)); - quadtree.put(new DegreePosition(49.51098, 8.639330000000001)); - quadtree.put(new DegreePosition(49.50845, 8.63959)); - quadtree.put(new DegreePosition(49.50417, 8.639740000000002)); - quadtree.put(new DegreePosition(49.499810000000004, 8.63963)); - quadtree.put(new DegreePosition(49.49546, 8.63912)); - quadtree.put(new DegreePosition(49.49306000000001, 8.638910000000001)); - quadtree.put(new DegreePosition(49.490320000000004, 8.638760000000001)); - quadtree.put(new DegreePosition(49.48669, 8.63865)); - quadtree.put(new DegreePosition(49.484480000000005, 8.638760000000001)); - quadtree.put(new DegreePosition(49.48073, 8.639330000000001)); - quadtree.put(new DegreePosition(49.4776, 8.640130000000001)); - quadtree.put(new DegreePosition(49.476310000000005, 8.64052)); - quadtree.put(new DegreePosition(49.468500000000006, 8.64342)); - quadtree.put(new DegreePosition(49.464470000000006, 8.64483)); - quadtree.put(new DegreePosition(49.461290000000005, 8.64577)); - quadtree.put(new DegreePosition(49.458690000000004, 8.64629)); - quadtree.put(new DegreePosition(49.457530000000006, 8.646460000000001)); - quadtree.put(new DegreePosition(49.455380000000005, 8.64666)); - quadtree.put(new DegreePosition(49.453050000000005, 8.64668)); - quadtree.put(new DegreePosition(49.451750000000004, 8.64661)); - quadtree.put(new DegreePosition(49.450430000000004, 8.64647)); - quadtree.put(new DegreePosition(49.44711, 8.64578)); - quadtree.put(new DegreePosition(49.445350000000005, 8.6453)); - quadtree.put(new DegreePosition(49.44398, 8.64478)); - quadtree.put(new DegreePosition(49.44091, 8.64338)); - quadtree.put(new DegreePosition(49.439840000000004, 8.64282)); - quadtree.put(new DegreePosition(49.438340000000004, 8.64193)); - quadtree.put(new DegreePosition(49.43139000000001, 8.63724)); - quadtree.put(new DegreePosition(49.42933000000001, 8.636080000000002)); - quadtree.put(new DegreePosition(49.427890000000005, 8.63537)); - quadtree.put(new DegreePosition(49.426460000000006, 8.634820000000001)); - quadtree.put(new DegreePosition(49.42436000000001, 8.634160000000001)); - quadtree.put(new DegreePosition(49.422200000000004, 8.63371)); - quadtree.put(new DegreePosition(49.42033000000001, 8.633500000000002)); - quadtree.put(new DegreePosition(49.41946, 8.63347)); - quadtree.put(new DegreePosition(49.41798000000001, 8.63348)); - quadtree.put(new DegreePosition(49.415710000000004, 8.633700000000001)); - quadtree.put(new DegreePosition(49.41463, 8.6339)); - quadtree.put(new DegreePosition(49.412670000000006, 8.63437)); - quadtree.put(new DegreePosition(49.411120000000004, 8.6349)); - quadtree.put(new DegreePosition(49.40739000000001, 8.636330000000001)); - quadtree.put(new DegreePosition(49.40572, 8.636800000000001)); - quadtree.put(new DegreePosition(49.39164, 8.63865)); - quadtree.put(new DegreePosition(49.39021, 8.63879)); - quadtree.put(new DegreePosition(49.38855, 8.638720000000001)); - quadtree.put(new DegreePosition(49.38721, 8.638480000000001)); - quadtree.put(new DegreePosition(49.38656, 8.638290000000001)); - quadtree.put(new DegreePosition(49.38440000000001, 8.63746)); - quadtree.put(new DegreePosition(49.37805, 8.63387)); - quadtree.put(new DegreePosition(49.376940000000005, 8.63334)); - quadtree.put(new DegreePosition(49.376000000000005, 8.63297)); - quadtree.put(new DegreePosition(49.37500000000001, 8.63269)); - quadtree.put(new DegreePosition(49.373780000000004, 8.632480000000001)); - quadtree.put(new DegreePosition(49.36988, 8.63222)); - quadtree.put(new DegreePosition(49.36872, 8.632190000000001)); - quadtree.put(new DegreePosition(49.364360000000005, 8.631910000000001)); - quadtree.put(new DegreePosition(49.35228000000001, 8.63127)); - quadtree.put(new DegreePosition(49.34911, 8.631160000000001)); - quadtree.put(new DegreePosition(49.33944, 8.63067)); - quadtree.put(new DegreePosition(49.31497, 8.62917)); - quadtree.put(new DegreePosition(49.312200000000004, 8.62892)); - quadtree.put(new DegreePosition(49.31073000000001, 8.628670000000001)); - quadtree.put(new DegreePosition(49.303380000000004, 8.626940000000001)); - quadtree.put(new DegreePosition(49.30293, 8.62654)); - quadtree.put(new DegreePosition(49.30285000000001, 8.62644)); - quadtree.put(new DegreePosition(49.302690000000005, 8.62608)); - quadtree.put(new DegreePosition(49.30268, 8.62584)); - quadtree.put(new DegreePosition(49.30299, 8.62268)); - quadtree.put(new DegreePosition(49.30303000000001, 8.622010000000001)); - quadtree.put(new DegreePosition(49.30299, 8.621730000000001)); - quadtree.put(new DegreePosition(49.30293, 8.6216)); - quadtree.put(new DegreePosition(49.30274000000001, 8.62147)); - quadtree.put(new DegreePosition(49.30238000000001, 8.62139)); - quadtree.put(new DegreePosition(49.302290000000006, 8.621310000000001)); - quadtree.put(new DegreePosition(49.301950000000005, 8.62127)); - quadtree.put(new DegreePosition(49.30187, 8.62279)); - quadtree.put(new DegreePosition(49.30172, 8.62456)); - quadtree.put(new DegreePosition(49.30134, 8.62697)); - quadtree.put(new DegreePosition(49.30116, 8.627690000000001)); - quadtree.put(new DegreePosition(49.30053, 8.629800000000001)); - quadtree.put(new DegreePosition(49.299820000000004, 8.63142)); - quadtree.put(new DegreePosition(49.29916, 8.6327)); - quadtree.put(new DegreePosition(49.299530000000004, 8.63279)); - quadtree.put(new DegreePosition(49.30006, 8.63272)); - quadtree.put(new DegreePosition(49.30068000000001, 8.63277)); - quadtree.put(new DegreePosition(49.30082, 8.63283)); - quadtree.put(new DegreePosition(49.301050000000004, 8.633040000000001)); - quadtree.put(new DegreePosition(49.300340000000006, 8.634780000000001)); - quadtree.put(new DegreePosition(49.29995, 8.63593)); - quadtree.put(new DegreePosition(49.299690000000005, 8.63723)); - quadtree.put(new DegreePosition(49.299600000000005, 8.638200000000001)); - quadtree.put(new DegreePosition(49.29963, 8.63973)); - quadtree.put(new DegreePosition(49.299710000000005, 8.64104)); - quadtree.put(new DegreePosition(49.29831, 8.643080000000001)); - quadtree.put(new DegreePosition(49.29796, 8.64334)); - quadtree.put(new DegreePosition(49.297920000000005, 8.643450000000001)); - quadtree.put(new DegreePosition(49.297920000000005, 8.643590000000001)); - quadtree.put(new DegreePosition(49.29798, 8.64389)); - quadtree.put(new DegreePosition(49.299420000000005, 8.646180000000001)); - quadtree.put(new DegreePosition(49.299580000000006, 8.64652)); - quadtree.put(new DegreePosition(49.29955, 8.646640000000001)); - quadtree.put(new DegreePosition(49.29957, 8.64677)); - quadtree.put(new DegreePosition(49.299710000000005, 8.64681)); - quadtree.put(new DegreePosition(49.29977, 8.646730000000002)); - quadtree.put(new DegreePosition(49.299780000000005, 8.646640000000001)); - quadtree.put(new DegreePosition(49.299690000000005, 8.64648)); - quadtree.put(new DegreePosition(49.2997, 8.64638)); - quadtree.put(new DegreePosition(49.29992000000001, 8.64586)); - quadtree.put(new DegreePosition(49.29995, 8.64563)); - quadtree.put(new DegreePosition(49.300790000000006, 8.644)); - quadtree.put(new DegreePosition(49.301120000000004, 8.643650000000001)); - quadtree.put(new DegreePosition(49.301390000000005, 8.64348)); - quadtree.put(new DegreePosition(49.30283000000001, 8.642980000000001)); - quadtree.put(new DegreePosition(49.30346, 8.642560000000001)); - quadtree.put(new DegreePosition(49.30378, 8.64241)); - quadtree.put(new DegreePosition(49.309740000000005, 8.64105)); - quadtree.put(new DegreePosition(49.309760000000004, 8.64207)); - quadtree.put(new DegreePosition(49.309140000000006, 8.64212)); - quadtree.put(new DegreePosition(49.309140000000006, 8.643880000000001)); - quadtree.put(new DegreePosition(49.30917, 8.64403)); - quadtree.put(new DegreePosition(49.30923000000001, 8.644110000000001)); - quadtree.put(new DegreePosition(49.30937, 8.644110000000001)); - - Position p1 = new DegreePosition(50.47498691278631, 8.701171875); - Position p2 = new DegreePosition(50.47149085139956, 8.7066650390625); - Position p3 = new DegreePosition(50.47848271564207, 8.7066650390625); - double maxDistance = 0.06242236766906711; Position p1Nearest = quadtree.get(p1, maxDistance); Position p2Nearest = quadtree.get(p2, maxDistance); @@ -1207,4 +1231,141 @@ public class QuadTreeTest { assertNotNull(p3Nearest); } + @Test + public void testNearest() { + double maxDistance = 0.06242236766906711; + Position p1Nearest = quadtree.get(p1, maxDistance); + Position p2Nearest = quadtree.get(p2, maxDistance); + Position p3Nearest = quadtree.get(p3, maxDistance); + assertSame(getNearestByApproximateDistance(p1), p1Nearest); + assertSame(getNearestByApproximateDistance(p2), p2Nearest); + assertSame(getNearestByApproximateDistance(p3), p3Nearest); + } + + private Position getNearestByApproximateDistance(Position pos) { + double minDistance = Double.MAX_VALUE; + Position nearestByDistance = null; + for (final Position p : quadtree.get(new BoundsImpl(new DegreePosition(-90, -180), new DegreePosition(90, 180)))) { // get all + if (QuadTree.getLatLngDistance(p, pos) < minDistance) { + nearestByDistance = p; + minDistance = QuadTree.getLatLngDistance(p, pos); + } + } + return nearestByDistance; + } + + @Test + public void testTooFarAwayProducesEmptyResults() { + double maxDistance = 0.06242236766906711; + Position p1Nearest = quadtree.get(new DegreePosition(0, 0), maxDistance); + assertNull(p1Nearest); + } + + @Test + public void measureLookupNearestPerformance() { + long start = System.currentTimeMillis(); + final int ITERATIONS = 100000; + for (int i=0; i positions = new ArrayList<>(); + for (int i=0; i extends Node { + public NodeWithPublicGetDistance(Bounds bounds, int maxItems) { + super(bounds, maxItems); + } + + @Override + public double getDistance(Position point) { + return super.getDistance(point); + } + } + + @Test + public void testNodeDistance() { + /* + {SW: (50.625,-5.625), NE: (53.4375,0.0)}: 15 items in node, 0 child nodes + (51.0,-6.0) + */ + NodeWithPublicGetDistance node = new NodeWithPublicGetDistance<>(new BoundsImpl(new DegreePosition(50.625,-5.625), new DegreePosition(53.4375,0.0)), + /* maxItems */ 20); + Position p = new DegreePosition(51.0, -6.0); + // lat is in bounds; lon is nearby, -5.625+6.0 should be the distance + final double expectedDistance = -5.625 + 6.0; + assertEquals(expectedDistance, node.getDistance(p), 0.0001); + } + + @AfterClass + public static void writeMeasurements() throws IOException { + performanceReport.write(); + } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/measurements/Measurement.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/measurements/Measurement.java index e9ed61c0ab6..741067764e8 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/measurements/Measurement.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/measurements/Measurement.java @@ -1,5 +1,13 @@ package com.sap.sailing.domain.test.measurements; +/** + * Create an instance of this class and {@link MeasurementCase#addMeasurement(Measurement) add it} to a + * measurement case. The final reporting is then done by invoking {@link MeasurementXMLFile#write()} on + * the measurement file created before. + * + * @author Axel Uhl (D043530) + * + */ public class Measurement { private final String name; private final double value; @@ -10,11 +18,11 @@ public class Measurement { this.value = value; } - public String getName() { + String getName() { return name; } - public double getValue() { + double getValue() { return value; } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/measurements/MeasurementCase.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/measurements/MeasurementCase.java index 0bd2a97b0a4..6e8b7577c22 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/measurements/MeasurementCase.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/measurements/MeasurementCase.java @@ -3,17 +3,24 @@ package com.sap.sailing.domain.test.measurements; import java.util.HashSet; import java.util.Set; +/** + * Obtain an instance of this class by invoking {@link MeasurementXMLFile#addCase(String)}, then add + * measurements using the {@link #addMeasurement(Measurement)} method. + * + * @author Axel Uhl (D043530) + * + */ public class MeasurementCase { private final String name; private final Set measurements; - public MeasurementCase(String name) { + MeasurementCase(String name) { super(); this.name = name; measurements = new HashSet<>(); } - public String getName() { + String getName() { return name; } @@ -21,7 +28,7 @@ public class MeasurementCase { measurements.add(measurement); } - public Iterable getMeasurements() { + Iterable getMeasurements() { return measurements; } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/measurements/MeasurementXMLFile.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/measurements/MeasurementXMLFile.java index f192eb1c1b0..240b021f9f2 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/measurements/MeasurementXMLFile.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/measurements/MeasurementXMLFile.java @@ -15,7 +15,15 @@ import com.sap.sse.common.Util; * <measurement> tags embedded which list named values for use by the Hudson/Jenkins Measurements Plot plug-in. * The output is written to the bin/surefire-reports/ directory by the {@link #write()} method, but only if * a bin/ directory exists as subdirectory of the current working directory. The surefire-reports - * subdirectory will be created if it doesn't exist. + * subdirectory will be created if it doesn't exist.

+ * + * Use this class as in the following example: + *

+ *       MeasurementXMLFile performanceReport = new MeasurementXMLFile(this.getClass());
+ *       MeasurementCase performanceReportCase = performanceReport.addCase(getClass().getSimpleName());
+ *       performanceReportCase.addMeasurement(new Measurement("This is a measurement name", 12345); // 12345 is the value to be recorded
+ *       performanceReport.write();
+ * 
* * @author Axel Uhl (D043530) * diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithFixedRank.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithFixedRank.java index cebb4552807..dadc21866c5 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithFixedRank.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithFixedRank.java @@ -81,6 +81,11 @@ public class MockedTrackedRaceWithFixedRank extends MockedTrackedRace { public Boat getBoatOfCompetitorById(Serializable competitorID) { return null; } + + @Override + public byte[] getCompetitorMD5() { + return null; + } } @Override diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithFixedRankAndManyCompetitors.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithFixedRankAndManyCompetitors.java index 2eacc2264bd..02ac83a163d 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithFixedRankAndManyCompetitors.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithFixedRankAndManyCompetitors.java @@ -55,6 +55,10 @@ public class MockedTrackedRaceWithFixedRankAndManyCompetitors extends MockedTrac public Boat getBoatOfCompetitorById(Serializable competitorID) { return null; } + @Override + public byte[] getCompetitorMD5() { + return null; + } }; } diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java index 50c376d419c..dc74e7f3e35 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java @@ -409,7 +409,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements addListenersForStoredDataAndStartController(receivers); } - private URI checkForCachedStoredData(URI storedURI){ + private URI checkForCachedStoredData(URI storedURI) { final String CACHE_DIR_PROPERTY = "tractrac.mtb.cache.dir"; if (System.getProperty(CACHE_DIR_PROPERTY) != null) { final String directory = System.getProperty(CACHE_DIR_PROPERTY); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceDefinition.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceDefinition.java index b55928727f9..144d6c2ddd3 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceDefinition.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RaceDefinition.java @@ -2,6 +2,7 @@ package com.sap.sailing.domain.base; import java.io.Serializable; +import com.sap.sailing.domain.common.RaceCompetitorIdsAsStringWithMD5Hash; import com.sap.sse.common.Named; import com.sap.sse.common.WithID; @@ -31,4 +32,11 @@ public interface RaceDefinition extends Named, WithID { */ Boat getBoatOfCompetitorById(Serializable competitorID); + /** + * The MD5 hash as produced by + * {@link RaceCompetitorIdsAsStringWithMD5Hash#getMd5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID()} + * for this race's competitor set. + */ + byte[] getCompetitorMD5(); + } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java index a60d5e91926..52219d1545c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java @@ -257,47 +257,26 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain double radiusCalculationFactor = 10.0; Placemark startBest = null; Placemark finishBest = null; + Position startPosition = null; // Get start postition - Iterator startMarks = race.getRace().getCourse().getFirstWaypoint().getMarks().iterator(); - GPSFix startMarkFix = startMarks.hasNext() ? race.getOrCreateTrack(startMarks.next()).getLastRawFix() : null; - Position startPosition = startMarkFix != null ? startMarkFix.getPosition() : null; - if (startPosition != null) { - try { - // Get distance to nearest placemark and calculate the search radius - Placemark startNearest = ReverseGeocoder.INSTANCE.getPlacemarkNearest(startPosition); - if (startNearest != null) { - Distance startNearestDistance = startNearest.distanceFrom(startPosition); - double startRadius = startNearestDistance.getKilometers() * radiusCalculationFactor; - - // Get the estimated best start place - startBest = ReverseGeocoder.INSTANCE.getPlacemarkLast(startPosition, startRadius, - new Placemark.ByPopulationDistanceRatio(startPosition)); - } - } catch (IOException e) { - logger.throwing(TrackedRaceImpl.class.getName(), "getPlaceOrder()", e); - } catch (org.json.simple.parser.ParseException e) { - logger.throwing(TrackedRaceImpl.class.getName(), "getPlaceOrder()", e); - } - } - - // Get finish position - Iterator finishMarks = race.getRace().getCourse().getFirstWaypoint().getMarks().iterator(); - GPSFix finishMarkFix = finishMarks.hasNext() ? race.getOrCreateTrack(finishMarks.next()).getLastRawFix() : null; - Position finishPosition = finishMarkFix != null ? finishMarkFix.getPosition() : null; - if (startPosition != null && finishPosition != null) { - if (startPosition.getDistance(finishPosition).getKilometers() <= ReverseGeocoder.POSITION_CACHE_DISTANCE_LIMIT_IN_KM) { - finishBest = startBest; - } else { + final Waypoint firstWaypoint = race.getRace().getCourse().getFirstWaypoint(); + if (firstWaypoint != null) { + Iterator startMarks = firstWaypoint.getMarks().iterator(); + GPSFix startMarkFix = startMarks.hasNext() ? race.getOrCreateTrack(startMarks.next()).getLastRawFix() : null; + startPosition = startMarkFix != null ? startMarkFix.getPosition() : null; + if (startPosition != null) { try { // Get distance to nearest placemark and calculate the search radius - Placemark finishNearest = ReverseGeocoder.INSTANCE.getPlacemarkNearest(finishPosition); - Distance finishNearestDistance = finishNearest.distanceFrom(finishPosition); - double finishRadius = finishNearestDistance.getKilometers() * radiusCalculationFactor; - - // Get the estimated best finish place - finishBest = ReverseGeocoder.INSTANCE.getPlacemarkLast(finishPosition, finishRadius, - new Placemark.ByPopulationDistanceRatio(finishPosition)); + Placemark startNearest = ReverseGeocoder.INSTANCE.getPlacemarkNearest(startPosition); + if (startNearest != null) { + Distance startNearestDistance = startNearest.distanceFrom(startPosition); + double startRadius = startNearestDistance.getKilometers() * radiusCalculationFactor; + + // Get the estimated best start place + startBest = ReverseGeocoder.INSTANCE.getPlacemarkLast(startPosition, startRadius, + new Placemark.ByPopulationDistanceRatio(startPosition)); + } } catch (IOException e) { logger.throwing(TrackedRaceImpl.class.getName(), "getPlaceOrder()", e); } catch (org.json.simple.parser.ParseException e) { @@ -305,6 +284,34 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain } } } + + // Get finish position + final Waypoint lastWaypoint = race.getRace().getCourse().getLastWaypoint(); + if (lastWaypoint != null) { + Iterator finishMarks = firstWaypoint.getMarks().iterator(); + GPSFix finishMarkFix = finishMarks.hasNext() ? race.getOrCreateTrack(finishMarks.next()).getLastRawFix() : null; + Position finishPosition = finishMarkFix != null ? finishMarkFix.getPosition() : null; + if (startPosition != null && finishPosition != null) { + if (startPosition.getDistance(finishPosition).getKilometers() <= ReverseGeocoder.POSITION_CACHE_DISTANCE_LIMIT_IN_KM) { + finishBest = startBest; + } else { + try { + // Get distance to nearest placemark and calculate the search radius + Placemark finishNearest = ReverseGeocoder.INSTANCE.getPlacemarkNearest(finishPosition); + Distance finishNearestDistance = finishNearest.distanceFrom(finishPosition); + double finishRadius = finishNearestDistance.getKilometers() * radiusCalculationFactor; + + // Get the estimated best finish place + finishBest = ReverseGeocoder.INSTANCE.getPlacemarkLast(finishPosition, finishRadius, + new Placemark.ByPopulationDistanceRatio(finishPosition)); + } catch (IOException e) { + logger.throwing(TrackedRaceImpl.class.getName(), "getPlaceOrder()", e); + } catch (org.json.simple.parser.ParseException e) { + logger.throwing(TrackedRaceImpl.class.getName(), "getPlaceOrder()", e); + } + } + } + } Util.Pair placemarks = new Util.Pair(startBest, finishBest); return placemarks; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceDefinitionImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceDefinitionImpl.java index c62df996b41..9545afb6742 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceDefinitionImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceDefinitionImpl.java @@ -1,6 +1,8 @@ package com.sap.sailing.domain.base.impl; import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -15,6 +17,7 @@ import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.RaceDefinition; +import com.sap.sailing.domain.common.RaceCompetitorIdsAsStringWithMD5Hash; import com.sap.sse.common.impl.NamedImpl; public class RaceDefinitionImpl extends NamedImpl implements RaceDefinition { @@ -27,6 +30,7 @@ public class RaceDefinitionImpl extends NamedImpl implements RaceDefinition { private final Map competitorBoats; private final BoatClass boatClass; private final Serializable id; + private final RaceCompetitorIdsAsStringWithMD5Hash raceCompetitorsMD5Hash; public RaceDefinitionImpl(String name, Course course, BoatClass boatClass, Iterable competitors) { this(name, course, boatClass, competitors, Collections.emptyMap()); @@ -49,9 +53,11 @@ public class RaceDefinitionImpl extends NamedImpl implements RaceDefinition { this.competitors = new HashSet<>(); this.competitorsById = new LinkedHashMap<>(); this.competitorBoats = new HashMap<>(); + final Set idsOfCompetitorsAsString = new HashSet<>(); for (Competitor competitor : competitors) { Competitor competitorWithEqualID = competitorsById.put(competitor.getId(), competitor); this.competitors.add(competitor); + idsOfCompetitorsAsString.add(competitor.getId().toString()); if (competitorWithEqualID != null && competitorWithEqualID != competitor) { throw new IllegalArgumentException("Two distinct competitors with equal ID "+competitor.getId()+" are not allowed within the single race "+name); } @@ -65,6 +71,11 @@ public class RaceDefinitionImpl extends NamedImpl implements RaceDefinition { " which is not part of race "+getName()+"'s set of competitors"); } } + try { + raceCompetitorsMD5Hash = new RaceCompetitorIdsAsStringWithMD5Hash(idsOfCompetitorsAsString); + } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { + throw new RuntimeException("Internal error: issue with UTF8 or MD5 for encoding competitor IDs as MD5 hash", e); + } this.boatClass = boatClass; this.id = id; } @@ -78,11 +89,16 @@ public class RaceDefinitionImpl extends NamedImpl implements RaceDefinition { public Course getCourse() { return course; } - + @Override public Iterable getCompetitors() { return Collections.unmodifiableSet(competitors); } + + @Override + public byte[] getCompetitorMD5() { + return raceCompetitorsMD5Hash.getMd5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID(); + } @Override public Competitor getCompetitorById(Serializable competitorID) { diff --git a/java/com.sap.sailing.geocoding/src/com/sap/sailing/geocoding/impl/ReverseGeocoderImpl.java b/java/com.sap.sailing.geocoding/src/com/sap/sailing/geocoding/impl/ReverseGeocoderImpl.java index 577e4d1fe9a..bb91b4d3cf1 100644 --- a/java/com.sap.sailing.geocoding/src/com/sap/sailing/geocoding/impl/ReverseGeocoderImpl.java +++ b/java/com.sap.sailing.geocoding/src/com/sap/sailing/geocoding/impl/ReverseGeocoderImpl.java @@ -217,7 +217,7 @@ public class ReverseGeocoderImpl implements ReverseGeocoder { private void updateCachedPlacemarks(Position cachedPoint, Double newRadius, List newPlacemarks) { if (cachedPoint != null) { synchronized (cache) { - cache.replace(cachedPoint, new Util.Triple>(cachedPoint, newRadius, newPlacemarks)); + cache.put(cachedPoint, new Util.Triple>(cachedPoint, newRadius, newPlacemarks)); } } } diff --git a/java/com.sap.sailing.gwt.ui/.settings/org.eclipse.core.resources.prefs b/java/com.sap.sailing.gwt.ui/.settings/org.eclipse.core.resources.prefs index c6979559171..fef4a78a7dc 100755 --- a/java/com.sap.sailing.gwt.ui/.settings/org.eclipse.core.resources.prefs +++ b/java/com.sap.sailing.gwt.ui/.settings/org.eclipse.core.resources.prefs @@ -3,11 +3,21 @@ encoding//src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages.prop encoding//src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_de.properties=UTF-8 encoding//src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_ru.properties=UTF-8 encoding//src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_zh.properties=UTF-8 +encoding//src/main/java/com/sap/sailing/gwt/home/mobile/partials/sectionHeader/SectionHeaderContent.java=utf-8 +encoding//src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java=utf-8 encoding//src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java=utf-8 +encoding//src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java=utf-8 encoding//src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java=utf-8 +encoding//src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java=utf-8 encoding//src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties=UTF-8 encoding//src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties=UTF-8 encoding//src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties=UTF-8 encoding//src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties=UTF-8 +encoding//src/main/java/com/sap/sailing/gwt/ui/client/media/MediaPlayerManagerComponent.java=utf-8 encoding//src/main/java/com/sap/sailing/gwt/ui/datamining/presentation/AbstractResultsPresenter.java=utf-8 +encoding//src/main/java/com/sap/sailing/gwt/ui/datamining/presentation/PlainResultsPresenter.java=utf-8 encoding//src/main/java/com/sap/sailing/gwt/ui/leaderboard/CompetitorFilterPanel.java=utf-8 +encoding//src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardEntryPoint.java=utf-8 +encoding//src/main/java/com/sap/sailing/gwt/ui/leaderboard/MultiLeaderboardPanel.java=utf-8 +encoding//src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java=utf-8 +encoding//src/main/java/com/sap/sailing/gwt/ui/spectator/LeaderboardGroupPanel.java=utf-8 diff --git a/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF b/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF index 58fd71023f7..526bf3509b7 100644 --- a/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.gwt.ui/META-INF/MANIFEST.MF @@ -71,6 +71,15 @@ TrackLifecycle: true Export-Package: com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.confidence.impl, com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.impl, com.google.gwt.user.client.rpc.core.com.sap.sailing.domain.common.tracking.impl, + com.sap.sailing.gwt.dispatch.client, + com.sap.sailing.gwt.dispatch.client.batching, + com.sap.sailing.gwt.dispatch.client.caching, + com.sap.sailing.gwt.dispatch.client.exceptions, + com.sap.sailing.gwt.dispatch.client.impl, + com.sap.sailing.gwt.dispatch.client.rpcimpl, + com.sap.sailing.gwt.home.communication, + com.sap.sailing.gwt.home.server, + com.sap.sailing.gwt.server, com.sap.sailing.gwt.ui.actions, com.sap.sailing.gwt.ui.client, com.sap.sailing.gwt.ui.client.shared.charts, diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/dispatch/client/impl/DispatchSystemImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/dispatch/client/impl/DispatchSystemImpl.java index 464bf283c52..b90d0b900f5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/dispatch/client/impl/DispatchSystemImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/dispatch/client/impl/DispatchSystemImpl.java @@ -15,18 +15,19 @@ import com.sap.sailing.gwt.dispatch.client.rpcimpl.SimpleDispatch; public class DispatchSystemImpl implements DispatchSystem { - private final SimpleDispatch simpleDispatch = new SimpleDispatch(null); + private final SimpleDispatch simpleDispatch; private final DispatchAsync dispatch; - - public DispatchSystemImpl() { - this(false); + + public DispatchSystemImpl(String dispatchRPCPath) { + this(dispatchRPCPath, false); } - public DispatchSystemImpl(boolean processResultsScheduled) { + public DispatchSystemImpl(String dispatchRPCPath, boolean processResultsScheduled) { + simpleDispatch = new SimpleDispatch(dispatchRPCPath); dispatch = new CachingDispatch(new AutomaticBatchingDispatch( simpleDispatch, processResultsScheduled)); } - + @Override public > void execute(final A action, final AsyncCallback callback) { // TODO: client side execution time logging diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/dispatch/client/rpcimpl/SimpleDispatch.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/dispatch/client/rpcimpl/SimpleDispatch.java index 63b564c4e04..49ab4df3730 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/dispatch/client/rpcimpl/SimpleDispatch.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/dispatch/client/rpcimpl/SimpleDispatch.java @@ -9,8 +9,6 @@ import com.sap.sailing.gwt.dispatch.client.DispatchAsync; import com.sap.sailing.gwt.dispatch.client.DispatchContext; import com.sap.sailing.gwt.dispatch.client.Result; import com.sap.sailing.gwt.dispatch.client.ResultWrapper; -import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants; -import com.sap.sailing.gwt.ui.client.SailingClientFactory; public class SimpleDispatch implements DispatchAsync { @@ -18,8 +16,8 @@ public class SimpleDispatch implements DispatchAsyn private long clientServerOffset = 0; - public SimpleDispatch(SailingClientFactory clientFactory) { - ((ServiceDefTarget) dispatchRPC).setServiceEntryPoint(RemoteServiceMappingConstants.dispatchServiceRemotePath); + public SimpleDispatch(String dispatchRPCPath) { + ((ServiceDefTarget) dispatchRPC).setServiceEntryPoint(dispatchRPCPath); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/SailingDispatchSystemImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/SailingDispatchSystemImpl.java index f6a83a87e13..db62ef9885d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/SailingDispatchSystemImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/SailingDispatchSystemImpl.java @@ -1,7 +1,12 @@ package com.sap.sailing.gwt.home.communication; import com.sap.sailing.gwt.dispatch.client.impl.DispatchSystemImpl; +import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants; public class SailingDispatchSystemImpl extends DispatchSystemImpl implements SailingDispatchSystem { + + public SailingDispatchSystemImpl() { + super(RemoteServiceMappingConstants.dispatchServiceRemotePath); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/actions/GetRaceMapDataAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/actions/GetRaceMapDataAction.java index 244247e5216..aa983200a8a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/actions/GetRaceMapDataAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/actions/GetRaceMapDataAction.java @@ -16,14 +16,17 @@ public class GetRaceMapDataAction extends AbstractGetMapRelatedDataAction competitorsByIdAsString; private final Date date; private final LegIdentifier simulationLegIdentifier; + private final byte[] md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID; public GetRaceMapDataAction(SailingServiceAsync sailingService, Map competitorsByIdAsString, RegattaAndRaceIdentifier raceIdentifier, Date date, Map from, - Map to, boolean extrapolate, LegIdentifier simulationLegIdentifier) { + Map to, boolean extrapolate, LegIdentifier simulationLegIdentifier, + byte[] md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID) { super(sailingService, raceIdentifier, from, to, extrapolate); this.competitorsByIdAsString = competitorsByIdAsString; this.date = date; this.simulationLegIdentifier = simulationLegIdentifier; + this.md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID = md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID; } @Override @@ -37,7 +40,8 @@ public class GetRaceMapDataAction extends AbstractGetMapRelatedDataAction() { + isExtrapolate(), simulationLegIdentifier, md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID, + new AsyncCallback() { @Override public void onFailure(Throwable caught) { callback.onFailure(caught); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java index 382674ef414..f2ab322c0d5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.CaptionPanel; import com.google.gwt.user.client.ui.Composite; @@ -139,7 +140,7 @@ public class EventDetailsComposite extends Composite { regattaOverviewURLParameters.put("event", event.id.toString()); String regattaOverviewLink = EntryPointLinkFactory.createRegattaOverviewLink(regattaOverviewURLParameters); eventOverviewURL.setText(regattaOverviewLink); - eventOverviewURL.setHref(regattaOverviewLink); + eventOverviewURL.setHref(UriUtils.fromString(regattaOverviewLink)); List courseAreaNames = new ArrayList<>(); if (event.venue.getCourseAreas() != null && event.venue.getCourseAreas().size() > 0) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java index e2b7decab9e..7a2c891e806 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java @@ -9,6 +9,7 @@ import com.google.gwt.cell.client.FieldUpdater; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.text.shared.SafeHtmlRenderer; import com.google.gwt.user.cellview.client.CellTable; import com.google.gwt.user.cellview.client.Column; @@ -160,7 +161,7 @@ public class IgtimiAccountsPanel extends FlowPanel { @Override public void onSuccess(String result) { - Anchor addIgtimiUserLink = new Anchor(stringMessages.addIgtimiUser(), result); + Anchor addIgtimiUserLink = new Anchor(stringMessages.addIgtimiUser(), UriUtils.fromString(result).asString()); controlsPanel.add(addIgtimiUserLink); } }); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java index dd67a567fda..1d8ed5ef1e8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java @@ -109,24 +109,30 @@ public abstract class ImageDialog extends DataEntryDialog { imageURLAndUploadComposite.addValueChangeHandler(new ValueChangeHandler() { @Override public void onValueChange(ValueChangeEvent event) { - busyIndicator.setBusy(true); String imageUrlAsString = event.getValue(); - ImageDialog.this.sailingService.resolveImageDimensions(imageUrlAsString, new AsyncCallback>() { - @Override - public void onSuccess(Pair imageSize) { - busyIndicator.setBusy(false); - if (imageSize != null) { - widthInPxBox.setValue(imageSize.getA()); - heightInPxBox.setValue(imageSize.getB()); - } - validate(); - } - - @Override - public void onFailure(Throwable caught) { - busyIndicator.setBusy(false); - } - }); + if (imageUrlAsString == null || imageUrlAsString.isEmpty()) { + widthInPxBox.setText(""); + heightInPxBox.setText(""); + } else { + busyIndicator.setBusy(true); + ImageDialog.this.sailingService.resolveImageDimensions(imageUrlAsString, + new AsyncCallback>() { + @Override + public void onSuccess(Pair imageSize) { + busyIndicator.setBusy(false); + if (imageSize != null) { + widthInPxBox.setValue(imageSize.getA()); + heightInPxBox.setValue(imageSize.getB()); + } + validate(); + } + + @Override + public void onFailure(Throwable caught) { + busyIndicator.setBusy(false); + } + }); + } validate(); } }); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java index bf9ae75620a..75e4b2735e5 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java @@ -18,6 +18,7 @@ import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.safehtml.client.SafeHtmlTemplates; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.user.cellview.client.CellTable; import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; @@ -46,6 +47,7 @@ import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.client.shared.controls.FlushableCellTable; import com.sap.sailing.gwt.ui.client.shared.controls.SelectionCheckboxColumn; import com.sap.sailing.gwt.ui.leaderboard.LeaderboardEntryPoint; +import com.sap.sailing.gwt.ui.leaderboard.LeaderboardUrlSettings; import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter; import com.sap.sailing.gwt.ui.shared.EventDTO; import com.sap.sailing.gwt.ui.shared.RaceLogSetStartTimeAndProcedureDTO; @@ -53,7 +55,6 @@ import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; import com.sap.sse.common.Util; import com.sap.sse.common.util.NaturalComparator; import com.sap.sse.gwt.client.ErrorReporter; -import com.sap.sse.gwt.client.URLEncoder; import com.sap.sse.gwt.client.async.MarkedAsyncCallback; import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; @@ -136,11 +137,15 @@ TrackedRaceChangedListener, LeaderboardsDisplayer { Column linkColumn = new Column(anchorCell) { @Override public SafeHtml getValue(StrippedLeaderboardDTO object) { - String debugParam = Window.Location.getParameter("gwt.codesvr"); - String link = URLEncoder.encode("/gwt/Leaderboard.html?name=" + object.name - + (showRaceDetails ? "&showRaceDetails=true" : "") - + (object.displayName != null ? "&displayName="+object.displayName : "") - + (debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr=" + debugParam : "")); + Map leaderboardUrlParams = new HashMap<>(); + leaderboardUrlParams.put("name", object.name); + if (showRaceDetails) { + leaderboardUrlParams.put(LeaderboardUrlSettings.PARAM_SHOW_RACE_DETAILS, "true"); + } + if (object.displayName != null) { + leaderboardUrlParams.put("displayName", object.displayName); + } + String link = EntryPointLinkFactory.createLeaderboardLink(leaderboardUrlParams); return ANCHORTEMPLATE.cell(link, object.name); } @@ -307,9 +312,10 @@ TrackedRaceChangedListener, LeaderboardsDisplayer { } } } else if (LeaderboardConfigImagesBarCell.ACTION_EDIT_SCORES.equals(value)) { - String debugParam = Window.Location.getParameter("gwt.codesvr"); - Window.open("/gwt/LeaderboardEditing.html?name=" + leaderboardDTO.name - + (debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr=" + debugParam : ""), "_blank", null); + Map leaderboardEditingParams = new HashMap<>(); + leaderboardEditingParams.put("name", leaderboardDTO.name); + String leaderboardEditingUrl = EntryPointLinkFactory.createLeaderboardEditingLink(leaderboardEditingParams); + Window.open(leaderboardEditingUrl, "_blank", null); } else if (LeaderboardConfigImagesBarCell.ACTION_EDIT_COMPETITORS.equals(value)) { EditCompetitorsDialog editCompetitorsDialog = new EditCompetitorsDialog(sailingService, leaderboardDTO.name, stringMessages, errorReporter, new DialogCallback>() { @@ -326,7 +332,7 @@ TrackedRaceChangedListener, LeaderboardsDisplayer { } else if (LeaderboardConfigImagesBarCell.ACTION_CONFIGURE_URL.equals(value)) { openLeaderboardUrlConfigDialog(leaderboardDTO, stringMessages); } else if (LeaderboardConfigImagesBarCell.ACTION_EXPORT_XML.equals(value)) { - Window.open("/export/xml?domain=leaderboard&name=" + leaderboardDTO.name, "", null); + Window.open(UriUtils.fromString("/export/xml?domain=leaderboard&name=" + leaderboardDTO.name).asString(), "", null); } else if (LeaderboardConfigImagesBarCell.ACTION_OPEN_COACH_DASHBOARD.equals(value)) { Map dashboardURLParameters = new HashMap(); dashboardURLParameters.put("leaderboardName", leaderboardDTO.name); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java index ce6e0419ea9..268ae3f3907 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java @@ -29,7 +29,6 @@ import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.view.client.ListDataProvider; -import com.google.gwt.view.client.ProvidesKey; import com.google.gwt.view.client.SelectionChangeEvent; import com.sap.sailing.domain.common.dto.RaceColumnDTO; import com.sap.sailing.gwt.ui.adminconsole.LeaderboardConfigPanel.AnchorCell; @@ -578,13 +577,7 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel implements groupsTable.addColumn(groupActionsColumn, stringMessages.actions()); groupsTable.addColumnSortHandler(leaderboardGroupsListHandler); - ProvidesKey groupsKeyProvider = new ProvidesKey() { - @Override - public Object getKey(LeaderboardGroupDTO group) { - return group.getName(); - } - }; - refreshableGroupsSelectionModel = new RefreshableMultiSelectionModel<>(groupsKeyProvider, + refreshableGroupsSelectionModel = new RefreshableMultiSelectionModel<>( new EntityIdentityComparator() { @Override public boolean representSameEntity(LeaderboardGroupDTO dto1, LeaderboardGroupDTO dto2) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompetitorColorProviderImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompetitorColorProviderImpl.java index 07afa3256b4..4ec01e9cf03 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompetitorColorProviderImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompetitorColorProviderImpl.java @@ -13,7 +13,10 @@ import com.sap.sailing.domain.common.impl.ColorMapImpl; import com.sap.sse.common.Color; public class CompetitorColorProviderImpl implements CompetitorColorProvider { - private final ColorMap competitorsColorMap; + /** + * Uses the {@link CompetitorDTO#getIdAsString()} as the ID for the color map + */ + private final ColorMap competitorsColorMap; private final Map> competitorsBoatColorsPerRace; public CompetitorColorProviderImpl() { @@ -22,7 +25,7 @@ public class CompetitorColorProviderImpl implements CompetitorColorProvider { public CompetitorColorProviderImpl(RegattaAndRaceIdentifier raceIdentifier, Map competitorsAndTheirBoats) { - this.competitorsColorMap = new ColorMapImpl(); + this.competitorsColorMap = new ColorMapImpl<>(); this.competitorsBoatColorsPerRace = new HashMap>(); if (raceIdentifier != null) { for (Entry competitorAndBoat : competitorsAndTheirBoats.entrySet()) { @@ -61,7 +64,7 @@ public class CompetitorColorProviderImpl implements CompetitorColorProvider { } // fallback if (result == null) { - result = competitorsColorMap.getColorByID(competitor); + result = competitorsColorMap.getColorByID(competitor.getIdAsString()); } return result; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompetitorSelectionModel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompetitorSelectionModel.java index d64458f2f94..f6859a5b75b 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompetitorSelectionModel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/CompetitorSelectionModel.java @@ -3,9 +3,12 @@ package com.sap.sailing.gwt.ui.client; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.Map; import java.util.Set; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; @@ -18,7 +21,10 @@ import com.sap.sse.common.filter.FilterSet; public class CompetitorSelectionModel implements CompetitorSelectionProvider { private final Set allCompetitors; - private final LinkedHashSet selectedCompetitors; + /** + * Keys are {@link CompetitorDTO#getIdAsString()} of their values + */ + private final LinkedHashMap selectedCompetitors; private final Set listeners; @@ -42,7 +48,7 @@ public class CompetitorSelectionModel implements CompetitorSelectionProvider { this.competitorColorProvider = competitorColorProvider; this.competitorsFilterSet = competitorsFilterSet; this.allCompetitors = new LinkedHashSet(); - this.selectedCompetitors = new LinkedHashSet(); + this.selectedCompetitors = new LinkedHashMap<>(); this.listeners = new HashSet(); } @@ -115,12 +121,12 @@ public class CompetitorSelectionModel implements CompetitorSelectionProvider { @Override public Iterable getSelectedCompetitors() { - return Collections.unmodifiableCollection(selectedCompetitors); + return Collections.unmodifiableCollection(selectedCompetitors.values()); } @Override public Iterable getSelectedFilteredCompetitors() { - Set result = new HashSet<>(selectedCompetitors); + Set result = new HashSet<>(selectedCompetitors.values()); result.retainAll(getFilteredCompetitors()); return result; } @@ -148,13 +154,13 @@ public class CompetitorSelectionModel implements CompetitorSelectionProvider { public void setSelected(CompetitorDTO competitor, boolean selected, CompetitorSelectionChangeListener... listenersNotToNotify) { if (selected) { - if (allCompetitors.contains(competitor) && !selectedCompetitors.contains(competitor)) { - selectedCompetitors.add(competitor); + if (allCompetitors.contains(competitor) && !selectedCompetitors.containsKey(competitor.getIdAsString())) { + selectedCompetitors.put(competitor.getIdAsString(), competitor); fireAddedToSelection(competitor, listenersNotToNotify); } } else { - if (selectedCompetitors.contains(competitor)) { - selectedCompetitors.remove(competitor); + if (selectedCompetitors.containsKey(competitor.getIdAsString())) { + selectedCompetitors.remove(competitor.getIdAsString()); fireRemovedFromSelection(competitor, listenersNotToNotify); } } @@ -186,7 +192,7 @@ public class CompetitorSelectionModel implements CompetitorSelectionProvider { @Override public boolean isSelected(CompetitorDTO competitor) { - return selectedCompetitors.contains(competitor); + return selectedCompetitors.containsKey(competitor.getIdAsString()); } @Override @@ -201,7 +207,7 @@ public class CompetitorSelectionModel implements CompetitorSelectionProvider { @Override public void setSelection(Iterable newSelection, CompetitorSelectionChangeListener... listenersNotToNotify) { - Set competitorsToRemoveFromSelection = new HashSet(selectedCompetitors); + Set competitorsToRemoveFromSelection = new HashSet(selectedCompetitors.values()); for (CompetitorDTO newSelectedCompetitor : newSelection) { setSelected(newSelectedCompetitor, true, listenersNotToNotify); competitorsToRemoveFromSelection.remove(newSelectedCompetitor); @@ -214,17 +220,32 @@ public class CompetitorSelectionModel implements CompetitorSelectionProvider { @Override public void setCompetitors(Iterable newCompetitors, CompetitorSelectionChangeListener... listenersNotToNotify) { boolean changed = false; - - Set oldCompetitorsToRemove = new HashSet(allCompetitors); + Map oldCompetitorsToRemove = new HashMap(); + for (final CompetitorDTO c : allCompetitors) { + oldCompetitorsToRemove.put(c.getIdAsString(), c); + } for (CompetitorDTO newCompetitor : newCompetitors) { - if (allCompetitors.contains(newCompetitor)) { // TODO bug 3413 Lukas: should this use an EntityIdentityComparator instead? - oldCompetitorsToRemove.remove(newCompetitor); // TODO bug 3413 Lukas: the old competitor object remains in allCompetitors; it is equal but doesn't have to be identical to newCompetitor; should it be replaced? + // Search by equality, including all CompetitorDTO fields; if equal object is found, leave it in place; + // non-equal objects may still represent the same competitor entity; yet, replace the object to obtain the + // new, changed state; make sure the selection keeps unchanged regarding the selected competitor "entities"; + // see also bug 3413 for more background. + if (allCompetitors.contains(newCompetitor)) { + oldCompetitorsToRemove.remove(newCompetitor.getIdAsString()); // the old competitor object remains in allCompetitors; it is equal but doesn't have to be identical to newCompetitor } else { + boolean selected = isSelected(newCompetitor); + if (selected) { + remove(oldCompetitorsToRemove.get(newCompetitor.getIdAsString())); + oldCompetitorsToRemove.remove(newCompetitor.getIdAsString()); + } add(newCompetitor, false); // due to the equals definition of CompetitorDTOImpl that compares most fields, state changes lead to a replacement here + if (selected) { + // restore selection for replaced element + setSelected(newCompetitor, selected, listenersNotToNotify); + } changed = true; } } - for (CompetitorDTO oldCompetitorToRemove : oldCompetitorsToRemove) { + for (CompetitorDTO oldCompetitorToRemove : oldCompetitorsToRemove.values()) { remove(oldCompetitorToRemove); changed = true; } @@ -241,7 +262,7 @@ public class CompetitorSelectionModel implements CompetitorSelectionProvider { @Override public Color getColor(CompetitorDTO competitor, RegattaAndRaceIdentifier raceIdentfier) { - return allCompetitors.contains(competitor) ? competitorColorProvider.getColor(competitor, raceIdentfier) : null; + return allCompetitors.contains(competitor) ? competitorColorProvider.getColor(competitor, raceIdentfier) : Color.WHITE /* safe default */; } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EntryPointLinkFactory.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EntryPointLinkFactory.java index 66840bcf631..0cbc204ee07 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EntryPointLinkFactory.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EntryPointLinkFactory.java @@ -1,5 +1,6 @@ package com.sap.sailing.gwt.ui.client; +import java.util.Collections; import java.util.Map; import com.sap.sse.gwt.client.AbstractEntryPointLinkFactory; @@ -17,10 +18,21 @@ public class EntryPointLinkFactory extends AbstractEntryPointLinkFactory { return createEntryPointLink("/gwt/Leaderboard.html", parameters); } + public static String createLeaderboardEditingLink(Map parameters) { + return createEntryPointLink("/gwt/LeaderboardEditing.html", parameters); + } + public static String createLeaderboardTabLink(String eventId, String regattaId, Map parameters) { return createEntryPointLink("/gwt/Home.html#/regatta/leaderboard/:eventId=" + eventId + "®attaId=" + regattaId, parameters); } + public static String createLeaderboardPlaceLink(String eventId, String leaderboardName) { + final Map emptyParams = Collections.emptyMap(); + return createEntryPointLink("/gwt/Home.html#EventPlace:eventId="+eventId+ + "&navigationTab=Regatta&leaderboardName=" +leaderboardName, emptyParams); + + } + public static String createLeaderboardGroupLink(Map parameters) { return createEntryPointLink("/gwt/Spectator.html", parameters); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index f2b20fa0ef9..75ec7c32609 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -157,7 +157,8 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS Map getCompetitorBoats(RegattaAndRaceIdentifier raceIdentifier); CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map fromPerCompetitorIdAsString, - Map toPerCompetitorIdAsString, boolean extrapolate, LegIdentifier simulationLegIdentifier) throws NoWindException; + Map toPerCompetitorIdAsString, boolean extrapolate, LegIdentifier simulationLegIdentifier, + byte[] md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID) throws NoWindException; CompactBoatPositionsDTO getBoatPositions(RegattaAndRaceIdentifier raceIdentifier, Map fromPerCompetitorIdAsString, Map toPerCompetitorIdAsString, diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index 0282609e482..fb9d13f85af 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -364,10 +364,16 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan * @param date * use null to indicate "live" in which case the server live time stamp for the race * identified by raceIdentifier will be used, considering that race's delay. + * @param md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID + * used to decide whether the client requires an update to the race's competitor set. If the server + * has the same MD5 hash for the race's competitors, no competitor set is transmitted to the client. + * Otherwise, the full race competitor ID's as strings are sent to the client again for update. */ void getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map fromPerCompetitorIdAsString, Map toPerCompetitorIdAsString, - boolean extrapolate, LegIdentifier simulationLegIdentifier, AsyncCallback callback); + boolean extrapolate, LegIdentifier simulationLegIdentifier, + byte[] md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID, + AsyncCallback callback); void getBoatPositions(RegattaAndRaceIdentifier raceIdentifier, Map fromPerCompetitorIdAsString, Map toPerCompetitorIdAsString, boolean extrapolate, diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaPlayerManagerComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaPlayerManagerComponent.java index 843955e5fa2..b10c5671e99 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaPlayerManagerComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/MediaPlayerManagerComponent.java @@ -15,6 +15,7 @@ import com.google.gwt.dom.client.MediaElement; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.media.client.Audio; +import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window.ClosingEvent; import com.google.gwt.user.client.Window.ClosingHandler; @@ -124,7 +125,7 @@ public class MediaPlayerManagerComponent implements Component, AudioElement mediaReachableTester = audio.getAudioElement(); addLoadMetadataHandler(mediaReachableTester, mediaTrack); mediaReachableTester.setPreload(MediaElement.PRELOAD_METADATA); - mediaReachableTester.setSrc(mediaTrack.url); + mediaReachableTester.setSrc(UriUtils.fromString(mediaTrack.url).asString()); mediaReachableTester.load(); } else { mediaTrack.status = Status.CANNOT_PLAY; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CombinedWindPanelStyle.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CombinedWindPanelStyle.java index b2bcaaafab6..a1d84ffb09d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CombinedWindPanelStyle.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CombinedWindPanelStyle.java @@ -6,8 +6,6 @@ import com.google.gwt.resources.client.CssResource.Shared; @Shared public interface CombinedWindPanelStyle extends CssResource { public String combinedWindPanel(); - public String combinedWindPanelTextLabel(); - public String combinedWindPanelCanvas(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/FixesAndTails.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/FixesAndTails.java index 485bdb1062c..06150e64a98 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/FixesAndTails.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/FixesAndTails.java @@ -203,13 +203,13 @@ public class FixesAndTails { * longer tail itself), such that the second request that uses the same map will be considered * having an overlap now, not leading to a replacement of the previous update originating from the same * request. - * @return * - * @return a {@link Runnable} for each competitor that the caller must invoke before starting to create or update - * the key competitor's tail. The object returned may be a no-op, but it may also clear an existing tail if - * necessary. The reason why this is not executed immediately is that there may be a transition-based delay - * with which the tails are updated. In this case we would be producing severe flicker. By delaying the - * command to the point when the update is applied should avoid such flicker. + * @return a {@link Runnable} for each competitor from fixesForCompetitors' key set that the caller + * must invoke before starting to create or update the key competitor's tail. The object returned may be a + * no-op, but it may also clear an existing tail if necessary. The reason why this is not executed + * immediately is that there may be a transition-based delay with which the tails are updated. In this case + * we would be producing severe flicker. By delaying the command to the point when the update is applied we + * should avoid such flicker. */ protected Map updateFixes(Map> fixesForCompetitors, Map overlapsWithKnownFixes, TailFactory tailFactory, long timeForPositionTransitionMillis) { @@ -397,8 +397,7 @@ public class FixesAndTails { } int vertexCount = tail.getPath().getLength(); final List fixesForCompetitor = getFixes(competitorDTO); - int indexOfFirstShownFix = firstShownFix.get(competitorDTO) == null ? -1 : firstShownFix - .get(competitorDTO); + int indexOfFirstShownFix = firstShownFix.get(competitorDTO) == null ? -1 : firstShownFix.get(competitorDTO); // remove fixes before what is now to be the beginning of the polyline: while (indexOfFirstShownFix != -1 && vertexCount > 0 && fixesForCompetitor.get(indexOfFirstShownFix).timepoint.before(from)) { @@ -417,8 +416,7 @@ public class FixesAndTails { vertexCount++; } // now adjust the polyline's tail: remove excess vertices that are after "to" - int indexOfLastShownFix = lastShownFix.get(competitorDTO) == null ? -1 : lastShownFix - .get(competitorDTO); + int indexOfLastShownFix = lastShownFix.get(competitorDTO) == null ? -1 : lastShownFix.get(competitorDTO); while (indexOfLastShownFix != -1 && vertexCount > 0 && fixesForCompetitor.get(indexOfLastShownFix).timepoint.after(to)) { if (vertexCount-1 == 0 || (indexOfLastShownFix-1 >= 0 && !fixesForCompetitor.get(indexOfLastShownFix-1).timepoint.after(to))) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceCompetitorSet.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceCompetitorSet.java new file mode 100644 index 00000000000..cc760d12891 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceCompetitorSet.java @@ -0,0 +1,124 @@ +package com.sap.sailing.gwt.ui.client.shared.racemap; + +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.sap.sailing.domain.common.RaceCompetitorIdsAsStringWithMD5Hash; +import com.sap.sailing.domain.common.dto.CompetitorDTO; +import com.sap.sailing.gwt.ui.client.CompetitorSelectionChangeListener; +import com.sap.sailing.gwt.ui.client.CompetitorSelectionProvider; +import com.sap.sse.common.filter.Filter; +import com.sap.sse.common.filter.FilterSet; + +/** + * As an extension of {@link RaceCompetitorIdsAsStringWithMD5Hash}, adds the link with a + * {@link CompetitorSelectionProvider} and allows its clients to obtain the {@link CompetitorDTO} objects for those + * competitors participating in the race under consideration. + *

+ * + * The implementation caches the {@link CompetitorDTO}s and keeps this cache up to date by + * {@link CompetitorSelectionProvider#addCompetitorSelectionChangeListener(CompetitorSelectionChangeListener)} + * listening} on the competitor selection provider for changes. When either the set of competitors for the race + * {@link #setIdsAsStringsOfCompetitorsInRace(Iterable) changes} or the set of competitors + * {@link CompetitorSelectionChangeListener#competitorsListChanged(Iterable) changes}, the {@link CompetitorDTO} + * collection is re-calculated. + * + * @author Axel Uhl (D043530) + * + */ +public class RaceCompetitorSet extends RaceCompetitorIdsAsStringWithMD5Hash { + private static final long serialVersionUID = 3357742414149799988L; + + private CompetitorSelectionProvider competitorSelection; + + /** + * A subset of the competitor selection's {@link CompetitorSelectionProvider#getAllCompetitors()} describing the + * competitors participting in the context of a specific race, or null if this set hasn't been determined + * yet, usually meaning that we have to default to all competitors of the regatta.

+ * + * When {@link #idsAsStringOfCompetitorsParticipatingInRace} is null then so is this field, and vice versa. + */ + private Iterable competitorsParticipatingInRace; + + RaceCompetitorSet() {} // for GWT serialization only + + /** + * Starts out using {@link CompetitorSelectionProvider#getAllCompetitors() all regatta competitors} as response for + * {@link #getCompetitorsParticipatingInRace()}. Only after a call to + * {@link #setIdsAsStringsOfCompetitorsInRace(Iterable)} has been received may this set become adjusted to the + * actual subset participating in the race. + */ + public RaceCompetitorSet(CompetitorSelectionProvider competitorSelection) { + super(); + this.competitorSelection = competitorSelection; + this.competitorsParticipatingInRace = competitorSelection.getAllCompetitors(); + competitorSelection.addCompetitorSelectionChangeListener(new CompetitorSelectionChangeListener() { + @Override + public void removedFromSelection(CompetitorDTO competitor) { + // we don't care about selection + } + + @Override + public void filteredCompetitorsListChanged(Iterable filteredCompetitors) { + // filtering doesn't affect who we think participates in the race + } + + @Override + public void filterChanged(FilterSet> oldFilterSet, + FilterSet> newFilterSet) { + // filtering doesn't affect who we think participates in the race + } + + @Override + public void competitorsListChanged(final Iterable competitors) { + competitorsParticipatingInRace = computeCompetitorsFromIDs(competitors); + } + + @Override + public void addedToSelection(CompetitorDTO competitor) { + // we don't care about selection + } + }); + } + + public void setIdsAsStringsOfCompetitorsInRace(Set idsAsStringsOfCompetitorsInRace) throws UnsupportedEncodingException, NoSuchAlgorithmException { + super.setIdsAsStringsOfCompetitorsInRace(idsAsStringsOfCompetitorsInRace); + competitorsParticipatingInRace = computeCompetitorsFromIDs(competitorSelection.getAllCompetitors()); + } + + public Iterable getCompetitorsParticipatingInRace() { + return competitorsParticipatingInRace; + } + + /** + * Tries to locate the competitors described by the IDs in {@link #idsAsStringOfCompetitorsParticipatingInRace} in + * competitors and returns them in a set. If not all competitors can be found, null is + * returned instead. + */ + private Set computeCompetitorsFromIDs(Iterable competitors) { + Set result; + if (getIdsOfCompetitorsParticipatingInRaceAsStrings() == null) { + result = null; + } else { + final Map competitorsByIdAsString = new HashMap<>(); + for (CompetitorDTO c : competitors) { + competitorsByIdAsString.put(c.getIdAsString(), c); + } + result = new HashSet<>(); + for (String id : getIdsOfCompetitorsParticipatingInRaceAsStrings()) { + CompetitorDTO c = competitorsByIdAsString.get(id); + if (c == null) { + result = null; + break; + } else { + result.add(c); + } + } + } + return result; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java index f929d7b0973..932bb243576 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java @@ -14,7 +14,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import com.google.gwt.canvas.dom.client.CssColor; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; @@ -121,6 +120,7 @@ import com.sap.sailing.gwt.ui.shared.racemap.GoogleMapAPIKey; import com.sap.sailing.gwt.ui.shared.racemap.GoogleMapStyleHelper; import com.sap.sailing.gwt.ui.shared.racemap.RaceSimulationOverlay; import com.sap.sailing.gwt.ui.shared.racemap.WindStreamletsRaceboardOverlay; +import com.sap.sse.common.Color; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Triple; @@ -140,6 +140,7 @@ import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent; public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSelectionChangeListener, RaceTimesInfoProviderListener, TailFactory, Component, RequiresDataInitialization, RequiresResize, QuickRankProvider { + private static final Color LOWLIGHTED_TAIL_COLOR = new RGBColor(200, 200, 200); public static final String GET_RACE_MAP_DATA_CATEGORY = "getRaceMapData"; public static final String GET_WIND_DATA_CATEGORY = "getWindData"; @@ -291,6 +292,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe private final CompetitorSelectionProvider competitorSelection; + private final RaceCompetitorSet raceCompetitorSet; + /** * Used to check if the first initial zoom to the mark markers was already done. */ @@ -423,6 +426,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe windSensorOverlays = new HashMap(); courseMarkOverlays = new HashMap(); this.competitorSelection = competitorSelection; + this.raceCompetitorSet = new RaceCompetitorSet(competitorSelection); competitorSelection.addCompetitorSelectionChangeListener(this); settings = new RaceMapSettings(); coordinateSystem = new DelegateCoordinateSystem(new IdentityCoordinateSystem()); @@ -877,8 +881,10 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe // overlap if it happens after this update. asyncActionsExecutor.execute(new GetRaceMapDataAction(sailingService, competitorsByIdAsString, race, useNullAsTimePoint() ? null : newTime, fromTimesForQuickCall, toTimesForQuickCall, /* extrapolate */true, - (settings.isShowSimulationOverlay() ? simulationOverlay.getLegIdentifier() : null)), GET_RACE_MAP_DATA_CATEGORY, - getRaceMapDataCallback(newTime, transitionTimeInMillis, fromAndToAndOverlap.getC(), competitorsToShow, ++boatPositionRequestIDCounter)); + (settings.isShowSimulationOverlay() ? simulationOverlay.getLegIdentifier() : null), + raceCompetitorSet.getMd5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID()), + GET_RACE_MAP_DATA_CATEGORY, + getRaceMapDataCallback(newTime, transitionTimeInMillis, fromAndToAndOverlap.getC(), competitorsToShow, ++boatPositionRequestIDCounter)); // next, if necessary, do the full thing; the two calls have different action classes, so throttling should not drop one for the other if (!fromTimesForNonOverlappingTailsCall.keySet().isEmpty()) { asyncActionsExecutor.execute(new GetBoatPositionsAction(sailingService, race, fromTimesForNonOverlappingTailsCall, toTimesForNonOverlappingTailsCall, @@ -919,6 +925,14 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe // process response only if not received out of order if (startedProcessingRequestID < requestID) { startedProcessingRequestID = requestID; + if (raceMapDataDTO.raceCompetitorIdsAsStrings != null) { + try { + raceCompetitorSet.setIdsAsStringsOfCompetitorsInRace(raceMapDataDTO.raceCompetitorIdsAsStrings); + } catch (Exception e) { + GWT.log("Error trying to update competitor set for race "+raceIdentifier.getRaceName()+ + " in regatta "+raceIdentifier.getRegattaName(), e); + } + } quickRanks = raceMapDataDTO.quickRanks; competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber = raceMapDataDTO.competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber; @@ -1236,7 +1250,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe if (fixesAndTails.hasFixesFor(competitorDTO)) { Polyline tail = fixesAndTails.getTail(competitorDTO); if (tail == null) { - tailPreparer.run(); // presumably a no-op, but you never know... + if (tailPreparer != null) { // could be we didn't receive boat position data for this competitor; then no tailPreparer will have been created + tailPreparer.run(); // presumably a no-op, but you never know... + } tail = fixesAndTails.createTailAndUpdateIndices(competitorDTO, tailsFromTime, tailsToTime, this); } else { fixesAndTails.updateTail(tail, competitorDTO, tailsFromTime, tailsToTime, @@ -2080,15 +2096,30 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe return vPanel; } - // FIXME bug3378: only fetch those competitors relevant to the race displayed by this RaceMap; see http://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=3378#c20 - // could be a method on CompetitorSelectionProvider, parameterized by a RaceIdentifier, and if nothing is known about the race association, all competitors are returned as a safe default + /** + * @return the {@link CompetitorSelectionProvider#getSelectedCompetitors()} if + * {@link RaceMapSettings#isShowOnlySelectedCompetitors() only selected competitors are to be shown}, the + * {@link CompetitorSelectionProvider#getFilteredCompetitors() filtered competitors} otherwise. In both cases, + * if we have {@link RaceCompetitorSet information about the competitors participating} in this map's race, + * the result set is reduced to those, no matter if other regatta participants would otherwise have been in + * the result set + */ private Iterable getCompetitorsToShow() { - Iterable result; + final Set result = new HashSet<>(); Iterable selection = competitorSelection.getSelectedCompetitors(); + final Set raceCompetitorIdsAsString = raceCompetitorSet.getIdsOfCompetitorsParticipatingInRaceAsStrings(); if (!settings.isShowOnlySelectedCompetitors() || Util.isEmpty(selection)) { - result = competitorSelection.getFilteredCompetitors(); + for (final CompetitorDTO filteredCompetitor : competitorSelection.getFilteredCompetitors()) { + if (raceCompetitorIdsAsString == null || raceCompetitorIdsAsString.contains(filteredCompetitor.getIdAsString())) { + result.add(filteredCompetitor); + } + } } else { - result = selection; + for (final CompetitorDTO selectedCompetitor : selection) { + if (raceCompetitorIdsAsString == null || raceCompetitorIdsAsString.contains(selectedCompetitor.getIdAsString())) { + result.add(selectedCompetitor); + } + } } return result; } @@ -2590,10 +2621,10 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe options.setGeodesic(true); options.setStrokeOpacity(1.0); boolean noCompetitorSelected = Util.isEmpty(competitorSelection.getSelectedCompetitors()); - if (isHighlighted || noCompetitorSelected) { + if (isHighlighted || noCompetitorSelected || getSettings().isShowOnlySelectedCompetitors()) { options.setStrokeColor(competitorSelection.getColor(competitor, raceIdentifier).getAsHtml()); } else { - options.setStrokeColor(CssColor.make(200, 200, 200).toString()); + options.setStrokeColor(LOWLIGHTED_TAIL_COLOR.getAsHtml()); } if (isHighlighted) { options.setStrokeWeight(2); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/presentation/AbstractResultsPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/presentation/AbstractResultsPresenter.java index 8effafd7f9f..4cf316b6e8b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/presentation/AbstractResultsPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/presentation/AbstractResultsPresenter.java @@ -5,6 +5,7 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.safehtml.shared.SafeHtmlUtils; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.DeckLayoutPanel; import com.google.gwt.user.client.ui.DockLayoutPanel; @@ -124,7 +125,7 @@ public abstract class AbstractResultsPresenter im public void showError(String error) { if (state != ResultsPresenterState.ERROR) { mainPanel.setWidgetHidden(controlsPanel, true); - errorLabel.setHTML(error); + errorLabel.setHTML(SafeHtmlUtils.fromString(error).asString()); state = ResultsPresenterState.ERROR; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/presentation/PlainResultsPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/presentation/PlainResultsPresenter.java index 310e27258f8..49a0a67b67d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/presentation/PlainResultsPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/presentation/PlainResultsPresenter.java @@ -5,6 +5,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.Widget; @@ -29,18 +30,23 @@ public class PlainResultsPresenter extends AbstractResultsPresenterWithDataProvi @Override protected void internalShowNumberResult(Map resultValues) { QueryResultDTO result = getCurrentResult(); - - StringBuilder resultsBuilder = new StringBuilder("" + result.getResultSignifier() + ""); - resultsBuilder.append(""); + SafeHtmlBuilder resultsBuilder = new SafeHtmlBuilder(); + resultsBuilder.appendHtmlConstant(""); + resultsBuilder.appendEscaped(result.getResultSignifier()); + resultsBuilder.appendHtmlConstant(""); + resultsBuilder.appendHtmlConstant("
"); for (GroupKey key : getSortedKeys(result)) { - resultsBuilder.append(""); - resultsBuilder.append(""); - resultsBuilder.append(""); - resultsBuilder.append(""); + resultsBuilder.appendHtmlConstant(""); + resultsBuilder.appendHtmlConstant(""); + resultsBuilder.appendHtmlConstant(""); + resultsBuilder.appendHtmlConstant(""); } - resultsBuilder.append("
" + key.toString() + ":" + resultValues.get(key).doubleValue() + "
"); + resultsBuilder.appendEscaped(key.toString()); + resultsBuilder.appendHtmlConstant(":"); + resultsBuilder.append(resultValues.get(key).doubleValue()); + resultsBuilder.appendHtmlConstant("
"); - - resultsLabel.setHTML(resultsBuilder.toString()); + resultsBuilder.appendHtmlConstant(""); + resultsLabel.setHTML(resultsBuilder.toSafeHtml().asString()); } private Iterable getSortedKeys(QueryResultDTO result) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java index 84591a02c58..f96f590ed24 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java @@ -1637,30 +1637,15 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS */ @Override public void addedToSelection(CompetitorDTO competitor) { - getSelectionModel().setSelected(getRow(competitor), true); -/* final LeaderboardRowDTO row = getRow(competitor); - if (row != null) { - redrawRow(row); - }*/ + getSelectionModel().setSelected(getRow(competitor.getIdAsString()), true); } -/* - private void redrawRow(final LeaderboardRowDTO row) { - final List leaderboardDataList = getData().getList(); - synchronized (leaderboardDataList) { - redrawRow(row, leaderboardDataList); - } - } -*/ + /** * Ensure that the checkbox is redrawn when the competitor selection changes */ @Override public void removedFromSelection(CompetitorDTO competitor) { - getSelectionModel().setSelected(getRow(competitor), false); -/* final LeaderboardRowDTO row = getRow(competitor); - if (row != null) { - redrawRow(row); - }*/ + getSelectionModel().setSelected(getRow(competitor.getIdAsString()), false); } @Override @@ -3124,10 +3109,10 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS return stringMessages.leaderboard(); } - private LeaderboardRowDTO getRow(CompetitorDTO competitor) { + private LeaderboardRowDTO getRow(String competitorIdAsString) { synchronized (getData().getList()) { for (LeaderboardRowDTO row : getData().getList()) { - if (row.competitor.equals(competitor)) { + if (row.competitor.getIdAsString().equals(competitorIdAsString)) { return row; } } @@ -3137,7 +3122,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS @Override public void addedToSelection(CompetitorDTO competitor) { - LeaderboardRowDTO row = getRow(competitor); + LeaderboardRowDTO row = getRow(competitor.getIdAsString()); if (row != null) { leaderboardSelectionModel.setSelected(row, true); } @@ -3145,7 +3130,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS @Override public void removedFromSelection(CompetitorDTO competitor) { - LeaderboardRowDTO row = getRow(competitor); + LeaderboardRowDTO row = getRow(competitor.getIdAsString()); if (row != null) { leaderboardSelectionModel.setSelected(row, false); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/MultiLeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/MultiLeaderboardPanel.java index be6a819d2b6..86f9a1e9763 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/MultiLeaderboardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/MultiLeaderboardPanel.java @@ -181,40 +181,35 @@ public class MultiLeaderboardPanel extends AbstractLazyComponent leaderboardNameAndDisplayName : leaderboardNamesAndDisplayNames) { FlowPanel tabFlowPanel = new FlowPanel(); leaderboardsTabPanel.add(tabFlowPanel, leaderboardNameAndDisplayName.getB(), false); - if(selectedLeaderboardName != null && selectedLeaderboardName.equals(leaderboardNameAndDisplayName.getA())) { + if (selectedLeaderboardName != null + && selectedLeaderboardName.equals(leaderboardNameAndDisplayName.getA())) { leaderboardsTabPanel.selectTab(index); } index++; } - // show the last leaderboard when no leaderboard is selected yet - if(selectedLeaderboardName == null && leaderboardCount > 0) { - leaderboardsTabPanel.selectTab(leaderboardCount-1); + // show the last leaderboard when no leaderboard is selected yet + if (selectedLeaderboardName == null && leaderboardCount > 0) { + leaderboardsTabPanel.selectTab(leaderboardCount - 1); } - leaderboardsTabPanel.setVisible(leaderboardCount > 0); - if(!isEmbedded) { + if (!isEmbedded) { leaderboardsLabel.setVisible(leaderboardCount > 0); } } } private void updateSelectedLeaderboard(String newSelectedLeaderboardName, int newTabIndex) { - if(newSelectedLeaderboardName != null) { - if(selectedLeaderboardPanel != null && selectedLeaderboardFlowPanel != null) { + if (newSelectedLeaderboardName != null) { + if (selectedLeaderboardPanel != null && selectedLeaderboardFlowPanel != null) { selectedLeaderboardPanel.removeAllListeners(); selectedLeaderboardFlowPanel.remove(selectedLeaderboardPanel); selectedLeaderboardPanel = null; @@ -229,12 +224,12 @@ public class MultiLeaderboardPanel extends AbstractLazyComponent fromPerCompetitorIdAsString, Map toPerCompetitorIdAsString, - boolean extrapolate, LegIdentifier simulationLegIdentifier) throws NoWindException { + boolean extrapolate, LegIdentifier simulationLegIdentifier, + byte[] md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID) throws NoWindException { + final HashSet raceCompetitorIdsAsStrings; + final TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier); + // if md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID is null, Arrays.equals will return false, and the + // competitor set will be calculated and returned to the client + if (trackedRace == null || Arrays.equals(md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID, trackedRace.getRace().getCompetitorMD5())) { + raceCompetitorIdsAsStrings = null; // tracked race not found or still same MD5 hash, suggesting unchanged competitor set + } else { + raceCompetitorIdsAsStrings = new HashSet<>(); + for (final Competitor c : trackedRace.getRace().getCompetitors()) { + raceCompetitorIdsAsStrings.add(c.getId().toString()); + } + } final Map> boatPositions = getBoatPositionsInternal(raceIdentifier, fromPerCompetitorIdAsString, toPerCompetitorIdAsString, extrapolate); final CoursePositionsDTO coursePositions = getCoursePositions(raceIdentifier, date); @@ -1651,7 +1665,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S SimulationService simulationService = getService().getSimulationService(); simulationResultVersion = simulationService.getSimulationResultsVersion(simulationLegIdentifier); } - return new CompactRaceMapDataDTO(boatPositions, coursePositions, courseSidelines, quickRanks, simulationResultVersion); + return new CompactRaceMapDataDTO(boatPositions, coursePositions, courseSidelines, quickRanks, simulationResultVersion, raceCompetitorIdsAsStrings); } private Map getCompetitorBoatsForRace(RaceDefinition race, List competitorDTOs) { @@ -3442,8 +3456,13 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public Pair resolveImageDimensions(String imageUrlAsString) throws Exception { - URL imageURL = new URL(imageUrlAsString); - Pair imageDimensions = MediaUtils.getImageDimensions(imageURL); + final Pair imageDimensions; + if (imageUrlAsString != null && !imageUrlAsString.isEmpty()) { + URL imageURL = new URL(imageUrlAsString); + imageDimensions = MediaUtils.getImageDimensions(imageURL); + } else { + imageDimensions = null; + } return imageDimensions; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java index c2635fa64f4..bcde6f2e11f 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/CompactRaceMapDataDTO.java @@ -2,12 +2,14 @@ package com.sap.sailing.gwt.ui.shared; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import com.google.gwt.user.client.rpc.IsSerializable; +import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.common.dto.CompetitorDTO; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sse.common.Util; @@ -31,11 +33,18 @@ public class CompactRaceMapDataDTO implements IsSerializable { private LinkedHashMap competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber; private long simulationResultVersion; + /** + * null if the client's request contained an equal MD5 as the race's competitors {@link RaceDefinition#getCompetitorMD5() produce}; + * otherwise, the set of competitor IDs, {@link Object#toString() converted to strings}, in no particular order. + */ + private HashSet raceCompetitorIdsAsStrings; + CompactRaceMapDataDTO() {} public CompactRaceMapDataDTO(Map> boatPositions, CoursePositionsDTO coursePositions, - List courseSidelines, QuickRanksDTO quickRanks, long simulationResultVersion) { + List courseSidelines, QuickRanksDTO quickRanks, long simulationResultVersion, HashSet raceCompetitorIdsAsStrings) { this.boatPositionsByCompetitorIdAsString = new CompactBoatPositionsDTO(boatPositions); + this.raceCompetitorIdsAsStrings = raceCompetitorIdsAsStrings; this.quickRanks = new ArrayList(quickRanks == null ? 0 : Util.size(quickRanks.getQuickRanks())); this.competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber = new LinkedHashMap<>(); Map competitorIdAsStringToOneBasedLegNumber = new HashMap<>(); @@ -76,6 +85,7 @@ public class CompactRaceMapDataDTO implements IsSerializable { } } result.simulationResultVersion = simulationResultVersion; + result.raceCompetitorIdsAsStrings = this.raceCompetitorIdsAsStrings; return result; } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceMapDataDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceMapDataDTO.java index c0f5edb0614..571fc5b0123 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceMapDataDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceMapDataDTO.java @@ -1,5 +1,6 @@ package com.sap.sailing.gwt.ui.shared; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -14,4 +15,5 @@ public class RaceMapDataDTO implements IsSerializable { public LinkedHashMap quickRanks; public LinkedHashMap competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber; public long simulationResultVersion; + public HashSet raceCompetitorIdsAsStrings; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/NoUI.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/NoUI.gwt.xml index ea5872a6f56..eb7cd8bbdb9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/NoUI.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/ui/NoUI.gwt.xml @@ -26,7 +26,9 @@ - + + + @@ -51,6 +53,8 @@ + + diff --git a/java/com.sap.sailing.server.gateway.ess40/.project b/java/com.sap.sailing.server.gateway.ess40/.project new file mode 100644 index 00000000000..18883cf12dd --- /dev/null +++ b/java/com.sap.sailing.server.gateway.ess40/.project @@ -0,0 +1,28 @@ + + + com.sap.sailing.server.gateway.ess40 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/FileUploadServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/FileUploadServlet.java index 15d05cc0f1d..72cd10d3c1f 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/FileUploadServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/FileUploadServlet.java @@ -49,21 +49,22 @@ public class FileUploadServlet extends AbstractFileUploadServlet { */ final JSONArray resultList = new JSONArray(); for (FileItem fileItem : fileItems) { - JSONObject result = new JSONObject(); - String fileExtension = ""; - String fileType = fileItem.getContentType(); + final JSONObject result = new JSONObject(); + final String fileExtension; + final String fileType = fileItem.getContentType(); if (fileType.equals("image/jpeg")) { fileExtension = ".jpg"; } else if (fileType.equals("image/png")) { fileExtension = ".png"; + } else { + fileExtension = ""; } - URI fileUri; try { if (fileItem.getSize() > 1024 * 1024 * MAX_SIZE_IN_MB) { throw new WebApplicationException(Response.status(Status.BAD_REQUEST) .entity("Image is larger than " + MAX_SIZE_IN_MB + "MB").build()); } - fileUri = getService().getFileStorageManagementService().getActiveFileStorageService() + final URI fileUri = getService().getFileStorageManagementService().getActiveFileStorageService() .storeFile(fileItem.getInputStream(), fileExtension, fileItem.getSize()); result.put(JSON_FILE_NAME, fileItem.getName()); result.put(JSON_FILE_URI, fileUri.toString()); @@ -75,6 +76,12 @@ public class FileUploadServlet extends AbstractFileUploadServlet { } resultList.add(result); } - resp.getOutputStream().write(resultList.toJSONString().getBytes("UTF-8")); + // surprise, surprise: see https://www.sencha.com/forum/showthread.php?132949-Fileupload-Invalid-JSON-string + // When sending a JSON response for a file upload, don't use application/json as the content type. It would lead + // to wrapping the content by a

 tag. Use text/html instead which should deliver the content to the app running
+        // in the browser unchanged.
+        resp.setContentType("text/html");
+        resp.setCharacterEncoding("UTF-8");
+        resp.getWriter().append(resultList.toJSONString());
     }
 }
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/AddEntryToRaceLogJsonPostServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/AddEntryToRaceLogJsonPostServlet.java
index a5e56720082..fc534d63b6f 100644
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/AddEntryToRaceLogJsonPostServlet.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/AddEntryToRaceLogJsonPostServlet.java
@@ -12,6 +12,7 @@ import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.commons.lang.StringEscapeUtils;
 import org.json.simple.JSONObject;
 import org.json.simple.JSONValue;
 import org.json.simple.parser.ParseException;
@@ -88,19 +89,19 @@ public class AddEntryToRaceLogJsonPostServlet extends AbstractJsonHttpServlet {
 
         Leaderboard leaderboard = service.getLeaderboardByName(leaderboardName);
         if (leaderboard == null) {
-            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Leaderboard "+leaderboardName+" not found.");
+            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Leaderboard "+StringEscapeUtils.escapeHtml(leaderboardName)+" not found.");
             return;
         }
 
         RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName);
         if (raceColumn == null) {
-            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Race column "+raceColumnName+" not found.");
+            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Race column "+StringEscapeUtils.escapeHtml(raceColumnName)+" not found.");
             return;
         }
 
         Fleet fleet = raceColumn.getFleetByName(fleetName);
         if (fleet == null) {
-            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Fleet "+fleetName+" not found.");
+            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Fleet "+StringEscapeUtils.escapeHtml(fleetName)+" not found.");
             return;
         }
 
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CompetitorsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CompetitorsResource.java
index 5a9dba18631..f53a8abaa71 100644
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CompetitorsResource.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CompetitorsResource.java
@@ -21,6 +21,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
 import org.apache.commons.fileupload.util.Streams;
+import org.apache.commons.lang.StringEscapeUtils;
 import org.json.simple.JSONObject;
 
 import com.sap.sailing.domain.base.Competitor;
@@ -72,7 +73,7 @@ public class CompetitorsResource extends AbstractSailingServerResource {
                 competitorIdAsString);
         if (competitor == null) {
             response = Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a competitor with id '" + competitorIdAsString + "'.")
+                    .entity("Could not find a competitor with id '" + StringEscapeUtils.escapeHtml(competitorIdAsString) + "'.")
                     .type(MediaType.TEXT_PLAIN).build();
         } else {
             String jsonString = getCompetitorJSON(competitor).toJSONString();
@@ -89,7 +90,7 @@ public class CompetitorsResource extends AbstractSailingServerResource {
 
         if (competitor == null) {
             return Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a competitor with id '" + competitorId + "'.").type(MediaType.TEXT_PLAIN)
+                    .entity("Could not find a competitor with id '" + StringEscapeUtils.escapeHtml(competitorId) + "'.").type(MediaType.TEXT_PLAIN)
                     .build();
         }
 
@@ -97,7 +98,7 @@ public class CompetitorsResource extends AbstractSailingServerResource {
 
         if (team == null) {
             return Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a team associated with competitor '" + competitorId + "'.")
+                    .entity("Could not find a team associated with competitor '" + StringEscapeUtils.escapeHtml(competitorId) + "'.")
                     .type(MediaType.TEXT_PLAIN).build();
         }
 
@@ -127,7 +128,7 @@ public class CompetitorsResource extends AbstractSailingServerResource {
         CompetitorStore store = service.getCompetitorStore();
         Competitor competitor = store.getExistingCompetitorByIdAsString(competitorId);
         if (competitor == null) {
-            logger.log(Level.INFO, "Could not find competitor to store image for: " + competitorId);
+            logger.log(Level.INFO, "Could not find competitor to store image for: " + StringEscapeUtils.escapeHtml(competitorId));
             throw new WebApplicationException(Response.status(Status.BAD_REQUEST)
                     .entity("Could not find competitor with id " + competitorId).type(MediaType.TEXT_PLAIN).build());
         }
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DataMiningResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DataMiningResource.java
index 9a53561cbb6..472489eaca3 100644
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DataMiningResource.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DataMiningResource.java
@@ -13,6 +13,7 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
+import org.apache.commons.lang.StringEscapeUtils;
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 import org.osgi.util.tracker.ServiceTracker;
@@ -60,7 +61,7 @@ public class DataMiningResource extends AbstractSailingServerResource {
     }
 
     private Response getBadQueryDefinitionErrorResponse(ModifiableStatisticQueryDefinitionDTO queryDefinitionDTO) {
-        return Response.status(Status.BAD_REQUEST).entity("Couldn't create a query for definition '" + queryDefinitionDTO + "'.")
+        return Response.status(Status.BAD_REQUEST).entity("Couldn't create a query for definition '" + StringEscapeUtils.escapeHtml(queryDefinitionDTO.toString()) + "'.")
                 .type(MediaType.TEXT_PLAIN).build();
     }
 
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java
index 98860559abf..50404e507cf 100644
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java
@@ -11,6 +11,7 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
+import org.apache.commons.lang.StringEscapeUtils;
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 
@@ -29,7 +30,7 @@ import com.sap.sse.common.Util.Pair;
 public class EventsResource extends AbstractSailingServerResource {
 
     private Response getBadEventErrorResponse(String eventId) {
-        return  Response.status(Status.NOT_FOUND).entity("Could not find an event with id '" + eventId + "'.").type(MediaType.TEXT_PLAIN).build();
+        return  Response.status(Status.NOT_FOUND).entity("Could not find an event with id '" + StringEscapeUtils.escapeHtml(eventId) + "'.").type(MediaType.TEXT_PLAIN).build();
     }
 
     @GET
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java
index b399c213d41..96d6fa865d3 100644
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java
@@ -16,6 +16,7 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
+import org.apache.commons.lang.StringEscapeUtils;
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 
@@ -61,7 +62,8 @@ public class LeaderboardGroupsResource extends AbstractSailingServerResource {
         Response response;
         LeaderboardGroup leaderboardGroup = getService().getLeaderboardGroupByName(leaderboardGroupName);
         if (leaderboardGroup == null) {
-            response = Response.status(Status.NOT_FOUND).entity("Could not find a leaderboard group with name '"+leaderboardGroupName+"'.").type(MediaType.TEXT_PLAIN).build();
+            response = Response.status(Status.NOT_FOUND).entity("Could not find a leaderboard group with name '"+
+                    StringEscapeUtils.escapeHtml(leaderboardGroupName)+"'.").type(MediaType.TEXT_PLAIN).build();
         } else {
             TimePoint timePoint = MillisecondsTimePoint.now();
             JSONObject jsonLeaderboardGroup = new JSONObject();
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java
index 9a0ee52b42f..6879796f33e 100644
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java
@@ -28,6 +28,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.xml.ws.http.HTTPException;
 
+import org.apache.commons.lang.StringEscapeUtils;
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 import org.json.simple.JSONValue;
@@ -123,7 +124,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
         Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
         if (leaderboard == null) {
             response = Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a leaderboard with name '" + leaderboardName + "'.")
+                    .entity("Could not find a leaderboard with name '" + StringEscapeUtils.escapeHtml(leaderboardName) + "'.")
                     .type(MediaType.TEXT_PLAIN).build();
         } else {
             try {
@@ -515,11 +516,11 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
 
         if (competitor == null) {
             response = Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a competitor with id '" + competitorIdAsString + "'.")
+                    .entity("Could not find a competitor with id '" + StringEscapeUtils.escapeHtml(competitorIdAsString) + "'.")
                     .type(MediaType.TEXT_PLAIN).build();
         } else if (leaderboard == null) {
             response = Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a leaderboard with name '" + leaderboardName + "'.")
+                    .entity("Could not find a leaderboard with name '" + StringEscapeUtils.escapeHtml(leaderboardName) + "'.")
                     .type(MediaType.TEXT_PLAIN).build();
         } else {
             JSONObject json = CompetitorsResource.getCompetitorJSON(competitor);
@@ -539,7 +540,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
         Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
         if (leaderboard == null) {
             return Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a leaderboard with name '" + leaderboardName + "'.")
+                    .entity("Could not find a leaderboard with name '" + StringEscapeUtils.escapeHtml(leaderboardName) + "'.")
                     .type(MediaType.TEXT_PLAIN).build();
         }
         final Set marks;
@@ -567,14 +568,15 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
             if (raceColumn == null) {
                 return Response
                         .status(Status.NOT_FOUND)
-                        .entity("Could not find a race column '" + raceColumnName + "' in leaderboard '"
-                                + leaderboardName + "'.").type(MediaType.TEXT_PLAIN).build();
+                        .entity("Could not find a race column '" + StringEscapeUtils.escapeHtml(raceColumnName) + "' in leaderboard '"
+                                + StringEscapeUtils.escapeHtml(leaderboardName) + "'.").type(MediaType.TEXT_PLAIN).build();
             } else if (fleetName != null) {
                 Fleet fleet = raceColumn.getFleetByName(fleetName);
                 if (fleet == null) {
                     return Response
                             .status(Status.NOT_FOUND)
-                            .entity("Could not find fleet '" + fleetName + "' in leaderboard '" + leaderboardName
+                            .entity("Could not find fleet '" + StringEscapeUtils.escapeHtml(fleetName) + "' in leaderboard '" +
+                                    StringEscapeUtils.escapeHtml(leaderboardName)
                                     + "'.").type(MediaType.TEXT_PLAIN).build();
                 } else {
                     marks = getMarksForFleet(raceColumn, fleet);
@@ -641,7 +643,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
         Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
         if (leaderboard == null) {
             return Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a leaderboard with name '" + leaderboardName + "'.")
+                    .entity("Could not find a leaderboard with name '" + StringEscapeUtils.escapeHtml(leaderboardName) + "'.")
                     .type(MediaType.TEXT_PLAIN).build();
         }
 
@@ -650,13 +652,13 @@ public class LeaderboardsResource extends AbstractSailingServerResource {
             regattaLog = ((HasRegattaLike) leaderboard).getRegattaLike().getRegattaLog();
         } else {
             return Response.status(Status.BAD_REQUEST)
-                    .entity("Leaderboard '" + leaderboardName + "' does not have an attached RegattaLog.")
+                    .entity("Leaderboard '" + StringEscapeUtils.escapeHtml(leaderboardName) + "' does not have an attached RegattaLog.")
                     .type(MediaType.TEXT_PLAIN).build();
         }
 
         Mark mark = getService().getBaseDomainFactory().getExistingMarkByIdAsString(markId);
         if (mark == null) {
-            return Response.status(Status.NOT_FOUND).entity("Could not find a mark with ID '" + markId + "'.")
+            return Response.status(Status.NOT_FOUND).entity("Could not find a mark with ID '" + StringEscapeUtils.escapeHtml(markId) + "'.")
                     .type(MediaType.TEXT_PLAIN).build();
         }
         TimePoint now = MillisecondsTimePoint.now();
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java
index a6633dc57e2..ec832b06767 100644
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/PolarResource.java
@@ -14,6 +14,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.ResponseBuilder;
 import javax.ws.rs.core.Response.Status;
 
+import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
 import org.json.simple.JSONArray;
 
@@ -134,11 +135,12 @@ public class PolarResource extends AbstractSailingServerResource {
     }
 
     private Response getBadRegattaErrorResponse(String regattaName) {
-        return  Response.status(Status.NOT_FOUND).entity("Could not find a regatta with name '" + regattaName + "'.").type(MediaType.TEXT_PLAIN).build();
+        return  Response.status(Status.NOT_FOUND).entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN).build();
     }
 
     private Response getBadRaceErrorResponse(String regattaName, String raceName) {
-        return Response.status(Status.NOT_FOUND).entity("Could not find a race with name '" + raceName + "' in regatta '" + regattaName + "'.").type(MediaType.TEXT_PLAIN).build();
+        return Response.status(Status.NOT_FOUND).entity("Could not find a race with name '" + StringEscapeUtils.escapeHtml(raceName) +
+                "' in regatta '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN).build();
     }
 
     @GET
diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java
index f20ceb6899e..e08f2deb2ce 100644
--- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java
+++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java
@@ -20,6 +20,7 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
+import org.apache.commons.lang.StringEscapeUtils;
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 
@@ -76,26 +77,26 @@ public class RegattasResource extends AbstractSailingServerResource {
     private static final Logger logger = Logger.getLogger(RegattasResource.class.getName());
 
     private Response getBadRegattaErrorResponse(String regattaName) {
-        return Response.status(Status.NOT_FOUND).entity("Could not find a regatta with name '" + regattaName + "'.")
+        return Response.status(Status.NOT_FOUND).entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.")
                 .type(MediaType.TEXT_PLAIN).build();
     }
 
     private Response getBadRaceErrorResponse(String regattaName, String raceName) {
         return Response.status(Status.NOT_FOUND)
-                .entity("Could not find a race with name '" + raceName + "' in regatta '" + regattaName + "'.")
+                .entity("Could not find a race with name '" + StringEscapeUtils.escapeHtml(raceName) + "' in regatta '" + StringEscapeUtils.escapeHtml(regattaName) + "'.")
                 .type(MediaType.TEXT_PLAIN).build();
     }
     
 
     private Response getNoTrackedRaceErrorResponse(String regattaName, String raceName) {
         return Response.status(Status.NOT_FOUND)
-                .entity("No tracked race for race with name '" + raceName + "' in regatta '" + regattaName + "'.")
+                .entity("No tracked race for race with name '" + StringEscapeUtils.escapeHtml(raceName) + "' in regatta '" + StringEscapeUtils.escapeHtml(regattaName) + "'.")
                 .type(MediaType.TEXT_PLAIN).build();
     }
 
     private Response getNotEnoughDataAvailabeErrorResponse(String regattaName, String raceName) {
         return Response.status(Status.NOT_FOUND)
-                .entity("No wind or polar data for race with name '" + raceName + "' in regatta '" + regattaName + "'.")
+                .entity("No wind or polar data for race with name '" + StringEscapeUtils.escapeHtml(raceName) + "' in regatta '" + StringEscapeUtils.escapeHtml(regattaName) + "'.")
                 .type(MediaType.TEXT_PLAIN).build();
     }
 
@@ -603,13 +604,13 @@ public class RegattasResource extends AbstractSailingServerResource {
         Regatta regatta = findRegattaByName(regattaName);
         if (regatta == null) {
             response = Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a regatta with name '" + regattaName + "'.").type(MediaType.TEXT_PLAIN)
+                    .entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN)
                     .build();
         } else {
             RaceDefinition race = findRaceByName(regatta, raceName);
             if (race == null) {
                 response = Response.status(Status.NOT_FOUND)
-                        .entity("Could not find a race with name '" + raceName + "'.").type(MediaType.TEXT_PLAIN)
+                        .entity("Could not find a race with name '" + StringEscapeUtils.escapeHtml(raceName) + "'.").type(MediaType.TEXT_PLAIN)
                         .build();
             } else {
                 TrackedRace trackedRace = findTrackedRace(regattaName, raceName);
@@ -640,13 +641,13 @@ public class RegattasResource extends AbstractSailingServerResource {
         Regatta regatta = findRegattaByName(regattaName);
         if (regatta == null) {
             response = Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a regatta with name '" + regattaName + "'.").type(MediaType.TEXT_PLAIN)
+                    .entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN)
                     .build();
         } else {
             RaceDefinition race = findRaceByName(regatta, raceName);
             if (race == null) {
                 response = Response.status(Status.NOT_FOUND)
-                        .entity("Could not find a race with name '" + raceName + "'.").type(MediaType.TEXT_PLAIN)
+                        .entity("Could not find a race with name '" + StringEscapeUtils.escapeHtml(raceName) + "'.").type(MediaType.TEXT_PLAIN)
                         .build();
             } else {
                 TrackedRace trackedRace = findTrackedRace(regattaName, raceName);
@@ -696,13 +697,13 @@ public class RegattasResource extends AbstractSailingServerResource {
         Regatta regatta = findRegattaByName(regattaName);
         if (regatta == null) {
             response = Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a regatta with name '" + regattaName + "'.").type(MediaType.TEXT_PLAIN)
+                    .entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN)
                     .build();
         } else {
             RaceDefinition race = findRaceByName(regatta, raceName);
             if (race == null) {
                 response = Response.status(Status.NOT_FOUND)
-                        .entity("Could not find a race with name '" + raceName + "'.").type(MediaType.TEXT_PLAIN)
+                        .entity("Could not find a race with name '" + StringEscapeUtils.escapeHtml(raceName) + "'.").type(MediaType.TEXT_PLAIN)
                         .build();
             } else {
                 TrackedRace trackedRace = findTrackedRace(regattaName, raceName);
@@ -736,13 +737,13 @@ public class RegattasResource extends AbstractSailingServerResource {
         Regatta regatta = findRegattaByName(regattaName);
         if (regatta == null) {
             response = Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a regatta with name '" + regattaName + "'.").type(MediaType.TEXT_PLAIN)
+                    .entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN)
                     .build();
         } else {
             RaceDefinition race = findRaceByName(regatta, raceName);
             if (race == null) {
                 response = Response.status(Status.NOT_FOUND)
-                        .entity("Could not find a race with name '" + raceName + "'.").type(MediaType.TEXT_PLAIN)
+                        .entity("Could not find a race with name '" + StringEscapeUtils.escapeHtml(raceName) + "'.").type(MediaType.TEXT_PLAIN)
                         .build();
             } else {
                 TrackedRace trackedRace = findTrackedRace(regattaName, raceName);
@@ -763,7 +764,7 @@ public class RegattasResource extends AbstractSailingServerResource {
         Regatta regatta = findRegattaByName(regattaName);
         if (regatta == null) {
             response = Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a regatta with name '" + regattaName + "'.").type(MediaType.TEXT_PLAIN)
+                    .entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN)
                     .build();
         } else {
             JSONObject jsonRaceResults = new JSONObject();
@@ -791,13 +792,13 @@ public class RegattasResource extends AbstractSailingServerResource {
         Regatta regatta = findRegattaByName(regattaName);
         if (regatta == null) {
             response = Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a regatta with name '" + regattaName + "'.").type(MediaType.TEXT_PLAIN)
+                    .entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN)
                     .build();
         } else {
             RaceDefinition race = findRaceByName(regatta, raceName);
             if (race == null) {
                 response = Response.status(Status.NOT_FOUND)
-                        .entity("Could not find a race with name '" + raceName + "'.").type(MediaType.TEXT_PLAIN)
+                        .entity("Could not find a race with name '" + StringEscapeUtils.escapeHtml(raceName) + "'.").type(MediaType.TEXT_PLAIN)
                         .build();
             } else {
                 TrackedRace trackedRace = findTrackedRace(regattaName, raceName);
@@ -939,13 +940,13 @@ public class RegattasResource extends AbstractSailingServerResource {
         Regatta regatta = findRegattaByName(regattaName);
         if (regatta == null) {
             response = Response.status(Status.NOT_FOUND)
-                    .entity("Could not find a regatta with name '" + regattaName + "'.").type(MediaType.TEXT_PLAIN)
+                    .entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN)
                     .build();
         } else {
             RaceDefinition race = findRaceByName(regatta, raceName);
             if (race == null) {
                 response = Response.status(Status.NOT_FOUND)
-                        .entity("Could not find a race with name '" + raceName + "'.").type(MediaType.TEXT_PLAIN)
+                        .entity("Could not find a race with name '" + StringEscapeUtils.escapeHtml(raceName) + "'.").type(MediaType.TEXT_PLAIN)
                         .build();
             } else {
                 TrackedRace trackedRace = findTrackedRace(regattaName, raceName);
diff --git a/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/SimulatorUtils.java b/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/SimulatorUtils.java
index 0b1d16ee6ae..a2324cbcbd8 100644
--- a/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/SimulatorUtils.java
+++ b/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/SimulatorUtils.java
@@ -67,103 +67,6 @@ public class SimulatorUtils {
         return prependedBundlePath;
     }
 
-    /*public static RaceHandle loadRace(RacingEventServiceImpl service, TracTracAdapterFactory tracTracAdapterFactory,
-            URL paramURL, URI liveURI, URI storedURI, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
-            long timeoutInMilliseconds) throws Exception {
-        // TODO: TracTrac Username / Password
-        String tractracUsername = "";
-        String tractracPassword = "";
-        RaceHandle raceHandle = tracTracAdapterFactory.getOrCreateTracTracAdapter(service.getBaseDomainFactory())
-                .addTracTracRace(service, paramURL, liveURI, storedURI, null, raceLogStore, regattaLogStore,
-                        timeoutInMilliseconds, tractracUsername, tractracPassword, TracTracConnectionConstants.ONLINE_STATUS,
-                        TracTracConnectionConstants.ONLINE_VISIBILITY);
-        return raceHandle;
-    }*/
-
-    public static boolean savePathsToFiles(Map paths, Path raceCourse) {
-        if (paths == null) {
-            return false;
-        }
-
-        if (paths.isEmpty()) {
-            return true;
-        }
-
-        if (pathPrefix == null) {
-            pathPrefix = getPathPrefix();
-        }
-
-        String filePath = "";
-        boolean result = true;
-
-        for (String name : PATH_NAMES) {
-            filePath = pathPrefix + "\\resources\\" + name + ".dat";
-            result &= saveToFile(paths.get(name), filePath);
-        }
-
-        filePath = pathPrefix + "\\resources\\" + RACECOURSE_DAT;
-        result &= saveToFile(raceCourse, filePath);
-
-        return result;
-    }
-
-    public static boolean saveLegPathsToFiles(Map paths, Path raceCourse, int selectedRaceIndex,
-            int selectedCompetitorIndex, int selectedLegIndex) {
-        if (paths == null) {
-            return false;
-        }
-
-        if (paths.isEmpty()) {
-            return true;
-        }
-
-        if (pathPrefix == null) {
-            pathPrefix = getPathPrefix();
-        }
-
-        String filePath = "";
-        String fileName = "";
-        boolean result = true;
-
-        for (String name : PATH_NAMES) {
-
-            fileName = SimulatorUtils.getFileName(selectedRaceIndex, selectedCompetitorIndex, selectedLegIndex,
-                    name);
-            filePath = pathPrefix + "\\resources\\" + fileName;
-            result &= saveToFile(paths.get(name), filePath);
-        }
-
-        fileName = SimulatorUtils.getFileName(selectedRaceIndex, selectedCompetitorIndex, selectedLegIndex,
-                "racecourse");
-        filePath = pathPrefix + "\\resources\\" + fileName;
-        result &= saveToFile(raceCourse, filePath);
-
-        return result;
-    }
-
-    public static boolean saveToFile(Path path, String fileName) {
-        boolean result = true;
-        try {
-            OutputStream file = new FileOutputStream(fileName);
-            OutputStream buffer = new BufferedOutputStream(file);
-            ObjectOutput output = new ObjectOutputStream(buffer);
-
-            try {
-                output.writeObject(path);
-            } finally {
-                output.close();
-                buffer.close();
-                file.close();
-            }
-        } catch (IOException ex) {
-            System.err.println("[ERROR][SerializationUtils][saveToFile][IOException]  " + ex.getMessage());
-            LOGGER.severe("[ERROR][SerializationUtils][saveToFile][IOException]  " + ex.getMessage());
-            result = false;
-        }
-
-        return result;
-    }
-
     public static Util.Pair, Path> readLegPathsFromResources(int selectedRaceIndex,
             int selectedCompetitorIndex, int selectedLegIndex) {
         HashMap paths = new HashMap();
diff --git a/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java b/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java
index 2b820bc9e63..d22e33221a6 100755
--- a/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java
+++ b/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java
@@ -11,6 +11,7 @@ import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.json.client.JSONArray;
 import com.google.gwt.json.client.JSONObject;
 import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.json.client.JSONValue;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.Composite;
@@ -54,7 +55,7 @@ public class URLFieldWithFileUpload extends Composite implements HasValue]*>(.*)
", "$1")).isObject(); + final JSONObject resultJson = parseAfterReplacingSurroundingPreElement(event.getResults()).isObject(); Window.alert(stringMessages.removeResult(resultJson.get("status").isString().stringValue(), resultJson.get("message") == null ? "" : resultJson.get("message").isString().stringValue())); setURL(""); @@ -110,7 +111,7 @@ public class URLFieldWithFileUpload extends Composite implements HasValue]*>(.*)", "$1")); + JSONArray resultJson = parseAfterReplacingSurroundingPreElement(result).isArray(); if (resultJson != null) { if (resultJson.get(0).isObject().get("file_uri") != null) { uri = resultJson.get(0).isObject().get("file_uri").isString().stringValue(); @@ -185,4 +186,14 @@ public class URLFieldWithFileUpload extends Composite implements HasValue]*>(.*)", "$1")); + } } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/EntityIdentityWrapper.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/EntityIdentityWrapper.java new file mode 100755 index 00000000000..a4553cf4e8b --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/EntityIdentityWrapper.java @@ -0,0 +1,42 @@ +package com.sap.sse.gwt.client.celltable; + + +/** + * Wraps an object such that its {@link #equals(Object)} and {@link #hashCode()} implementations are based on the + * {@link RefreshableMultiSelectionModel#comp} comparator's + * {@link EntityIdentityComparator#representSameEntity(Object, Object)} and + * {@link EntityIdentityComparator#hashCode(Object)} methods, respectively. + * + * @author Axel Uhl (D043530) + * + * @param + */ +class EntityIdentityWrapper { + private final T t; + private final EntityIdentityComparator comp; + + public EntityIdentityWrapper(T t, EntityIdentityComparator comp) { + super(); + this.t = t; + this.comp = comp; + } + + @Override + public int hashCode() { + return comp.hashCode(t); + } + + private T getT() { + return t; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof EntityIdentityWrapper)) { + throw new ClassCastException("Can only compare EntityIdentityWrapper with other objects of same class"); + } + @SuppressWarnings("unchecked") // need to cast to generic type argument T + EntityIdentityWrapper objAsT = ((EntityIdentityWrapper) obj); + return comp.representSameEntity(t, objAsT.getT()); + } +} \ No newline at end of file diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableMultiSelectionModel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableMultiSelectionModel.java index fb9ffac2386..8073b625899 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableMultiSelectionModel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableMultiSelectionModel.java @@ -29,32 +29,26 @@ import com.google.gwt.view.client.SelectionChangeEvent; */ public class RefreshableMultiSelectionModel extends MultiSelectionModel implements RefreshableSelectionModel { - private final EntityIdentityComparator comp; + final EntityIdentityComparator comp; private boolean dontcheckSelectionState = false; private final ListDataProvider listDataProvider; /** * @param comp - * {@link EntityIdentityComparator} to compare the identity of the objects + * {@link EntityIdentityComparator} to compare the identity of the objects; if not null, this will + * also be used to determine the selection "keys" using a {@link ProvidesKey} implementation based on this + * comparator. * @param listDataProvider * {@link ListDataProvider} to add this {@link RefreshableSingleSelectionModel selectionmodel} as an * display on {@link ListDataProvider} */ - public RefreshableMultiSelectionModel(EntityIdentityComparator comp, ListDataProvider listDataProvider) { - this(/* keyProvider */ null, comp, listDataProvider); - } - - /** - * @param keyProvider - * {@link ProvidesKey} for the super class constructor - * @param comp - * {@link EntityIdentityComparator} to compare the identity of the objects - * @param listDataProvider - * {@link ListDataProvider} to add this {@link RefreshableSingleSelectionModel selectionmodel} as an - * display on {@link ListDataProvider} - */ - public RefreshableMultiSelectionModel(ProvidesKey keyProvider, EntityIdentityComparator comp, ListDataProvider listDataProvider) { - super(keyProvider); + public RefreshableMultiSelectionModel(final EntityIdentityComparator comp, ListDataProvider listDataProvider) { + super(/* keyProvider */ comp == null ? null : new ProvidesKey() { + @Override + public Object getKey(T item) { + return new EntityIdentityWrapper(item, comp); + } + }); this.comp = comp; this.listDataProvider = listDataProvider; this.listDataProvider.addDataDisplay(new HasDataAdapter(this, listDataProvider)); @@ -99,43 +93,6 @@ public class RefreshableMultiSelectionModel extends MultiSelectionModel } } - /** - * Wraps an object such that its {@link #equals(Object)} and {@link #hashCode()} implementations are based on the - * {@link RefreshableMultiSelectionModel#comp} comparator's - * {@link EntityIdentityComparator#representSameEntity(Object, Object)} and - * {@link EntityIdentityComparator#hashCode(Object)} methods, respectively. - * - * @author Axel Uhl (D043530) - * - * @param - */ - private class EntityIdentityWrapper { - private final T t; - - public EntityIdentityWrapper(T t) { - super(); - this.t = t; - } - - @Override - public int hashCode() { - return comp.hashCode(t); - } - - private T getT() { - return t; - } - - @SuppressWarnings("unchecked") // need to cast to generic type argument T - @Override - public boolean equals(Object obj) { - if (!(obj instanceof RefreshableMultiSelectionModel.EntityIdentityWrapper)) { - throw new ClassCastException("Can only compare EntityIdentityWrapper with other objects of same class"); - } - return comp.representSameEntity(t, ((EntityIdentityWrapper) obj).getT()); - } - } - /** * Refreshes the {@link RefreshableMultiSelectionModel} with the newObjects.All objects from the * current selection that {@link EntityIdentityComparator#representSameEntity(Object, Object) represent the same @@ -164,15 +121,18 @@ public class RefreshableMultiSelectionModel extends MultiSelectionModel clear(); if (comp == null) { for (T it : newObjects) { - setSelected(it, selectedSet.contains(it)); + final boolean selected = selectedSet.contains(it); + if (selected) { + setSelected(it, true); + } } } else { - final Map wrappedNewObjects = new HashMap<>(); + final Map, T> wrappedNewObjects = new HashMap<>(); for (T it : newObjects) { - wrappedNewObjects.put(new EntityIdentityWrapper(it), it); + wrappedNewObjects.put(new EntityIdentityWrapper(it, comp), it); } for (final T selected : selectedSet) { - T newSelectedElement = wrappedNewObjects.remove(new EntityIdentityWrapper(selected)); + T newSelectedElement = wrappedNewObjects.remove(new EntityIdentityWrapper(selected, comp)); if (newSelectedElement != null) { setSelected(newSelectedElement, true); } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableSingleSelectionModel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableSingleSelectionModel.java index 797f686a577..dc0c7a5da15 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableSingleSelectionModel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableSingleSelectionModel.java @@ -36,26 +36,18 @@ public class RefreshableSingleSelectionModel extends SingleSelectionModel * {@link ListDataProvider} to add this {@link RefreshableSingleSelectionModel selectionmodel} as an * display on {@link ListDataProvider} */ - public RefreshableSingleSelectionModel(EntityIdentityComparator comp, ListDataProvider listDataProvider) { - this(/* keyProvider */ null, comp, listDataProvider); - } - - /** - * @param keyProvider - * {@link ProvidesKey} for the super class constructor - * @param comp - * {@link EntityIdentityComparator} to compare the identity of the objects - * @param listDataProvider - * {@link ListDataProvider} to add this {@link RefreshableSingleSelectionModel selectionmodel} as an - * display on {@link ListDataProvider} - */ - public RefreshableSingleSelectionModel(ProvidesKey keyProvider, EntityIdentityComparator comp, ListDataProvider listDataProvider) { - super(keyProvider); + public RefreshableSingleSelectionModel(final EntityIdentityComparator comp, ListDataProvider listDataProvider) { + super(comp == null ? null : new ProvidesKey() { + @Override + public Object getKey(T item) { + return new EntityIdentityWrapper(item, comp); + } + }); this.comp = comp; this.listDataProvider = listDataProvider; this.listDataProvider.addDataDisplay(new HasDataAdapter(this, listDataProvider)); } - + /** * @return the {@link EntityIdentityComparator} for the {@link RefreshableSingleSelectionModel}. If the * {@link EntityIdentityComparator} is not set this method will return null. diff --git a/java/com.sap.sse.replication/META-INF/MANIFEST.MF b/java/com.sap.sse.replication/META-INF/MANIFEST.MF index a2ca9d4a9a5..ded07e7ce34 100644 --- a/java/com.sap.sse.replication/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.replication/META-INF/MANIFEST.MF @@ -12,7 +12,8 @@ Export-Package: com.sap.sse.replication, Require-Bundle: com.sap.sse.common, com.sap.sse.operationaltransformation, com.sap.sse, - lz4-java;bundle-version="1.3.0" + lz4-java;bundle-version="1.3.0", + org.apache.commons.lang Bundle-ClassPath: . Web-ContextPath: /replication Import-Package: com.rabbitmq.client;version="2.8.4", diff --git a/java/com.sap.sse.replication/src/com/sap/sse/replication/impl/ReplicationServlet.java b/java/com.sap.sse.replication/src/com/sap/sse/replication/impl/ReplicationServlet.java index 67009dc4f53..3277eb00540 100755 --- a/java/com.sap.sse.replication/src/com/sap/sse/replication/impl/ReplicationServlet.java +++ b/java/com.sap.sse.replication/src/com/sap/sse/replication/impl/ReplicationServlet.java @@ -19,6 +19,7 @@ import javax.servlet.http.HttpServletResponse; import net.jpountz.lz4.LZ4BlockOutputStream; +import org.apache.commons.lang.StringEscapeUtils; import org.osgi.framework.BundleContext; import org.osgi.util.tracker.ServiceTracker; @@ -111,7 +112,7 @@ public class ReplicationServlet extends AbstractHttpServlet { if (replicable == null) { final String msg = "Couldn't find replicable with ID "+replicableIdAsString+". Aborting serialization of initial load."; logger.severe(msg); - resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg); + resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, StringEscapeUtils.escapeHtml(msg)); break; // causing an error on the replica which is expecting the replica's initial load } try { @@ -130,7 +131,7 @@ public class ReplicationServlet extends AbstractHttpServlet { channel.getConnection().close(); } default: - resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Action " + action + " not understood. Must be one of " + resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Action " + StringEscapeUtils.escapeHtml(action) + " not understood. Must be one of " + Arrays.toString(Action.values())); } } diff --git a/java/com.sap.sse.security.ui/.settings/org.eclipse.core.resources.prefs b/java/com.sap.sse.security.ui/.settings/org.eclipse.core.resources.prefs index bad142803ca..9866e8509fe 100755 --- a/java/com.sap.sse.security.ui/.settings/org.eclipse.core.resources.prefs +++ b/java/com.sap.sse.security.ui/.settings/org.eclipse.core.resources.prefs @@ -1,4 +1,8 @@ eclipse.preferences.version=1 encoding//src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties=UTF-8 encoding//src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties=UTF-8 +encoding//src/main/java/com/sap/sse/security/ui/client/UserService.java=utf-8 +encoding//src/main/java/com/sap/sse/security/ui/servlet/RedirectServlet.java=utf-8 +encoding//src/main/java/com/sap/sse/security/ui/login/LoginView.java=utf-8 +encoding//src/main/java/com/sap/sse/security/ui/oauth/client/util/ClientUtils.java=utf-8 encoding//src/main/java/com/sap/sse/security/ui/servlet/RedirectServlet.java=utf-8 diff --git a/java/com.sap.sse.security.ui/WEB-INF/web.xml b/java/com.sap.sse.security.ui/WEB-INF/web.xml index 6a4bf7d0912..e96f26129ec 100644 --- a/java/com.sap.sse.security.ui/WEB-INF/web.xml +++ b/java/com.sap.sse.security.ui/WEB-INF/web.xml @@ -4,16 +4,6 @@ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> - - default - org.eclipse.jetty.servlet.DefaultServlet - - - useFileMappedBuffer - false - - - default diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/shared/oauthlogin/OAuthLogin.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/shared/oauthlogin/OAuthLogin.java index 75fc66ae37c..964b23d1821 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/shared/oauthlogin/OAuthLogin.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/shared/oauthlogin/OAuthLogin.java @@ -2,6 +2,7 @@ package com.sap.sse.security.ui.client.shared.oauthlogin; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; @@ -62,7 +63,7 @@ public class OAuthLogin extends Composite { @Override public void onSuccess(String result) { - String authorizationUrl = result; + String authorizationUrl = UriUtils.fromString(result).asString(); GWT.log("Authorization url: " + authorizationUrl); // clear all cookies first diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/oauth/client/util/ClientUtils.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/oauth/client/util/ClientUtils.java index 479e3c74c2f..e3f658c6911 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/oauth/client/util/ClientUtils.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/oauth/client/util/ClientUtils.java @@ -1,5 +1,6 @@ package com.sap.sse.security.ui.oauth.client.util; +import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.user.client.Cookies; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window.Location; @@ -275,7 +276,7 @@ public class ClientUtils { } public static void redirect(String url) { - Window.Location.assign(url); + Window.Location.assign(UriUtils.fromString(url).asString()); } public static boolean redirected() { diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/servlet/RedirectServlet.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/servlet/RedirectServlet.java index db07d90417f..1eb7b581106 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/servlet/RedirectServlet.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/servlet/RedirectServlet.java @@ -14,6 +14,8 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import com.google.gwt.safehtml.shared.UriUtils; + public class RedirectServlet extends HttpServlet { private static final Logger logger = Logger.getLogger(RedirectServlet.class.getName()); @@ -57,7 +59,7 @@ public class RedirectServlet extends HttpServlet { private void doHiddenRedirect(HttpServletResponse resp, String target) throws IOException{ String html = ""; resp.setContentType("text/html"); resp.getWriter().append(html); @@ -97,12 +99,12 @@ public class RedirectServlet extends HttpServlet { } catch (MalformedURLException e) { e.printStackTrace(); } - if (host.contains("local")){ + if (host.startsWith("localhost")) { host = "127.0.0.1"; } String link = "http://" + host + ":" + port + baseLink; int i = 1; - for(Entry entry: parameters.entrySet()) { + for (Entry entry : parameters.entrySet()) { link += i == 1 ? "?" : "&"; link += entry.getKey() + "=" + entry.getValue(); i++; @@ -115,7 +117,7 @@ public class RedirectServlet extends HttpServlet { link += i == 1 ? "?" : "&"; link += "locale=" + localeParam; } - logger.info("Redirecting from " + req.getRequestURL().toString() +" to: " + link); + logger.info("Redirecting from " + req.getRequestURL().toString() + " to: " + link); return link; } } diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/ClientUtils.java b/java/com.sap.sse.security/src/com/sap/sse/security/ClientUtils.java index 2df683f171e..120df13028a 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/ClientUtils.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/ClientUtils.java @@ -1,5 +1,6 @@ package com.sap.sse.security; +import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.user.client.Cookies; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window.Location; @@ -329,7 +330,7 @@ public class ClientUtils public static void redirect(String url) { - Window.Location.assign(url); + Window.Location.assign(UriUtils.fromString(url).asString()); } public static boolean redirected() diff --git a/java/org.moxieapps.gwt.highcharts/src/org/moxieapps/gwt/highcharts/client/Series.java b/java/org.moxieapps.gwt.highcharts/src/org/moxieapps/gwt/highcharts/client/Series.java index a7749f03a8a..d60d1c9fd4e 100755 --- a/java/org.moxieapps.gwt.highcharts/src/org/moxieapps/gwt/highcharts/client/Series.java +++ b/java/org.moxieapps.gwt.highcharts/src/org/moxieapps/gwt/highcharts/client/Series.java @@ -16,16 +16,23 @@ package org.moxieapps.gwt.highcharts.client; -import com.google.gwt.core.client.JavaScriptObject; -import com.google.gwt.core.client.JsArray; -import com.google.gwt.dom.client.Document; -import com.google.gwt.json.client.*; -import org.moxieapps.gwt.highcharts.client.plotOptions.PlotOptions; - import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; +import org.moxieapps.gwt.highcharts.client.plotOptions.PlotOptions; + +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.core.client.JsArray; +import com.google.gwt.core.client.JsonUtils; +import com.google.gwt.dom.client.Document; +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONNull; +import com.google.gwt.json.client.JSONNumber; +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONString; +import com.google.gwt.json.client.JSONValue; + /** * Manages a data series (and its options) that can then be added to a {@link org.moxieapps.gwt.highcharts.client.Chart}. As an extension * of {@link org.moxieapps.gwt.highcharts.client.Configurable} each series instance can also optionally have configuration options set on it. @@ -1230,13 +1237,25 @@ public class Series extends Configurable { }-*/; public void updateThreshold(String threshold) { - updateNativeWay(this.getNativeSeries(), threshold); + updateThresHoldNative(this.getNativeSeries(), threshold); + } + + public void updateSeriesFillColor(String fillColor) { + JavaScriptObject fillColorObject = JsonUtils.safeEval(fillColor); + updateFillColorNative(this.getNativeSeries(), fillColorObject); } - public static native void updateNativeWay(JavaScriptObject series, String threshold) /*-{ + public static native void updateThresHoldNative(JavaScriptObject series, String threshold) /*-{ series.update({ threshold: threshold, borderColor: '#FF0000' }) }-*/; + + public static native void updateFillColorNative(JavaScriptObject series, JavaScriptObject fillColorValue) /*-{ + series.update({ + fillColor: fillColorValue + }) + }-*/; + } diff --git a/mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/logging/FileLoggingTask.java b/mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/logging/FileLoggingTask.java index 3533686e40b..ded70290c51 100644 --- a/mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/logging/FileLoggingTask.java +++ b/mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/logging/FileLoggingTask.java @@ -90,6 +90,7 @@ public class FileLoggingTask implements Runnable { logWriter.newLine(); logWriter.flush(); } catch (Exception e) { + // if logging don't work, how can we log that it didn't work...? } } diff --git a/mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/util/AppUtils.java b/mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/util/AppUtils.java index 0a29886f40c..6cf10ee3465 100644 --- a/mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/util/AppUtils.java +++ b/mobile/com.sap.sailing.android.shared/src/com/sap/sailing/android/shared/util/AppUtils.java @@ -46,7 +46,7 @@ public class AppUtils { try { reader.close(); } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Error trying to read build info", e); } } } diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/RegattaActivity.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/RegattaActivity.java index f66bdca92b4..c873843a4d0 100755 --- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/RegattaActivity.java +++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/RegattaActivity.java @@ -526,7 +526,7 @@ public class RegattaActivity extends AbstractRegattaActivity implements RegattaF try { in = new java.net.URL(downloadUrl).openStream(); imageFile = getImageFile(getLeaderboardImageFileName(leaderboard.name)); - if (!imageFile.exists()){ + if (!imageFile.exists()) { imageFile.createNewFile(); } outputStream = new FileOutputStream(imageFile); @@ -539,7 +539,7 @@ public class RegattaActivity extends AbstractRegattaActivity implements RegattaF outputStream.close(); in.close(); } catch (Exception e) { - e.printStackTrace(); + ExLog.e(RegattaActivity.this, TAG, "Failed to download image file " + imageFile); } finally { if (in != null) { safeClose(in); @@ -582,7 +582,7 @@ public class RegattaActivity extends AbstractRegattaActivity implements RegattaF InputStream in = new java.net.URL(downloadUrl).openStream(); mIcon11 = BitmapFactory.decodeStream(in); } catch (Exception e) { - e.printStackTrace(); + ExLog.e(RegattaActivity.this, TAG, "Failed to download flat image at url " + downloadUrl+": "+e.getMessage()); } return mIcon11; } diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/TrackingActivity.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/TrackingActivity.java index 9cbb55c9723..407d4b34a36 100644 --- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/TrackingActivity.java +++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/TrackingActivity.java @@ -427,7 +427,7 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener try { Thread.sleep(1000); } catch (InterruptedException e) { - e.printStackTrace(); + ExLog.e(TrackingActivity.this, TAG, "Interrupted sleep"); } } } diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/RegattaFragment.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/RegattaFragment.java index bfd4413bf60..9cbca5a4413 100755 --- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/RegattaFragment.java +++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/RegattaFragment.java @@ -395,7 +395,7 @@ public class RegattaFragment extends BaseFragment implements OnClickListener { try { Thread.sleep(1000); } catch (InterruptedException e) { - e.printStackTrace(); + ExLog.w(RegattaFragment.this.getActivity(), TAG, "Interrupted sleep"); } } } diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/DatabaseHelper.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/DatabaseHelper.java index c484621a633..bb645c100fe 100644 --- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/DatabaseHelper.java +++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/DatabaseHelper.java @@ -42,32 +42,14 @@ public class DatabaseHelper { int result = 0; ContentResolver cr = context.getContentResolver(); - Cursor cursor = cr.query(Event.CONTENT_URI, null, Event.EVENT_CHECKIN_DIGEST + " = \"" + checkinDigest + "\"", - null, null); + Cursor cursor = cr.query(Event.CONTENT_URI, null, Event.EVENT_CHECKIN_DIGEST + " = ?", + new String[] { checkinDigest }, null); cursor.moveToFirst(); result = cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)); cursor.close(); return result; } - // public EventInfo getEventInfoWithLeaderboard(Context context, String eventId) { - // EventInfo result = new EventInfo(); - // - // ContentResolver cr = context.getContentResolver(); - // String projectionStr = "events._id,leaderboards.leaderboard_name,events.event_name"; - // String[] projection = projectionStr.split(","); - // Cursor cursor = cr.query(LeaderboardsEventsJoined.CONTENT_URI, projection, "events.event_id = \"" + eventId + - // "\"", null, null); - // if (cursor.moveToFirst()) - // { - // result.name = cursor.getString(cursor.getColumnIndex("event_name")); - // result.leaderboardName = cursor.getString(cursor.getColumnIndex("leaderboard_name")); - // } - // - // cursor.close(); - // return result; - // } - public EventInfo getEventInfoWithLeaderboardAndCompetitor(Context context, String checkinDigest) { EventInfo result = new EventInfo(); @@ -76,7 +58,7 @@ public class DatabaseHelper { + " events.event_name, competitors.competitor_id"; String[] projection = projectionStr.split(","); Cursor cursor = cr.query(EventLeaderboardCompetitorJoined.CONTENT_URI, projection, "events." - + Event.EVENT_CHECKIN_DIGEST + " = \"" + checkinDigest + "\"", null, null); + + Event.EVENT_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }, null); if (cursor.moveToFirst()) { result.name = cursor.getString(cursor.getColumnIndex("event_name")); result.leaderboardName = cursor.getString(cursor.getColumnIndex("leaderboard_name")); @@ -88,32 +70,12 @@ public class DatabaseHelper { return result; } - // public EventInfo getEventInfoWithLeaderboardAndCompetitor(Context context, String eventId) { - // EventInfo result = new EventInfo(); - // - // ContentResolver cr = context.getContentResolver(); - // String projectionStr = "events._id,leaderboards.leaderboard_name,events.event_name, competitors.competitor_id"; - // String[] projection = projectionStr.split(","); - // Cursor cursor = cr.query(EventLeaderboardCompetitorJoined.CONTENT_URI, projection, "events.event_id = \"" + - // eventId + "\"", null, null); - // if (cursor.moveToFirst()) - // { - // result.name = cursor.getString(cursor.getColumnIndex("event_name")); - // result.leaderboardName = cursor.getString(cursor.getColumnIndex("leaderboard_name")); - // result.competitorId = cursor.getString(cursor.getColumnIndex("competitor_id")); - // } - // - // cursor.close(); - // return result; - // } - // - public EventInfo getEventInfo(Context context, String checkinDigest) { EventInfo event = new EventInfo(); event.checkinDigest = checkinDigest; Cursor cursor = context.getContentResolver().query(Event.CONTENT_URI, null, - Event.EVENT_CHECKIN_DIGEST + " = \"" + checkinDigest + "\"", null, null); + Event.EVENT_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }, null); if (cursor.moveToFirst()) { event.name = cursor.getString(cursor.getColumnIndex(Event.EVENT_NAME)); @@ -129,30 +91,12 @@ public class DatabaseHelper { return event; } - // public CompetitorInfo getCompetitor(Context context, String competitorId) - // { - // CompetitorInfo competitor = new CompetitorInfo(); - // competitor.id = competitorId; - // - // Cursor cursor = context.getContentResolver().query(Competitor.CONTENT_URI, null, "competitor_id = \"" + - // competitorId + "\"", null, null); - // if (cursor.moveToFirst()) { - // competitor.name = cursor.getString(cursor.getColumnIndex(Competitor.COMPETITOR_DISPLAY_NAME)); - // competitor.countryCode = cursor.getString(cursor.getColumnIndex(Competitor.COMPETITOR_COUNTRY_CODE)); - // competitor.sailId = cursor.getString(cursor.getColumnIndex(Competitor.COMPETITOR_SAIL_ID)); - // competitor.rowId = cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)); - // } - // - // cursor.close(); - // return competitor; - // } - public CompetitorInfo getCompetitor(Context context, String checkinDigest) { CompetitorInfo competitor = new CompetitorInfo(); competitor.checkinDigest = checkinDigest; Cursor cursor = context.getContentResolver().query(Competitor.CONTENT_URI, null, - Competitor.COMPETITOR_CHECKIN_DIGEST + " = \"" + checkinDigest + "\"", null, null); + Competitor.COMPETITOR_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }, null); if (cursor.moveToFirst()) { competitor.name = cursor.getString(cursor.getColumnIndex(Competitor.COMPETITOR_DISPLAY_NAME)); competitor.countryCode = cursor.getString(cursor.getColumnIndex(Competitor.COMPETITOR_COUNTRY_CODE)); @@ -165,29 +109,12 @@ public class DatabaseHelper { return competitor; } - // public LeaderboardInfo getLeaderboard(Context context, String leaderboardName) - // { - // LeaderboardInfo leaderboard = new LeaderboardInfo(); - // leaderboard.name = leaderboardName; - // - // Cursor lc = context.getContentResolver().query(Leaderboard.CONTENT_URI, null, "leaderboard_name = \"" + - // leaderboardName + "\"", null, null); - // if (lc.moveToFirst()) { - // leaderboard.rowId = lc.getInt(lc.getColumnIndex(BaseColumns._ID)); - // leaderboard.checkinDigest = lc.getString(lc.getColumnIndex(Leaderboard.LEADERBOARD_CHECKIN_DIGEST)); - // } - // - // lc.close(); - // - // return leaderboard; - // } - public LeaderboardInfo getLeaderboard(Context context, String checkinDigest) { LeaderboardInfo leaderboard = new LeaderboardInfo(); leaderboard.checkinDigest = checkinDigest; Cursor lc = context.getContentResolver().query(Leaderboard.CONTENT_URI, null, - Leaderboard.LEADERBOARD_CHECKIN_DIGEST + " = \"" + checkinDigest + "\"", null, null); + Leaderboard.LEADERBOARD_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }, null); if (lc.moveToFirst()) { leaderboard.rowId = lc.getInt(lc.getColumnIndex(BaseColumns._ID)); leaderboard.name = lc.getString(lc.getColumnIndex(Leaderboard.LEADERBOARD_NAME)); @@ -203,7 +130,7 @@ public class DatabaseHelper { checkinUrlInfo.checkinDigest = checkinDigest; Cursor uc = context.getContentResolver().query(CheckinUri.CONTENT_URI, null, - CheckinUri.CHECKIN_URI_CHECKIN_DIGEST + " = \"" + checkinDigest + "\"", null, null); + CheckinUri.CHECKIN_URI_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }, null); if (uc.moveToFirst()) { checkinUrlInfo.rowId = uc.getInt(uc.getColumnIndex(BaseColumns._ID)); checkinUrlInfo.urlString = uc.getString(uc.getColumnIndex(CheckinUri.CHECKIN_URI_VALUE)); @@ -214,34 +141,13 @@ public class DatabaseHelper { return checkinUrlInfo; } - // public void deleteRegattaFromDatabase(Context context, String eventId, String competitorId, String - // leaderboardName) - // { - // ContentResolver cr = context.getContentResolver(); - // - // int d1 = cr.delete(Event.CONTENT_URI, Event.EVENT_ID + " = \"" + eventId + "\"", null); - // int d2 = cr.delete(Competitor.CONTENT_URI, Competitor.COMPETITOR_ID + " = \"" + competitorId + "\"", null); - // int d3 = cr.delete(Leaderboard.CONTENT_URI, Leaderboard.LEADERBOARD_NAME + " = \"" + leaderboardName + "\"", - // null); - // - // if (BuildConfig.DEBUG) - // { - // ExLog.i(context, TAG, "Checkout, number of events deleted: " + d1); - // ExLog.i(context, TAG, "Checkout, number of competitors deleted: " + d2); - // ExLog.i(context, TAG, "Checkout, number of leaderbards deleted: " + d3); - // } - // } - public void deleteRegattaFromDatabase(Context context, String checkinDigest) { ContentResolver cr = context.getContentResolver(); - int d1 = cr.delete(Event.CONTENT_URI, Event.EVENT_CHECKIN_DIGEST + " = \"" + checkinDigest + "\"", null); - int d2 = cr.delete(Competitor.CONTENT_URI, Competitor.COMPETITOR_CHECKIN_DIGEST + " = \"" + checkinDigest - + "\"", null); - int d3 = cr.delete(Leaderboard.CONTENT_URI, Leaderboard.LEADERBOARD_CHECKIN_DIGEST + " = \"" + checkinDigest - + "\"", null); - int d4 = cr.delete(CheckinUri.CONTENT_URI, CheckinUri.CHECKIN_URI_CHECKIN_DIGEST + " = \"" + checkinDigest - + "\"", null); + int d1 = cr.delete(Event.CONTENT_URI, Event.EVENT_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }); + int d2 = cr.delete(Competitor.CONTENT_URI, Competitor.COMPETITOR_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }); + int d3 = cr.delete(Leaderboard.CONTENT_URI, Leaderboard.LEADERBOARD_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }); + int d4 = cr.delete(CheckinUri.CONTENT_URI, CheckinUri.CHECKIN_URI_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }); if (BuildConfig.DEBUG) { ExLog.i(context, TAG, "Checkout, number of events deleted: " + d1); @@ -333,16 +239,11 @@ public class DatabaseHelper { * @return */ public boolean eventLeaderboardCompetitorCombnationAvailable(Context context, String checkinDigest) { - ContentResolver cr = context.getContentResolver(); - String sel = "leaderboards.leaderboard_checkin_digest = \"" + checkinDigest - + "\" AND competitors.competitor_checkin_digest = \"" + checkinDigest - + "\" AND events.event_checkin_digest = \"" + checkinDigest + "\""; - - Cursor cursor = cr.query(AnalyticsContract.EventLeaderboardCompetitorJoined.CONTENT_URI, null, sel, null, null); - + String sel = "leaderboards.leaderboard_checkin_digest = ? AND competitors.competitor_checkin_digest = ? AND events.event_checkin_digest = ?"; + Cursor cursor = cr.query(AnalyticsContract.EventLeaderboardCompetitorJoined.CONTENT_URI, null, sel, + new String[] { checkinDigest, checkinDigest, checkinDigest }, null); int count = cursor.getCount(); - cursor.close(); return count == 0; } diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/ImageController.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/ImageController.java index cc79941f713..762e7fb82ef 100644 --- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/ImageController.java +++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/ImageController.java @@ -1,5 +1,10 @@ package com.sap.sailing.android.tracking.app.utils; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; @@ -14,16 +19,13 @@ import android.media.ExifInterface; import android.net.Uri; import android.provider.MediaStore; import android.util.Base64; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; +import android.util.Log; /** * Todo: Use this class? */ public class ImageController { + private static final String TAG = ImageController.class.getName(); public static String getRealPathFromURI(ContentResolver contentResolver, Uri contentUri) { String res = null; @@ -382,7 +384,7 @@ public class ImageController { InputStream inputStream = contentResolver.openInputStream(uri); BitmapFactory.decodeStream(inputStream, null, options); } catch (IOException e) { - + Log.e(TAG, "Error trying to read image from "+uri, e); } } else { BitmapFactory.decodeFile(filename, options); @@ -399,7 +401,7 @@ public class ImageController { InputStream inputStream = contentResolver.openInputStream(uri); bitmap = BitmapFactory.decodeStream(inputStream, null, options); } catch (IOException e) { - + Log.e(TAG, "Error trying to read image from "+uri, e); } } else { bitmap = BitmapFactory.decodeFile(filename, options); @@ -435,7 +437,7 @@ public class ImageController { bitmap = rotatedBitmap; } } catch (IOException e) { - + Log.e(TAG, "Error trying to determine orientation for image "+filename+" loaded from "+uri, e); } } return bitmap; diff --git a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/provider/AnalyticsProvider.java b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/provider/AnalyticsProvider.java index 110ba1812c7..ca153e8dde0 100644 --- a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/provider/AnalyticsProvider.java +++ b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/provider/AnalyticsProvider.java @@ -80,13 +80,6 @@ public class AnalyticsProvider extends ContentProvider { return true; } - // private void deleteDatabase() { - // Context context = getContext(); - // mOpenHelper.close(); - // AnalyticsDatabase.deleteDatabase(context); - // mOpenHelper = new AnalyticsDatabase(context); - // } - @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { if (BuildConfig.DEBUG && AppPreferences.getPrintDatabaseOperationDebugMessages()) { diff --git a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/service/MarkerService.java b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/service/MarkerService.java index 99753aed34e..4e25a2937f4 100644 --- a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/service/MarkerService.java +++ b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/service/MarkerService.java @@ -63,9 +63,8 @@ public class MarkerService extends Service implements CheckinManager.DataChange DatabaseHelper helper = DatabaseHelper.getInstance(); helper.deleteRegattaFromDatabase(this, checkinData.checkinDigest); helper.storeCheckinRow(this, checkinData.marks, checkinData.getLeaderboard(), checkinData.getCheckinUrl(), checkinData.pings); - } - catch (DatabaseHelper.GeneralDatabaseHelperException e) { - e.printStackTrace(); + } catch (DatabaseHelper.GeneralDatabaseHelperException e) { + Log.e(TAG, "Error trying to analyze mark checkin data", e); } } @@ -78,10 +77,9 @@ public class MarkerService extends Service implements CheckinManager.DataChange } private class TimerRunnable implements Runnable { - ; - private boolean running; + private boolean running; - public TimerRunnable(){ + public TimerRunnable() { running = true; } @@ -89,15 +87,14 @@ public class MarkerService extends Service implements CheckinManager.DataChange public void run() { while (running) { long timeDiff = Calendar.getInstance().getTimeInMillis() - lastCheck; - - if(timeDiff > preferences.getDataRefreshInterval() * 1000) { + if (timeDiff > preferences.getDataRefreshInterval() * 1000) { manager.callServerAndGenerateCheckinData(); lastCheck = Calendar.getInstance().getTimeInMillis(); } try { Thread.sleep(1000); } catch (InterruptedException e) { - e.printStackTrace(); + Log.d(TAG, "Interrupted Sleep", e); } } } diff --git a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java index bc760615baa..d8f0f755b39 100644 --- a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java +++ b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/ui/fragments/BuoyFragment.java @@ -304,7 +304,7 @@ public class BuoyFragment extends BaseFragment implements LocationListener { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Log.d(TAG, "Action: " + action); - if(action.equals(getString(R.string.database_changed))) { + if (action.equals(getString(R.string.database_changed))) { positioningActivity.loadDataFromDatabase(); setUpTextUI(lastKnownLocation); updateMap(); diff --git a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/util/CheckinManager.java b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/util/CheckinManager.java index 406296e0cb3..16466234caf 100644 --- a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/util/CheckinManager.java +++ b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/util/CheckinManager.java @@ -1,10 +1,26 @@ package com.sap.sailing.android.buoy.positioning.app.util; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLEncoder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.net.Uri; +import android.util.Log; import android.widget.Toast; + import com.sap.sailing.android.buoy.positioning.app.R; import com.sap.sailing.android.buoy.positioning.app.valueobjects.CheckinData; import com.sap.sailing.android.buoy.positioning.app.valueobjects.MarkInfo; @@ -19,19 +35,6 @@ import com.sap.sailing.android.shared.util.UniqueDeviceUuid; import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants; import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; import com.sap.sailing.domain.racelogtracking.impl.SmartphoneUUIDIdentifierImpl; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLEncoder; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; public class CheckinManager { @@ -77,6 +80,7 @@ public class CheckinManager { } private URLData extractRequestParametersFromUri(Uri uri, String scheme) { + assert uri != null; URLData urlData = new URLData(); urlData.uriStr = uri.toString(); urlData.server = scheme + "://" + uri.getHost(); @@ -290,11 +294,9 @@ public class CheckinManager { checkinDigest = buf.toString(); } } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Log.e(TAG, "Exception trying to generate check-in digest", e); } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Log.e(TAG, "Exception trying to generate check-in digest", e); } return checkinDigest; } diff --git a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/util/DatabaseHelper.java b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/util/DatabaseHelper.java index e4e15c6c2b9..7a496ff2ab8 100644 --- a/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/util/DatabaseHelper.java +++ b/mobile/com.sap.sailing.buoy.positioning/src/com/sap/sailing/android/buoy/positioning/app/util/DatabaseHelper.java @@ -46,7 +46,7 @@ public class DatabaseHelper { leaderboard.checkinDigest = checkinDigest; Cursor lc = context.getContentResolver().query(Leaderboard.CONTENT_URI, null, - Leaderboard.LEADERBOARD_CHECKIN_DIGEST + " = \"" + checkinDigest + "\"", null, null); + Leaderboard.LEADERBOARD_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }, null); if (lc.moveToFirst()) { leaderboard.rowId = lc.getInt(lc.getColumnIndex(BaseColumns._ID)); leaderboard.name = lc.getString(lc.getColumnIndex(Leaderboard.LEADERBOARD_NAME)); @@ -63,7 +63,7 @@ public class DatabaseHelper { checkinUrlInfo.checkinDigest = checkinDigest; Cursor uc = context.getContentResolver().query(CheckinUri.CONTENT_URI, null, - CheckinUri.CHECKIN_URI_CHECKIN_DIGEST + " = \"" + checkinDigest + "\"", null, null); + CheckinUri.CHECKIN_URI_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }, null); if (uc.moveToFirst()) { checkinUrlInfo.rowId = uc.getInt(uc.getColumnIndex(BaseColumns._ID)); checkinUrlInfo.urlString = uc.getString(uc.getColumnIndex(CheckinUri.CHECKIN_URI_VALUE)); @@ -77,7 +77,7 @@ public class DatabaseHelper { public List getMarks(Context context, String checkinDigest) { List marks = new ArrayList(); Cursor mc = context.getContentResolver().query(Mark.CONTENT_URI, null, - Mark.MARK_CHECKIN_DIGEST + " = \"" + checkinDigest + "\"", null, null); + Mark.MARK_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }, null); mc.moveToFirst(); while (!mc.isAfterLast()) { MarkInfo markInfo = new MarkInfo(); @@ -96,7 +96,7 @@ public class DatabaseHelper { public List getMarkPings(Context context, String markID) { List marks = new ArrayList(); Cursor mpc = context.getContentResolver().query(MarkPing.CONTENT_URI, null, - MarkPing.MARK_ID + " = \"" + markID + "\"", null, MarkPing.MARK_PING_TIMESTAMP + " DESC"); + MarkPing.MARK_ID + " = ?", new String[] { markID }, MarkPing.MARK_PING_TIMESTAMP + " DESC"); mpc.moveToFirst(); while (!mpc.isAfterLast()) { MarkPingInfo markPingInfo = new MarkPingInfo(); @@ -114,7 +114,7 @@ public class DatabaseHelper { public void deletePingsFromDataBase(Context context, String markID) { ContentResolver cr = context.getContentResolver(); - int d1 = cr.delete(MarkPing.CONTENT_URI, MarkPing.MARK_ID + " = \"" + markID + "\"", null); + int d1 = cr.delete(MarkPing.CONTENT_URI, MarkPing.MARK_ID + " = ?", new String[] { markID }); if (BuildConfig.DEBUG) { ExLog.i(context, TAG, "Checkout, number of markpings for mark: " + markID + " deleted: " + d1); @@ -130,11 +130,9 @@ public class DatabaseHelper { deletePingsFromDataBase(context, mark.getId()); } - int d2 = cr.delete(Leaderboard.CONTENT_URI, Leaderboard.LEADERBOARD_CHECKIN_DIGEST + " = \"" + checkinDigest - + "\"", null); - int d3 = cr.delete(Mark.CONTENT_URI, Mark.MARK_CHECKIN_DIGEST + " = \"" + checkinDigest + "\"", null); - int d4 = cr.delete(CheckinUri.CONTENT_URI, CheckinUri.CHECKIN_URI_CHECKIN_DIGEST + " = \"" + checkinDigest - + "\"", null); + int d2 = cr.delete(Leaderboard.CONTENT_URI, Leaderboard.LEADERBOARD_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }); + int d3 = cr.delete(Mark.CONTENT_URI, Mark.MARK_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }); + int d4 = cr.delete(CheckinUri.CONTENT_URI, CheckinUri.CHECKIN_URI_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }); if (BuildConfig.DEBUG) { ExLog.i(context, TAG, "Checkout, number of leaderbards deleted: " + d2); @@ -236,7 +234,7 @@ public class DatabaseHelper { public boolean markLeaderboardCombnationAvailable(Context context, String checkinDigest) { Cursor lc = context.getContentResolver().query(Leaderboard.CONTENT_URI, null, - Leaderboard.LEADERBOARD_CHECKIN_DIGEST + " = \"" + checkinDigest + "\"", null, null); + Leaderboard.LEADERBOARD_CHECKIN_DIGEST + " = ?", new String[] { checkinDigest }, null); int count = lc.getCount(); diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/coursedesign/CourseDesignComputer.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/coursedesign/CourseDesignComputer.java index 9bb0fc36265..ee6284b58c1 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/coursedesign/CourseDesignComputer.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/coursedesign/CourseDesignComputer.java @@ -1,9 +1,13 @@ package com.sap.sailing.racecommittee.app.domain.coursedesign; +import android.util.Log; + import com.sap.sailing.domain.common.Bearing; import com.sap.sailing.domain.common.Position; public class CourseDesignComputer { + private static final String TAG = CourseDesignComputer.class.getName(); + private Position startBoatPosition; private Double windSpeed; private Bearing windDirection; @@ -86,10 +90,9 @@ public class CourseDesignComputer { computedCourseDesign = courseLayout.getCourseDesignFactoryClass().newInstance() .createCourseDesign(startBoatPosition, windSpeed, windDirection, boatClass, courseLayout, numberOfRounds, targetTime); } catch (InstantiationException e) { - - e.printStackTrace(); + Log.e(TAG, "Exception trying compute course design", e); } catch (IllegalAccessException e) { - e.printStackTrace(); + Log.e(TAG, "Exception trying compute course design", e); } } else throw new IllegalStateException("At least one mandatory parameter was not set in the computer!"); diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java index be674ce1965..f051b8955c5 100755 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java @@ -346,7 +346,7 @@ public class RacingActivity extends SessionActivity implements RaceInfoListener, RacingActivity.this.startService(registerIntent); } } - }).run(); + }).start(); } public void setProgressSpinnerVisibility(boolean visible) { diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/CameraView.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/CameraView.java index a1c90c2a7ac..a961d4c3525 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/CameraView.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/CameraView.java @@ -60,7 +60,7 @@ public class CameraView extends SurfaceView implements SurfaceHolder.Callback { requestLayout(); camera.startPreview(); } catch (IOException e) { - Log.d(TAG, "Error setting camera preview: " + e.getMessage()); + Log.d(TAG, "Error setting camera preview", e); } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/utils/autoupdate/AutoUpdaterVersionDownloader.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/utils/autoupdate/AutoUpdaterVersionDownloader.java index 741855818b7..29a233b57f9 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/utils/autoupdate/AutoUpdaterVersionDownloader.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/utils/autoupdate/AutoUpdaterVersionDownloader.java @@ -7,12 +7,14 @@ import java.net.URL; import java.nio.charset.Charset; import android.content.Context; +import android.util.Log; import com.sap.sailing.android.shared.data.http.HttpGetRequest; import com.sap.sailing.racecommittee.app.utils.autoupdate.AutoUpdaterChecker.AutoUpdaterState; import com.sap.sse.common.Util; public class AutoUpdaterVersionDownloader extends AutoUpdaterDownloader> { + private final static String TAG = AutoUpdaterVersionDownloader.class.getName(); public AutoUpdaterVersionDownloader(AutoUpdaterState state, Context context) { super(state, context); @@ -29,11 +31,13 @@ public class AutoUpdaterVersionDownloader extends AutoUpdaterDownloader(code, apkFileName); } catch (NumberFormatException e) { + Log.e(TAG, "Exception while trying to parse version from version file"); } } return null; diff --git a/wiki/fortify.md b/wiki/fortify.md new file mode 100644 index 00000000000..825540f47b5 --- /dev/null +++ b/wiki/fortify.md @@ -0,0 +1,30 @@ +# Fortify Security Scans + +During the SAP-internal "I2M" (Idea-to-Market) process all software that will be shipped needs to undergo security validation. A point of contact for security validation is Frank Koehntopp (frank.koehntopp@sap.com). An essential step for security validation is a scan report created using the HP Fortify tool suite. + +We have an internal Wiki page documenting security aspects: [https://wiki.wdf.sap.corp/wiki/display/sailing/Security](https://wiki.wdf.sap.corp/wiki/display/sailing/Security). + +## Scanning Android Apps + +To perform a scan of the Android apps, install the Fortify SCA Eclipse plugin. [https://fortify1.wdf.sap.corp](https://fortify1.wdf.sap.corp) is the link to the Fortify Software Security Center. Installation and configuration is explained here: +[https://jam4.sapjam.com/wiki/show/e3aMSS4m2c078KSre2WfTn#pluginInstallation](https://jam4.sapjam.com/wiki/show/e3aMSS4m2c078KSre2WfTn#pluginInstallation) + +Then, open a Java file from the workspace in Eclipse (yes, Fortify is very sensitive to what is currently selected and opened, and the "HP Fortify" menu shows very different options based on this context which can be highly confusing). Then select "Advanced Scan..." from the "HP Fortify" menu. In the dialog, exclude all bin/, build/, gen/, target/ and tests-* folders in the app projects. Those folder icons should change from yellow to white color, indicating the exclusion rule. Then from the tree select the apps and the ``com.sap.sailing.android.shared`` folders, choose JDK 1.7 from the drop-down and click "Next." In case of repeated scans, select "Merge with previous scans." + +On the next page, say "No" to "Is this a J2EE Web application?" and select "No" for "Does this program run with escalated privileges...?" and click the "Scan" button. + +Be patient, the scan of the apps can last an hour or more. Progress indication is unreliable. When done, the Fortify plug-in will change to the Fortify perspective and show the scan results. Those can be uploaded to the Fortify Software Security Center and may be stored locally as a ``.fpr`` file. + +The project in the Fortify Software Security Center should use the "SAP 3.0" template so that the categories match with the Fortify Eclipse plugin's view. We need to audit all findings in the "Corporate Security Requirements" category, all from "Audit All" and one from each category in the "Spot Checks" tab. + +When done, a report of type "SAP Q-Gate Report" can be generated in the Fortify Software Security Center which, when "green," will be the basis for security validation. + +## Scanning the iOS Boat Tracker App + +A working Xcode development environment on a Mac computer is required to install Fortify there. Alexander Ries (alexander.ries@sap.com) was so kind as to support us in this process. A scan produces the usual ``.fpr`` file and has the code snippets included in the report. The report can be audited as usual, e.g., by loading the .fpr file into an Eclipse Fortify plugin installation, and can then be uploaded again to the Fortify Software Security Center. + +## Scanning the Back-End + +As we participate in the CloudCycle variant of the I2M process, our back-end also is subject to security validation. Scanning it takes too long for running it on a developer's PC, particularly as the workspace should not change really while a scan is running. With scans taking as long as a day or two, leaving a developer's workspace untouched for this long is not an option. + +Therefore, we have a Monsoon instance ``mo-11705429d.mo.sap.corp`` which has an installation of the Fortify software as a Linux command-line set of tools. There is a user ``sailing`` on this machine where under ``/home/sailing/code`` a git workspace exists. This git workspace contains the three scripts ``configuration/RunFortifyClean``, ``configuration/RunFortifyBuild``, and ``configuration/RunFortifyScan`` which should be executed in this order and will produce a new file ``java/com.sap.sailing_scan.fpr`` which can then be used for further processing and auditing. \ No newline at end of file