diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ManeuverDetectionOnKielerWoche505Race2DataTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ManeuverDetectionOnKielerWoche505Race2DataTest.java index b14e7195d2d..db9fa3c54b4 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ManeuverDetectionOnKielerWoche505Race2DataTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ManeuverDetectionOnKielerWoche505Race2DataTest.java @@ -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 hassosMarkPassingsIter = hassosMarkPassings.iterator(); TimePoint startMarkPassing = hassosMarkPassingsIter.next().getTimePoint(); TimePoint firstWindwardMarkPassing = hassosMarkPassingsIter.next().getTimePoint(); - GPSFix[] firstLegFineApproximation = dp.approximate(new MeterDistance(20), startMarkPassing, firstWindwardMarkPassing); + List 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 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 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 secondLegCoarseApproximation = dp.approximate(new MeterDistance(50), firstWindwardMarkPassing, leewardGatePassing); assertNotNull(secondLegCoarseApproximation); - assertEquals(3, secondLegCoarseApproximation.length); + assertEquals(3, secondLegCoarseApproximation.size()); } } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java index 2b64d4698b7..e4df0e1d233 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java @@ -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 approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DouglasPeucker.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DouglasPeucker.java index cf8b4ad68e8..a1dc6d6df6f 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DouglasPeucker.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DouglasPeucker.java @@ -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 { * the maximum distance of any fix on the {@link #track} to the approximation is less than * maxDistance. */ - 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 approximate(Distance maxDistance, TimePoint from, TimePoint to) { + List resultWithoutFirstFix = approximateWithoutFirst(maxDistance, from, to); + List result = new ArrayList(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 approximateWithoutFirst(Distance maxDistance, TimePoint from, TimePoint to) { + List result; Pair 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 left = approximateWithoutFirst(maxDistance, from, fixAndDistance.getA().getTimePoint()); + List right = approximateWithoutFirst(maxDistance, fixAndDistance.getA().getTimePoint(), to); + result = new ArrayList(left.size()+right.size()); + for (FixType fixFromLeft : left) { + result.add(fixFromLeft); + } + for (FixType fixFromRight : right) { + result.add(fixFromRight); + } } return result; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java index a0a53bd1b2d..87f6609002c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java @@ -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 from until time point to such that the maximum distance between the + * track's fixes and the approximation is at most maxDistance. + */ + List approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java index d8a25aceedb..2e21ea459fb 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java @@ -3,6 +3,7 @@ package com.sap.sailing.domain.tracking.impl; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.NavigableSet; import java.util.Set; import java.util.logging.Level; @@ -10,10 +11,12 @@ import java.util.logging.Logger; import com.sap.sailing.domain.base.Buoy; import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.Distance; import com.sap.sailing.domain.base.Leg; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.TimePoint; import com.sap.sailing.domain.base.Waypoint; +import com.sap.sailing.domain.base.impl.DouglasPeucker; import com.sap.sailing.domain.base.impl.MillisecondsTimePoint; import com.sap.sailing.domain.tracking.DynamicGPSFixTrack; import com.sap.sailing.domain.tracking.DynamicTrackedEvent; @@ -280,4 +283,10 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements public DynamicTrackedEvent getTrackedEvent() { return (DynamicTrackedEvent) super.getTrackedEvent(); } + + @Override + public List approximate(Competitor competitor, Distance maxDistance, TimePoint from, TimePoint to) { + DouglasPeucker douglasPeucker = new DouglasPeucker(getTrack(competitor)); + return douglasPeucker.approximate(maxDistance, from, to); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceMapPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceMapPanel.java index 9fc288b98c3..b7b53068b8f 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceMapPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/RaceMapPanel.java @@ -758,7 +758,7 @@ public class RaceMapPanel extends FormPanel implements EventDisplayer, TimeListe Map to = new HashMap(); to.put(competitorDAO, fixes.get(competitorDAO).get(lastShownFix.get(competitorDAO)).timepoint); sailingService.getDouglasPoints(event.name, race.name, from, - to, /* epsilon/meters */ 10, new AsyncCallback>>() { + to, /* epsilon/meters */ 3, new AsyncCallback>>() { @Override public void onFailure(Throwable caught) { errorReporter.reportError("Error obtaining douglas positions: " + caught.getMessage()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index e18ebcde95b..a37df115416 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -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 from, Map to, double meters) { Map> result = new HashMap>(); - 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 gpsFixTrack = getTrackedRace(eventName, raceName).getTrack( - competitor); - DouglasPeucker douglas = new DouglasPeucker( - gpsFixTrack); + GPSFixTrack 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 gpsFixApproximation = trackedRace.approximate(competitor, maxDistance, timePointFrom, timePointTo); List gpsFixDouglasList = new ArrayList(); - 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