refactored Douglas-Peucker to use List<FixType> instead of GPSFix[]; moved DP usage to TrackedRaceImpl

This commit is contained in:
Axel Uhl committed 2011-11-28 16:55:52 +01:00
1 parent bc703fd4b6
commit f796f24858
7 files changed
+64 -36

No files matched your search

@@ -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());
}
}
@@ -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,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;
}
@@ -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);
}
@@ -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<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);
}
}
@@ -758,7 +758,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 */ 10, 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());
@@ -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());