mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-04 11:23:50 +00:00
Merge branch 'gwt' into gwtracemapdouglas
Conflicts: java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceMapPanel.java
This commit is contained in:
commit
46608a237c
27 files changed
+513
-82
No files matched your search
+9
-9
@@ -7,6 +7,7 @@ import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -19,7 +20,6 @@ import com.sap.sailing.domain.base.impl.DouglasPeucker;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.base.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
@@ -53,18 +53,18 @@ public class ManeuverDetectionOnKielerWoche505Race2DataTest extends KielWeek2011
|
||||
Iterator<MarkPassing> hassosMarkPassingsIter = hassosMarkPassings.iterator();
|
||||
TimePoint startMarkPassing = hassosMarkPassingsIter.next().getTimePoint();
|
||||
TimePoint firstWindwardMarkPassing = hassosMarkPassingsIter.next().getTimePoint();
|
||||
GPSFix[] firstLegFineApproximation = dp.approximate(new MeterDistance(20), startMarkPassing, firstWindwardMarkPassing);
|
||||
List<GPSFixMoving> firstLegFineApproximation = dp.approximate(new MeterDistance(20), startMarkPassing, firstWindwardMarkPassing);
|
||||
assertNotNull(firstLegFineApproximation);
|
||||
assertEquals(9, firstLegFineApproximation.length);
|
||||
GPSFix[] firstLegCoarseApproximation = dp.approximate(new MeterDistance(50), startMarkPassing, firstWindwardMarkPassing);
|
||||
assertEquals(9, firstLegFineApproximation.size());
|
||||
List<GPSFixMoving> firstLegCoarseApproximation = dp.approximate(new MeterDistance(50), startMarkPassing, firstWindwardMarkPassing);
|
||||
assertNotNull(firstLegCoarseApproximation);
|
||||
assertEquals(4, firstLegCoarseApproximation.length);
|
||||
assertEquals(4, firstLegCoarseApproximation.size());
|
||||
TimePoint leewardGatePassing = hassosMarkPassingsIter.next().getTimePoint();
|
||||
GPSFix[] secondLegFineApproximation = dp.approximate(new MeterDistance(20), firstWindwardMarkPassing, leewardGatePassing);
|
||||
List<GPSFixMoving> secondLegFineApproximation = dp.approximate(new MeterDistance(20), firstWindwardMarkPassing, leewardGatePassing);
|
||||
assertNotNull(secondLegFineApproximation);
|
||||
assertEquals(7, secondLegFineApproximation.length);
|
||||
GPSFix[] secondLegCoarseApproximation = dp.approximate(new MeterDistance(50), firstWindwardMarkPassing, leewardGatePassing);
|
||||
assertEquals(7, secondLegFineApproximation.size());
|
||||
List<GPSFixMoving> secondLegCoarseApproximation = dp.approximate(new MeterDistance(50), firstWindwardMarkPassing, leewardGatePassing);
|
||||
assertNotNull(secondLegCoarseApproximation);
|
||||
assertEquals(3, secondLegCoarseApproximation.length);
|
||||
assertEquals(3, secondLegCoarseApproximation.size());
|
||||
}
|
||||
}
|
||||
+7
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.domain.test.mock;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
@@ -405,4 +406,10 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GPSFixMoving> approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,16 @@
|
||||
package com.sap.sailing.domain.base;
|
||||
|
||||
public interface BoatClass extends Named {
|
||||
long getApproximateManeuverDurationInMilliseconds();
|
||||
|
||||
/**
|
||||
* If the averaged courses over ground differ by at least this degree angle, a maneuver will
|
||||
* be assumed. Note that this should be much less than the tack angle because averaging may
|
||||
* span across the actual maneuver.
|
||||
*/
|
||||
double getManeuverDegreeAngleThreshold();
|
||||
|
||||
double getMinimumAngleBetweenDifferentTacksDownwind();
|
||||
|
||||
double getMinimumAngleBetweenDifferentTacksUpwind();
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.sap.sailing.domain.base;
|
||||
|
||||
import com.sap.sailing.domain.tracking.GPSFix;
|
||||
|
||||
/**
|
||||
* A course change happens at a position at a time and may change the course over ground as well as the speed over ground.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface CourseChange extends GPSFix {
|
||||
double getCourseChangeInDegrees();
|
||||
|
||||
double getSpeedChangeInKnots();
|
||||
|
||||
/**
|
||||
* @return the side ({@link Tack#STARBOARD} or {@link Tack#PORT} or <code>null</code>) to which the direction changed
|
||||
*/
|
||||
Tack to();
|
||||
}
|
||||
@@ -2,6 +2,12 @@ package com.sap.sailing.domain.base;
|
||||
|
||||
import com.sap.sailing.domain.base.impl.NauticalMileDistance;
|
||||
|
||||
/**
|
||||
* A distance which can be converted to various units of measure. Can be negative.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface Distance extends Comparable<Distance> {
|
||||
static final Distance NULL = new NauticalMileDistance(0);
|
||||
|
||||
@@ -22,8 +28,9 @@ public interface Distance extends Comparable<Distance> {
|
||||
Distance scale(double factor);
|
||||
|
||||
/**
|
||||
* Computes the (undirected) average speed one has traveled at when passing
|
||||
* this distance in the number of milliseconds specified.
|
||||
* Computes the (undirected) average speed one has traveled at when passing this distance in the number of
|
||||
* milliseconds specified. Sign-sensitive, meaning, e.g., that if this distance is negative and the time is positive
|
||||
* then the resulting speed will be negative.
|
||||
*/
|
||||
Speed inTime(long milliseconds);
|
||||
}
|
||||
@@ -3,6 +3,12 @@ package com.sap.sailing.domain.base;
|
||||
import com.sap.sailing.domain.base.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
|
||||
/**
|
||||
* A speed, convertable in various units of measure. Can be negative.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface Speed extends Comparable<Speed> {
|
||||
final static Speed NULL = new KnotSpeedWithBearingImpl(0, new DegreeBearingImpl(0));
|
||||
|
||||
@@ -16,7 +22,8 @@ public interface Speed extends Comparable<Speed> {
|
||||
|
||||
/**
|
||||
* Traveling at this speed starting at time <code>from</code> until time </code>to</code>, how far have we traveled?
|
||||
* If <code>to</code> is before </code>from</code>, the speed will be applied in reverse.
|
||||
* If <code>to</code> is before </code>from</code>, the speed will be applied in reverse. If this speed has a negative
|
||||
* amount then so will the resulting distance.
|
||||
*/
|
||||
Distance travel(TimePoint from, TimePoint to);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.domain.base;
|
||||
|
||||
|
||||
public interface SpeedWithBearing extends Speed {
|
||||
Bearing getBearing();
|
||||
|
||||
@@ -9,4 +10,6 @@ public interface SpeedWithBearing extends Speed {
|
||||
* applied in reverse.
|
||||
*/
|
||||
Position travelTo(Position pos, TimePoint from, TimePoint to);
|
||||
|
||||
SpeedWithBearing applyCourseChange(CourseChange courseChange);
|
||||
}
|
||||
+30
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.base.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.Bearing;
|
||||
import com.sap.sailing.domain.base.CourseChange;
|
||||
import com.sap.sailing.domain.base.Position;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.TimePoint;
|
||||
@@ -37,4 +38,33 @@ public abstract class AbstractSpeedWithBearingImpl extends AbstractSpeedImpl imp
|
||||
return super.equals(object) && object instanceof SpeedWithBearing
|
||||
&& getBearing().equals(((SpeedWithBearing) object).getBearing());
|
||||
}
|
||||
|
||||
public static CourseChange getCourseChangeRequiredToReach(SpeedWithBearing from, SpeedWithBearing to, Position position, TimePoint timePoint) {
|
||||
double courseChangeInDegrees = to.getBearing().getDegrees() - from.getBearing().getDegrees();
|
||||
if (courseChangeInDegrees < -180.) {
|
||||
courseChangeInDegrees += 360.;
|
||||
} else if (courseChangeInDegrees > 180.) {
|
||||
courseChangeInDegrees -= 360.;
|
||||
}
|
||||
double speedChangeInKnots = to.getKnots() - from.getKnots();
|
||||
return new CourseChangeImpl(courseChangeInDegrees, speedChangeInKnots, position, timePoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing applyCourseChange(CourseChange courseChange) {
|
||||
return applyCourseChange(this, courseChange);
|
||||
}
|
||||
|
||||
public static SpeedWithBearing applyCourseChange(SpeedWithBearing from, CourseChange courseChange) {
|
||||
double newBearingDeg = from.getBearing().getDegrees() + courseChange.getCourseChangeInDegrees();
|
||||
if (newBearingDeg < 0) {
|
||||
newBearingDeg += 360;
|
||||
} else if (newBearingDeg > 360) {
|
||||
newBearingDeg -= 360;
|
||||
}
|
||||
Bearing newBearing = new DegreeBearingImpl(newBearingDeg);
|
||||
double newSpeedInKnots = from.getKnots()+courseChange.getSpeedChangeInKnots();
|
||||
return new KnotSpeedWithBearingImpl(newSpeedInKnots, newBearing);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,9 +3,42 @@ package com.sap.sailing.domain.base.impl;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
|
||||
public class BoatClassImpl extends NamedImpl implements BoatClass {
|
||||
/**
|
||||
* If the averaged courses over ground differ by at least this degree angle, a maneuver will
|
||||
* be assumed. Note that this should be much less than the tack angle because averaging may
|
||||
* span across the actual maneuver.
|
||||
*/
|
||||
private static final double MANEUVER_DEGREE_ANGLE_THRESHOLD = /* minimumDegreeDifference */ 30.;
|
||||
|
||||
private static final double MINIMUM_ANGLE_BETWEEN_DIFFERENT_TACKS_UPWIND = 45.;
|
||||
|
||||
private static final double MINIMUM_ANGLE_BETWEEN_DIFFERENT_TACKS_DOWNWIND = 15.;
|
||||
|
||||
private final long approximateManeuverDurationInMilliseconds;
|
||||
|
||||
public BoatClassImpl(String name) {
|
||||
super(name);
|
||||
approximateManeuverDurationInMilliseconds = 10000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getApproximateManeuverDurationInMilliseconds() {
|
||||
return approximateManeuverDurationInMilliseconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getManeuverDegreeAngleThreshold() {
|
||||
return MANEUVER_DEGREE_ANGLE_THRESHOLD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getMinimumAngleBetweenDifferentTacksUpwind() {
|
||||
return MINIMUM_ANGLE_BETWEEN_DIFFERENT_TACKS_UPWIND;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getMinimumAngleBetweenDifferentTacksDownwind() {
|
||||
return MINIMUM_ANGLE_BETWEEN_DIFFERENT_TACKS_DOWNWIND;
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.sap.sailing.domain.base.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseChange;
|
||||
import com.sap.sailing.domain.base.Position;
|
||||
import com.sap.sailing.domain.base.Tack;
|
||||
import com.sap.sailing.domain.base.TimePoint;
|
||||
import com.sap.sailing.domain.tracking.impl.GPSFixImpl;
|
||||
|
||||
public class CourseChangeImpl extends GPSFixImpl implements CourseChange {
|
||||
private final double courseChangeInDegrees;
|
||||
private final double speedChangeInKnots;
|
||||
|
||||
public CourseChangeImpl(double courseChangeInDegrees, double speedChangeInKnots, Position position, TimePoint timePoint) {
|
||||
super(position, timePoint);
|
||||
this.courseChangeInDegrees = courseChangeInDegrees;
|
||||
this.speedChangeInKnots = speedChangeInKnots;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCourseChangeInDegrees() {
|
||||
return courseChangeInDegrees;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSpeedChangeInKnots() {
|
||||
return speedChangeInKnots;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tack to() {
|
||||
return getCourseChangeInDegrees() > 0 ? Tack.STARBOARD : getCourseChangeInDegrees() < 0 ? Tack.PORT : null;
|
||||
}
|
||||
|
||||
}
|
||||
+22
-13
@@ -1,6 +1,9 @@
|
||||
package com.sap.sailing.domain.base.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.Bearing;
|
||||
import com.sap.sailing.domain.base.Distance;
|
||||
@@ -56,26 +59,32 @@ public class DouglasPeucker<ItemType, FixType extends GPSFix> {
|
||||
* the maximum distance of any fix on the {@link #track} to the approximation is less than
|
||||
* <code>maxDistance</code>.
|
||||
*/
|
||||
public GPSFix[] approximate(Distance maxDistance, TimePoint from, TimePoint to) {
|
||||
GPSFix[] resultWithoutFirstFix = approximateWithoutFirst(maxDistance, from, to);
|
||||
GPSFix[] result = new GPSFix[resultWithoutFirstFix.length+1];
|
||||
result[0] = track.getFirstFixAtOrAfter(from);
|
||||
System.arraycopy(resultWithoutFirstFix, 0, result, 1, resultWithoutFirstFix.length);
|
||||
public List<FixType> approximate(Distance maxDistance, TimePoint from, TimePoint to) {
|
||||
List<FixType> resultWithoutFirstFix = approximateWithoutFirst(maxDistance, from, to);
|
||||
List<FixType> result = new ArrayList<FixType>(resultWithoutFirstFix.size()+1);
|
||||
result.add(track.getFirstFixAtOrAfter(from));
|
||||
for (FixType f : resultWithoutFirstFix) {
|
||||
result.add(f);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private GPSFix[] approximateWithoutFirst(Distance maxDistance, TimePoint from, TimePoint to) {
|
||||
GPSFix[] result;
|
||||
private List<FixType> approximateWithoutFirst(Distance maxDistance, TimePoint from, TimePoint to) {
|
||||
List<FixType> result;
|
||||
Pair<GPSFix, Distance> fixAndDistance = getFixWithGreatestCrossTrackErrorInInterval(from, to);
|
||||
if (fixAndDistance.getB().compareTo(maxDistance) < 0) {
|
||||
// reached desired accuracy for interval from..to
|
||||
result = new GPSFix[] { track.getLastFixAtOrBefore(to) };
|
||||
result = Collections.singletonList(track.getLastFixAtOrBefore(to));
|
||||
} else {
|
||||
GPSFix[] left = approximateWithoutFirst(maxDistance, from, fixAndDistance.getA().getTimePoint());
|
||||
GPSFix[] right = approximateWithoutFirst(maxDistance, fixAndDistance.getA().getTimePoint(), to);
|
||||
result = new GPSFix[left.length+right.length];
|
||||
System.arraycopy(left, 0, result, 0, left.length);
|
||||
System.arraycopy(right, 0, result, left.length, right.length);
|
||||
List<FixType> left = approximateWithoutFirst(maxDistance, from, fixAndDistance.getA().getTimePoint());
|
||||
List<FixType> right = approximateWithoutFirst(maxDistance, fixAndDistance.getA().getTimePoint(), to);
|
||||
result = new ArrayList<FixType>(left.size()+right.size());
|
||||
for (FixType fixFromLeft : left) {
|
||||
result.add(fixFromLeft);
|
||||
}
|
||||
for (FixType fixFromRight : right) {
|
||||
result.add(fixFromRight);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+6
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.base.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.Bearing;
|
||||
import com.sap.sailing.domain.base.CourseChange;
|
||||
import com.sap.sailing.domain.base.Position;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.TimePoint;
|
||||
@@ -23,6 +24,11 @@ public class KilometersPerHourSpeedWithBearingImpl extends KilometersPerHourSpee
|
||||
return pos.translateGreatCircle(getBearing(), this.travel(from, to));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing applyCourseChange(CourseChange courseChange) {
|
||||
return AbstractSpeedWithBearingImpl.applyCourseChange(this, courseChange);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()+" to "+getBearing().getDegrees()+"°";
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
package com.sap.sailing.domain.tracking;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseChange;
|
||||
import com.sap.sailing.domain.base.Moving;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
|
||||
public interface GPSFixMoving extends GPSFix, Moving {
|
||||
/**
|
||||
* Computes the minimal (in terms of bearing change) course and speed change required to reach the
|
||||
* target speed and bearing specified.
|
||||
*/
|
||||
CourseChange getCourseChangeRequiredToReach(SpeedWithBearing targetSpeedWithBearing);
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.sap.sailing.domain.tracking;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.Timed;
|
||||
|
||||
public interface Maneuver extends Timed, Positioned {
|
||||
enum Type { HEAD_UP, BEAR_AWAY, TACK, JIBE, PENALTY_CIRCLE }
|
||||
|
||||
Type getType();
|
||||
|
||||
SpeedWithBearing getSpeedWithBearingBefore();
|
||||
|
||||
SpeedWithBearing getSpeedWithBearingAfter();
|
||||
|
||||
double getDirectionChangeInDegrees();
|
||||
|
||||
/**
|
||||
* This assumes that a maneuver usually slows a boat down. This method tries to find out how long
|
||||
* after the {@link #getTimePoint() time of the maneuver} it took for the boat to reach a roughly
|
||||
* constant speed again.
|
||||
*/
|
||||
long getTimeInMillisecondsUntilBackToConstantSpeed();
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.domain.tracking;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import com.sap.sailing.domain.base.Buoy;
|
||||
@@ -12,6 +13,7 @@ import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Tack;
|
||||
import com.sap.sailing.domain.base.TimePoint;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.DouglasPeucker;
|
||||
|
||||
/**
|
||||
* Live tracking data of a single race. The race follows a defined {@link Course} with a sequence of {@link Leg}s. The
|
||||
@@ -206,4 +208,11 @@ public interface TrackedRace {
|
||||
TrackedEvent getTrackedEvent();
|
||||
|
||||
Wind getDirectionFromStartToNextMark(TimePoint at);
|
||||
|
||||
/**
|
||||
* Uses a {@link DouglasPeucker Douglas-Peucker} algorithm to approximate this track's fixes starting at
|
||||
* time <code>from</code> until time point <code>to</code> such that the maximum distance between the
|
||||
* track's fixes and the approximation is at most <code>maxDistance</code>.
|
||||
*/
|
||||
List<GPSFixMoving> approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to);
|
||||
}
|
||||
+12
@@ -1,11 +1,13 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.Bearing;
|
||||
import com.sap.sailing.domain.base.CourseChange;
|
||||
import com.sap.sailing.domain.base.Position;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.TimePoint;
|
||||
import com.sap.sailing.domain.base.impl.AbstractBearing;
|
||||
import com.sap.sailing.domain.base.impl.AbstractSpeedImpl;
|
||||
import com.sap.sailing.domain.base.impl.AbstractSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
|
||||
/**
|
||||
@@ -37,6 +39,11 @@ public class CompactGPSFixMovingImpl extends CompactGPSFixImpl implements GPSFix
|
||||
return pos.translateGreatCircle(getBearing(), this.travel(from, to));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing applyCourseChange(CourseChange courseChange) {
|
||||
return AbstractSpeedWithBearingImpl.applyCourseChange(this, courseChange);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()+" to "+getBearing().getDegrees()+"°";
|
||||
@@ -80,6 +87,11 @@ public class CompactGPSFixMovingImpl extends CompactGPSFixImpl implements GPSFix
|
||||
return new CompactSpeedWithBearing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseChange getCourseChangeRequiredToReach(SpeedWithBearing targetSpeedWithBearing) {
|
||||
return AbstractSpeedWithBearingImpl.getCourseChangeRequiredToReach(getSpeed(), targetSpeedWithBearing, getPosition(), getTimePoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " with " + getSpeed();
|
||||
|
||||
+5
@@ -5,6 +5,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseChange;
|
||||
import com.sap.sailing.domain.base.Position;
|
||||
import com.sap.sailing.domain.base.Speed;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
@@ -121,6 +122,10 @@ public class DynamicGPSFixMovingTrackImpl<ItemType> extends DynamicTrackImpl<Ite
|
||||
public SpeedWithBearing getSpeed() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public CourseChange getCourseChangeRequiredToReach(SpeedWithBearing targetSpeedWithBearing) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
@@ -280,4 +280,5 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
|
||||
public DynamicTrackedEvent getTrackedEvent() {
|
||||
return (DynamicTrackedEvent) super.getTrackedEvent();
|
||||
}
|
||||
|
||||
}
|
||||
+7
@@ -1,8 +1,10 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseChange;
|
||||
import com.sap.sailing.domain.base.Position;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.TimePoint;
|
||||
import com.sap.sailing.domain.base.impl.AbstractSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
|
||||
public class GPSFixMovingImpl extends GPSFixImpl implements GPSFixMoving {
|
||||
@@ -32,4 +34,9 @@ public class GPSFixMovingImpl extends GPSFixImpl implements GPSFixMoving {
|
||||
public boolean equals(Object other) {
|
||||
return super.equals(other) && other instanceof GPSFixMoving && getSpeed().equals(((GPSFixMoving) other).getSpeed());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseChange getCourseChangeRequiredToReach(SpeedWithBearing targetSpeedWithBearing) {
|
||||
return AbstractSpeedWithBearingImpl.getCourseChangeRequiredToReach(getSpeed(), targetSpeedWithBearing, getPosition(), getTimePoint());
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.Position;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.TimePoint;
|
||||
import com.sap.sailing.domain.tracking.Maneuver;
|
||||
|
||||
public class ManeuverImpl implements Maneuver {
|
||||
private final Type type;
|
||||
private final Position position;
|
||||
private final TimePoint timePoint;
|
||||
private final SpeedWithBearing speedWithBearingBefore;
|
||||
private final SpeedWithBearing speedWithBearingAfter;
|
||||
private final long timeInMillisecondsUntilBackToConstantSpeed;
|
||||
private final double directionChangeInDegrees;
|
||||
|
||||
public ManeuverImpl(Type type, Position position, TimePoint timePoint, SpeedWithBearing speedWithBearingBefore,
|
||||
SpeedWithBearing speedWithBearingAfter, long timeInMillisecondsUntilBackToConstantSpeed, double directionChangeInDegrees) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.position = position;
|
||||
this.timePoint = timePoint;
|
||||
this.speedWithBearingBefore = speedWithBearingBefore;
|
||||
this.speedWithBearingAfter = speedWithBearingAfter;
|
||||
this.timeInMillisecondsUntilBackToConstantSpeed = timeInMillisecondsUntilBackToConstantSpeed;
|
||||
this.directionChangeInDegrees = directionChangeInDegrees;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeInMillisecondsUntilBackToConstantSpeed() {
|
||||
return timeInMillisecondsUntilBackToConstantSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getTimePoint() {
|
||||
return timePoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getSpeedWithBearingBefore() {
|
||||
return speedWithBearingBefore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getSpeedWithBearingAfter() {
|
||||
return speedWithBearingAfter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDirectionChangeInDegrees() {
|
||||
return directionChangeInDegrees;
|
||||
}
|
||||
|
||||
}
|
||||
+67
-14
@@ -12,8 +12,10 @@ import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.Bearing;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Buoy;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CourseChange;
|
||||
import com.sap.sailing.domain.base.CourseListener;
|
||||
import com.sap.sailing.domain.base.Distance;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
@@ -23,11 +25,13 @@ import com.sap.sailing.domain.base.Tack;
|
||||
import com.sap.sailing.domain.base.TimePoint;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.base.impl.DouglasPeucker;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.Maneuver;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.NoWindError;
|
||||
import com.sap.sailing.domain.tracking.NoWindException;
|
||||
@@ -43,19 +47,8 @@ import com.sap.sailing.domain.tracking.WindTrack;
|
||||
import com.sap.sailing.util.Util;
|
||||
|
||||
public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
/**
|
||||
* If the averaged courses over ground differ by at least this degree angle, a maneuver will
|
||||
* be assumed. Note that this should be much less than the tack angle because averaging may
|
||||
* span across the actual maneuver.
|
||||
*/
|
||||
private static final double MANEUVER_DEGREE_ANGLE_THRESHOLD = /* minimumDegreeDifference */ 30.;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TrackedRaceImpl.class.getName());
|
||||
|
||||
// TODO make typical tack/jibe angles and the respective clustering thresholds a boat class parameter
|
||||
private static final double MINIMUM_ANGLE_BETWEEN_DIFFERENT_TACKS_UPWIND = 45.;
|
||||
private static final double MINIMUM_ANGLE_BETWEEN_DIFFERENT_TACKS_DOWNWIND = 15.;
|
||||
|
||||
// TODO observe the race course; if it changes, update leg structures; consider fine-grained update events that tell what changed
|
||||
private final RaceDefinition race;
|
||||
|
||||
@@ -562,7 +555,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
LegType legType = trackedLeg.getLegType(timePoint);
|
||||
if (legType != LegType.REACHING) {
|
||||
GPSFixTrack<Competitor, GPSFixMoving> track = getTrack(competitor);
|
||||
if (!track.hasDirectionChange(timePoint, MANEUVER_DEGREE_ANGLE_THRESHOLD)) {
|
||||
if (!track.hasDirectionChange(timePoint, getManeuverDegreeAngleThreshold())) {
|
||||
Bearing bearing = track.getEstimatedSpeed(timePoint).getBearing();
|
||||
BearingCluster bearingClusters = bearings.get(legType);
|
||||
bearingClusters.add(bearing);
|
||||
@@ -571,12 +564,12 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
}
|
||||
}
|
||||
Bearing upwindAverage = null;
|
||||
BearingCluster[] bearingClustersUpwind = bearings.get(LegType.UPWIND).splitInTwo(MINIMUM_ANGLE_BETWEEN_DIFFERENT_TACKS_UPWIND);
|
||||
BearingCluster[] bearingClustersUpwind = bearings.get(LegType.UPWIND).splitInTwo(getMinimumAngleBetweenDifferentTacksUpwind());
|
||||
if (!bearingClustersUpwind[0].isEmpty() && !bearingClustersUpwind[1].isEmpty()) {
|
||||
upwindAverage = bearingClustersUpwind[0].getAverage().middle(bearingClustersUpwind[1].getAverage());
|
||||
}
|
||||
Bearing downwindAverage = null;
|
||||
BearingCluster[] bearingClustersDownwind = bearings.get(LegType.DOWNWIND).splitInTwo(MINIMUM_ANGLE_BETWEEN_DIFFERENT_TACKS_DOWNWIND);
|
||||
BearingCluster[] bearingClustersDownwind = bearings.get(LegType.DOWNWIND).splitInTwo(getMinimumAngleBetweenDifferentTacksDownwind());
|
||||
if (!bearingClustersDownwind[0].isEmpty() && !bearingClustersDownwind[1].isEmpty()) {
|
||||
downwindAverage = bearingClustersDownwind[0].getAverage().middle(bearingClustersDownwind[1].getAverage());
|
||||
}
|
||||
@@ -633,4 +626,64 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
public String toString() {
|
||||
return "TrackedRace for "+getRace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GPSFixMoving> approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to) {
|
||||
DouglasPeucker<Competitor, GPSFixMoving> douglasPeucker = new DouglasPeucker<Competitor, GPSFixMoving>(getTrack(competitor));
|
||||
return douglasPeucker.approximate(maxDistance, from, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to detect a maneuver on the <code>competitor</code>'s track around a given time point. The time period is
|
||||
* taken from the {@link BoatClass#getApproximateManeuverDurationInMilliseconds() boat class}. If no maneuver is
|
||||
* detected, an empty list is returned. Maneuvers can only be expected to be detected if at least two fixes are
|
||||
* provided in <code>approximatedFixesToAnalyze</code> that have their {@link GPSFixMoving#getSpeed() speed and
|
||||
* bearing} propertly set.
|
||||
*
|
||||
* @return an empty list if no maneuver is detected for <code>competitor</code> between <code>from</code> and
|
||||
* <code>to</code>, or else the list of maneuvers detected.
|
||||
*/
|
||||
private List<Maneuver> detectManeuvers(Competitor competitor, List<GPSFixMoving> approximatedFixesToAnalyze) {
|
||||
List<Maneuver> result = new ArrayList<Maneuver>();
|
||||
if (approximatedFixesToAnalyze.size() > 2) {
|
||||
List<CourseChange> courseChangeSequenceInSameDirection = new ArrayList<CourseChange>();
|
||||
Iterator<GPSFixMoving> iter = approximatedFixesToAnalyze.iterator();
|
||||
GPSFixMoving current = iter.next();
|
||||
while (iter.hasNext()) {
|
||||
GPSFixMoving previous = current;
|
||||
current = iter.next();
|
||||
CourseChange courseChange = previous.getCourseChangeRequiredToReach(current.getSpeed());
|
||||
if (courseChangeSequenceInSameDirection.isEmpty() || courseChangeSequenceInSameDirection.get(0).to() == courseChange.to()) {
|
||||
courseChangeSequenceInSameDirection.add(courseChange);
|
||||
} else {
|
||||
// course change in different direction; cluster the course changes in same direction so far, then start new list
|
||||
List<Maneuver> maneuver = summarizeDirectionChangesIntoManeuvers(courseChangeSequenceInSameDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO first group fixes into sequences of direction changes in the same direction
|
||||
// TODO implement detectManeuvers
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Maneuver> summarizeDirectionChangesIntoManeuvers(List<CourseChange> courseChangeSequenceInSameDirection) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the boat class-specific parameter
|
||||
*/
|
||||
private double getManeuverDegreeAngleThreshold() {
|
||||
return getRace().getBoatClass().getManeuverDegreeAngleThreshold();
|
||||
}
|
||||
|
||||
private double getMinimumAngleBetweenDifferentTacksDownwind() {
|
||||
return getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksDownwind();
|
||||
}
|
||||
|
||||
private double getMinimumAngleBetweenDifferentTacksUpwind() {
|
||||
return getRace().getBoatClass().getMinimumAngleBetweenDifferentTacksUpwind();
|
||||
}
|
||||
|
||||
}
|
||||
+5
@@ -8,6 +8,7 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.Bearing;
|
||||
import com.sap.sailing.domain.base.CourseChange;
|
||||
import com.sap.sailing.domain.base.Distance;
|
||||
import com.sap.sailing.domain.base.Position;
|
||||
import com.sap.sailing.domain.base.Speed;
|
||||
@@ -249,6 +250,10 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
|
||||
public double getBeaufort() {
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public SpeedWithBearing applyCourseChange(CourseChange courseChange) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+16
-11
@@ -33,8 +33,9 @@ public class LeaderboardConfigPanel extends FormPanel implements EventDisplayer,
|
||||
|
||||
private static final int MAX_NUMBER_OF_DISCARDED_RESULTS = 4;
|
||||
|
||||
private final RaceTreeView raceTree;
|
||||
|
||||
// private final RaceTreeView raceTree;
|
||||
private final TrackedEventsComposite trackedEventsComposite;
|
||||
|
||||
private final StringConstants stringConstants;
|
||||
|
||||
private final SailingServiceAsync sailingService;
|
||||
@@ -190,9 +191,13 @@ public class LeaderboardConfigPanel extends FormPanel implements EventDisplayer,
|
||||
VerticalPanel labelAndTreePanel = new VerticalPanel();
|
||||
Label lblTrackedRaceConnected = new Label(stringConstants.trackedRaceConnectedToSelectedRaceName());
|
||||
labelAndTreePanel.add(lblTrackedRaceConnected);
|
||||
raceTree = new RaceTreeView(stringConstants, /* multiselection */ false);
|
||||
labelAndTreePanel.add(raceTree);
|
||||
raceTree.addRaceSelectionChangeListener(this);
|
||||
|
||||
trackedEventsComposite = new TrackedEventsComposite(sailingService, errorReporter, adminConsole,
|
||||
stringConstants, /* multiselection */ false);
|
||||
|
||||
// raceTree = new RaceTreeView(stringConstants, /* multiselection */ false);
|
||||
labelAndTreePanel.add(trackedEventsComposite);
|
||||
trackedEventsComposite.addRaceSelectionChangeListener(this);
|
||||
selectedLeaderboardPanel.add(labelAndTreePanel);
|
||||
|
||||
VerticalPanel buttonPanelForSelectedLeaderboardDetails = new VerticalPanel();
|
||||
@@ -284,7 +289,7 @@ public class LeaderboardConfigPanel extends FormPanel implements EventDisplayer,
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void arg0) {
|
||||
raceTree.clearSelection();
|
||||
trackedEventsComposite.clearSelection();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -442,7 +447,7 @@ public class LeaderboardConfigPanel extends FormPanel implements EventDisplayer,
|
||||
columnRemoveButton.setEnabled(false);
|
||||
columnMoveUpButton.setEnabled(false);
|
||||
columnMoveDownButton.setEnabled(false);
|
||||
raceTree.clearSelection();
|
||||
trackedEventsComposite.clearSelection();
|
||||
unlinkRaceColumnFromTrackedRaceButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
@@ -464,14 +469,14 @@ public class LeaderboardConfigPanel extends FormPanel implements EventDisplayer,
|
||||
if (eventAndRaceName != null) {
|
||||
selectRaceInTree(eventAndRaceName.getA(), eventAndRaceName.getB());
|
||||
} else {
|
||||
raceTree.clearSelection();
|
||||
trackedEventsComposite.clearSelection();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void selectRaceInTree(String eventName, String raceName) {
|
||||
raceTree.selectRaceByName(eventName, raceName);
|
||||
trackedEventsComposite.selectRaceByName(eventName, raceName);
|
||||
}
|
||||
|
||||
private String getSelectedRaceColumnName() {
|
||||
@@ -661,7 +666,7 @@ public class LeaderboardConfigPanel extends FormPanel implements EventDisplayer,
|
||||
|
||||
@Override
|
||||
public void fillEvents(List<EventDAO> result) {
|
||||
raceTree.fillEvents(result);
|
||||
trackedEventsComposite.fillEvents(result);
|
||||
}
|
||||
|
||||
private void addNewLeaderboard() {
|
||||
@@ -750,7 +755,7 @@ public class LeaderboardConfigPanel extends FormPanel implements EventDisplayer,
|
||||
+ " of event " + selectedRace.getA().name + " to race column named "
|
||||
+ getSelectedRaceColumnName() + " of leaderboard " + getSelectedLeaderboardName()
|
||||
+ ": " + t.getMessage());
|
||||
raceTree.clearSelection();
|
||||
trackedEventsComposite.clearSelection();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -766,7 +766,7 @@ public class RaceMapPanel extends FormPanel implements EventDisplayer, TimeListe
|
||||
Map<CompetitorDAO, Date> to = new HashMap<CompetitorDAO, Date>();
|
||||
to.put(competitorDAO, fixes.get(competitorDAO).get(lastShownFix.get(competitorDAO)).timepoint);
|
||||
sailingService.getDouglasPoints(event.name, race.name, from, to, /* epsilon/meters */5,
|
||||
new AsyncCallback<Map<CompetitorDAO, List<GPSFixDAO>>>() {
|
||||
to, /* epsilon/meters */ 3, new AsyncCallback<Map<CompetitorDAO, List<GPSFixDAO>>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Error obtaining douglas positions: " + caught.getMessage());
|
||||
|
||||
+48
-8
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.gwt.ui.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -10,6 +11,8 @@ import com.google.gwt.event.dom.client.ChangeEvent;
|
||||
import com.google.gwt.event.dom.client.ChangeHandler;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.event.dom.client.KeyUpEvent;
|
||||
import com.google.gwt.event.dom.client.KeyUpHandler;
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
|
||||
import com.google.gwt.text.client.DateTimeFormatRenderer;
|
||||
@@ -24,6 +27,7 @@ import com.google.gwt.user.client.ui.CaptionPanel;
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.FormPanel;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.HasVerticalAlignment;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.IntegerBox;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
@@ -54,6 +58,7 @@ public class SwissTimingEventManagementPanel extends FormPanel implements EventD
|
||||
private final ErrorReporter errorReporter;
|
||||
private final IntegerBox portIntegerbox;
|
||||
private final TextBox hostnameTextbox;
|
||||
private final TextBox filterEventsTextbox;
|
||||
private final ListDataProvider<SwissTimingRaceRecordDAO> raceList;
|
||||
private final CellTable<SwissTimingRaceRecordDAO> raceTable;
|
||||
private final Map<String, SwissTimingConfigurationDAO> previousConfigurations;
|
||||
@@ -61,7 +66,8 @@ public class SwissTimingEventManagementPanel extends FormPanel implements EventD
|
||||
private final TrackedEventsComposite trackedEventsComposite;
|
||||
private final EventRefresher eventRefresher;
|
||||
private final CheckBox canSendRequestsCheckbox;
|
||||
private DateTimeFormatRenderer dateFormatter = new DateTimeFormatRenderer(DateTimeFormat.getFormat(PredefinedFormat.DATE_TIME_LONG));
|
||||
private final DateTimeFormatRenderer dateFormatter = new DateTimeFormatRenderer(DateTimeFormat.getFormat(PredefinedFormat.DATE_TIME_LONG));
|
||||
private final List<SwissTimingRaceRecordDAO> availableSwissTimingRaces = new ArrayList<SwissTimingRaceRecordDAO>();
|
||||
|
||||
public SwissTimingEventManagementPanel(final SailingServiceAsync sailingService, ErrorReporter errorReporter,
|
||||
EventRefresher eventRefresher, StringConstants stringConstants) {
|
||||
@@ -176,7 +182,40 @@ public class SwissTimingEventManagementPanel extends FormPanel implements EventD
|
||||
trackedRacesPanel.setWidth("100%");
|
||||
trackedRacesCaptionPanel.setContentWidget(trackedRacesPanel);
|
||||
trackedRacesCaptionPanel.setStyleName("bold");
|
||||
|
||||
// text box for filtering the cell table
|
||||
HorizontalPanel filterPanel = new HorizontalPanel();
|
||||
filterPanel.setSpacing(5);
|
||||
racesPanel.add(filterPanel);
|
||||
|
||||
Label lblFilterEvents = new Label("Filter races by name:");
|
||||
filterPanel.add(lblFilterEvents);
|
||||
filterPanel.setCellVerticalAlignment(lblFilterEvents, HasVerticalAlignment.ALIGN_MIDDLE);
|
||||
|
||||
filterEventsTextbox = new TextBox();
|
||||
filterEventsTextbox.addKeyUpHandler(new KeyUpHandler() {
|
||||
@Override
|
||||
public void onKeyUp(KeyUpEvent event) {
|
||||
String text = filterEventsTextbox.getText();
|
||||
|
||||
raceList.getList().clear();
|
||||
|
||||
if(text == null || text.isEmpty()) {
|
||||
raceList.getList().addAll(availableSwissTimingRaces);
|
||||
} else {
|
||||
String textAsUppercase = text.toUpperCase();
|
||||
for(SwissTimingRaceRecordDAO dao: availableSwissTimingRaces) {
|
||||
if(dao.ID != null) {
|
||||
if(dao.ID.toUpperCase().contains(textAsUppercase))
|
||||
raceList.getList().add(dao);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
filterPanel.add(filterEventsTextbox);
|
||||
|
||||
HorizontalPanel racesHorizontalPanel = new HorizontalPanel();
|
||||
racesPanel.add(racesHorizontalPanel);
|
||||
|
||||
@@ -214,9 +253,6 @@ public class SwissTimingEventManagementPanel extends FormPanel implements EventD
|
||||
declinationCheckbox.setValue(true);
|
||||
trackPanel.add(declinationCheckbox);
|
||||
|
||||
// trackedRacesTreeView = new RaceTreeView(stringConstants, /* multiselection */ true);
|
||||
// trackedRacesPanel.add(trackedRacesTreeView);
|
||||
|
||||
trackedEventsComposite = new TrackedEventsComposite(sailingService, errorReporter, eventRefresher,
|
||||
stringConstants, /* multiselection */ true);
|
||||
trackedRacesPanel.add(trackedEventsComposite);
|
||||
@@ -295,10 +331,15 @@ public class SwissTimingEventManagementPanel extends FormPanel implements EventD
|
||||
|
||||
@Override
|
||||
public void onSuccess(final List<SwissTimingRaceRecordDAO> result) {
|
||||
availableSwissTimingRaces.clear();
|
||||
if (result != null)
|
||||
availableSwissTimingRaces.addAll(result);
|
||||
|
||||
raceList.getList().clear();
|
||||
if (result != null) {
|
||||
raceList.getList().addAll(result);
|
||||
}
|
||||
raceList.getList().addAll(availableSwissTimingRaces);
|
||||
|
||||
filterEventsTextbox.setText(null);
|
||||
|
||||
// store a successful configuration in the database for later retrieval
|
||||
final String configName = hostname+":"+port;
|
||||
sailingService.storeSwissTimingConfiguration(configName, hostname, port, canSendRequests,
|
||||
@@ -359,7 +400,6 @@ public class SwissTimingEventManagementPanel extends FormPanel implements EventD
|
||||
|
||||
@Override
|
||||
public void fillEvents(List<EventDAO> result) {
|
||||
// trackedRacesTreeView.fillEvents(result);
|
||||
trackedEventsComposite.fillEvents(result);
|
||||
}
|
||||
|
||||
|
||||
+47
-10
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.gwt.ui.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -63,16 +64,17 @@ public class TracTracEventManagementPanel extends FormPanel implements EventDisp
|
||||
private final IntegerBox livePortIntegerbox;
|
||||
private final TextBox hostnameTextbox;
|
||||
private final TextBox eventNameTextbox;
|
||||
private final TextBox filterEventsTextbox;
|
||||
private final ListDataProvider<TracTracRaceRecordDAO> raceList;
|
||||
private final CellTable<TracTracRaceRecordDAO> raceTable;
|
||||
private final Map<String, TracTracConfigurationDAO> previousConfigurations;
|
||||
private final ListBox previousConfigurationsComboBox;
|
||||
private final Grid grid;
|
||||
// private final RaceTreeView trackedRacesTreeView;
|
||||
private final TrackedEventsComposite trackedEventsComposite;
|
||||
private final EventRefresher eventRefresher;
|
||||
private DateTimeFormatRenderer dateFormatter = new DateTimeFormatRenderer(DateTimeFormat.getFormat(PredefinedFormat.DATE_TIME_LONG));
|
||||
|
||||
private final DateTimeFormatRenderer dateFormatter = new DateTimeFormatRenderer(DateTimeFormat.getFormat(PredefinedFormat.DATE_TIME_LONG));
|
||||
private final List<TracTracRaceRecordDAO> availableTracTracRaces = new ArrayList<TracTracRaceRecordDAO>();
|
||||
|
||||
public TracTracEventManagementPanel(final SailingServiceAsync sailingService, ErrorReporter errorReporter,
|
||||
EventRefresher eventRefresher, StringConstants stringConstants) {
|
||||
this.sailingService = sailingService;
|
||||
@@ -273,13 +275,46 @@ public class TracTracEventManagementPanel extends FormPanel implements EventDisp
|
||||
trackedRacesPanel.setWidth("100%");
|
||||
trackedRacesCaptionPanel.setContentWidget(trackedRacesPanel);
|
||||
trackedRacesCaptionPanel.setStyleName("bold");
|
||||
|
||||
// text box for filtering the cell table
|
||||
HorizontalPanel filterPanel = new HorizontalPanel();
|
||||
filterPanel.setSpacing(5);
|
||||
racesPanel.add(filterPanel);
|
||||
|
||||
Label lblFilterEvents = new Label("Filter races by name:");
|
||||
filterPanel.add(lblFilterEvents);
|
||||
filterPanel.setCellVerticalAlignment(lblFilterEvents, HasVerticalAlignment.ALIGN_MIDDLE);
|
||||
|
||||
filterEventsTextbox = new TextBox();
|
||||
filterEventsTextbox.addKeyUpHandler(new KeyUpHandler() {
|
||||
@Override
|
||||
public void onKeyUp(KeyUpEvent event) {
|
||||
String text = filterEventsTextbox.getText();
|
||||
|
||||
raceList.getList().clear();
|
||||
|
||||
if(text == null || text.isEmpty()) {
|
||||
raceList.getList().addAll(availableTracTracRaces);
|
||||
} else {
|
||||
String textAsUppercase = text.toUpperCase();
|
||||
for(TracTracRaceRecordDAO dao: availableTracTracRaces) {
|
||||
if(dao.name != null) {
|
||||
if(dao.name.toUpperCase().contains(textAsUppercase))
|
||||
raceList.getList().add(dao);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
filterPanel.add(filterEventsTextbox);
|
||||
|
||||
HorizontalPanel racesHorizontalPanel = new HorizontalPanel();
|
||||
racesPanel.add(racesHorizontalPanel);
|
||||
|
||||
VerticalPanel trackPanel = new VerticalPanel();
|
||||
trackPanel.setStyleName("paddedPanel");
|
||||
|
||||
|
||||
raceNameColumn.setSortable(true);
|
||||
raceStartTrackingColumn.setSortable(true);
|
||||
|
||||
@@ -312,9 +347,6 @@ public class TracTracEventManagementPanel extends FormPanel implements EventDisp
|
||||
declinationCheckbox.setValue(true);
|
||||
trackPanel.add(declinationCheckbox);
|
||||
|
||||
// trackedRacesTreeView = new RaceTreeView(stringConstants, /* multiselection */ true);
|
||||
// trackedRacesPanel.add(trackedRacesTreeView);
|
||||
|
||||
trackedEventsComposite = new TrackedEventsComposite(sailingService, errorReporter, eventRefresher,
|
||||
stringConstants, /* multiselection */ true);
|
||||
trackedRacesPanel.add(trackedEventsComposite);
|
||||
@@ -411,10 +443,15 @@ public class TracTracEventManagementPanel extends FormPanel implements EventDisp
|
||||
|
||||
@Override
|
||||
public void onSuccess(final Pair<String, List<TracTracRaceRecordDAO>> result) {
|
||||
availableTracTracRaces.clear();
|
||||
if (result.getB() != null)
|
||||
availableTracTracRaces.addAll(result.getB());
|
||||
|
||||
raceList.getList().clear();
|
||||
if (result.getB() != null) {
|
||||
raceList.getList().addAll(result.getB());
|
||||
}
|
||||
raceList.getList().addAll(availableTracTracRaces);
|
||||
|
||||
filterEventsTextbox.setText(null);
|
||||
|
||||
// store a successful configuration in the database for later retrieval
|
||||
sailingService.storeTracTracConfiguration(result.getA(), jsonURL, liveDataURI, storedDataURI,
|
||||
new AsyncCallback<Void>() {
|
||||
|
||||
+7
-13
@@ -40,7 +40,6 @@ import com.sap.sailing.domain.base.TimePoint;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.base.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.base.impl.DouglasPeucker;
|
||||
import com.sap.sailing.domain.base.impl.KilometersPerHourSpeedImpl;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
@@ -1117,28 +1116,23 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
|
||||
Map<CompetitorDAO, Date> from, Map<CompetitorDAO, Date> to,
|
||||
double meters) {
|
||||
Map<CompetitorDAO, List<GPSFixDAO>> result = new HashMap<CompetitorDAO, List<GPSFixDAO>>();
|
||||
Event event = getService().getEventByName(eventName);
|
||||
RaceDefinition race = getRaceByName(event, raceName);
|
||||
TrackedRace trackedRace = getService().getOrCreateTrackedEvent(event).getTrackedRace(race);
|
||||
TrackedRace trackedRace = getTrackedRace(eventName, raceName);
|
||||
MeterDistance maxDistance = new MeterDistance(meters);
|
||||
for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
|
||||
CompetitorDAO competitorDAO = getCompetitorDAO(competitor);
|
||||
if (from.containsKey(competitorDAO)) {
|
||||
// get Track of competitor
|
||||
GPSFixTrack<Competitor, GPSFixMoving> gpsFixTrack = getTrackedRace(eventName, raceName).getTrack(
|
||||
competitor);
|
||||
DouglasPeucker<Competitor, GPSFixMoving> douglas = new DouglasPeucker<Competitor, GPSFixMoving>(
|
||||
gpsFixTrack);
|
||||
GPSFixTrack<Competitor, GPSFixMoving> gpsFixTrack = trackedRace.getTrack(competitor);
|
||||
// Distance for DouglasPeucker
|
||||
TimePoint timePointFrom = new MillisecondsTimePoint(from.get(competitorDAO));
|
||||
TimePoint timePointTo = new MillisecondsTimePoint(to.get(competitorDAO));
|
||||
GPSFix[] gpsFixDouglas = douglas.approximate(maxDistance, timePointFrom, timePointTo);
|
||||
List<GPSFixMoving> gpsFixApproximation = trackedRace.approximate(competitor, maxDistance, timePointFrom, timePointTo);
|
||||
List<GPSFixDAO> gpsFixDouglasList = new ArrayList<GPSFixDAO>();
|
||||
for (int i = 0; i < gpsFixDouglas.length; i++) {
|
||||
GPSFix fix = gpsFixDouglas[i];
|
||||
for (int i = 0; i < gpsFixApproximation.size(); i++) {
|
||||
GPSFix fix = gpsFixApproximation.get(i);
|
||||
SpeedWithBearing speedWithBearing;
|
||||
if (i<gpsFixDouglas.length-1) {
|
||||
GPSFix next = gpsFixDouglas[i+1];
|
||||
if (i<gpsFixApproximation.size()-1) {
|
||||
GPSFix next = gpsFixApproximation.get(i+1);
|
||||
Bearing bearing = fix.getPosition().getBearingGreatCircle(next.getPosition());
|
||||
Speed speed = fix.getPosition().getDistance(next.getPosition()).inTime(
|
||||
next.getTimePoint().asMillis()-fix.getTimePoint().asMillis());
|
||||
|
||||
Reference in new issue
Block a user