Moved calculation of the start and finish for a tracked race to the sailing service

This commit is contained in:
Lennart Hensler
2012-03-30 08:48:56 +02:00
parent e56e0110fc
commit abcd5ac3f3
6 changed files with 68 additions and 160 deletions
@@ -1,71 +0,0 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Placemark;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.impl.GPSFixImpl;
import com.sap.sailing.domain.tractracadapter.ReceiverType;
public class LongRangeRegattaGeocoderTest extends AbstractManeuverDetectionTestCase {
public LongRangeRegattaGeocoderTest() throws MalformedURLException, URISyntaxException {
super();
}
@Before
public void setUp() throws URISyntaxException, IOException, InterruptedException {
super.setUp();
super.setUp("event_20110609_KielerWoch",
/* raceId */"357c700a-9d9a-11e0-85be-406186cbf87c", new ReceiverType[] { ReceiverType.MARKPASSINGS,
ReceiverType.RACESTARTFINISH, ReceiverType.RACECOURSE });
fixApproximateMarkPositionsForGeocoder(getTrackedRace());
dateFormat = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss");
}
private void fixApproximateMarkPositionsForGeocoder(DynamicTrackedRace race) {
TimePoint epoch = new MillisecondsTimePoint(0l);
TimePoint now = MillisecondsTimePoint.now();
Map<String, Position> buoyPositions = new HashMap<String, Position>();
buoyPositions.put("K Start (left)", new DegreePosition(5.90906782829855, -55.16166687011719));
buoyPositions.put("K Start (right)", new DegreePosition(5.939801840526332, -55.17402648925781));
buoyPositions.put("K Mark1", new DegreePosition(8.233237111274565, -31.640625));
buoyPositions.put("K Mark4 (right)", new DegreePosition(13.63083009512624, -21.8243408203125));
buoyPositions.put("K Mark4 (left)", new DegreePosition(13.870080100685891, -21.9122314453125));
buoyPositions.put("K Finish (left)", new DegreePosition(14.694198629294522, -17.39307403564453));
buoyPositions.put("K Finish (right)", new DegreePosition(14.693866535193942, -17.371788024902344));
for (Waypoint w : race.getRace().getCourse().getWaypoints()) {
for (Buoy buoy : w.getBuoys()) {
race.getOrCreateTrack(buoy).addGPSFix(new GPSFixImpl(buoyPositions.get(buoy.getName()), epoch));
race.getOrCreateTrack(buoy).addGPSFix(new GPSFixImpl(buoyPositions.get(buoy.getName()), now));
}
}
}
@Test
public void testSetupOK() throws ParseException, NoWindException {
assertNotNull(getTrackedRace());
Pair<Placemark, Placemark> placemarks = getTrackedRace().getStartFinishPlacemarks();
assertNotNull(placemarks.getA());
assertNotNull(placemarks.getB());
}
}
@@ -12,7 +12,6 @@ import com.sap.sailing.domain.base.RaceDefinition;
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.Placemark;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.Tack;
@@ -421,12 +420,6 @@ public class MockedTrackedRace implements DynamicTrackedRace {
// TODO Auto-generated method stub
}
@Override
public Pair<Placemark, Placemark> getStartFinishPlacemarks() {
// TODO Auto-generated method stub
return null;
}
@Override
public RaceIdentifier getRaceIdentifier() {
// TODO Auto-generated method stub
@@ -45,12 +45,6 @@ public interface TrackedRace {
RaceIdentifier getRaceIdentifier();
/**
* @return A pair of placemarks, where A is the start placemark and B is the finish placemark.<br />
* The returning pair is never <code>null</code>, but A and/or B can be <code>null</code>.
*/
Pair<Placemark, Placemark> getStartFinishPlacemarks();
/**
* Computes the estimated start time for this race (not to be confused with the {@link #getStartOfTracking()} time point
* which is expected to be before the race start time). When there are no {@link MarkPassing}s for the first mark, <code>null</code>
@@ -1,6 +1,5 @@
package com.sap.sailing.domain.tracking.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -18,8 +17,6 @@ import java.util.concurrent.ConcurrentSkipListSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.simple.parser.ParseException;
import com.sap.sailing.domain.base.BearingWithConfidence;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
@@ -43,7 +40,6 @@ import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NoWindError;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Placemark;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.Tack;
@@ -74,19 +70,12 @@ import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.geocoding.ReverseGeocoder;
public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
private static final Logger logger = Logger.getLogger(TrackedRaceImpl.class.getName());
private static final double PENALTY_CIRCLE_DEGREES_THRESHOLD = 320;
/**
* Used in {@link #getStartFinishPlacemarks()} to calculate the radius for the
* {@link ReverseGeocoder#getPlacemarksNear(Position, double) GetPlacemarksNear-Service}.
*/
private static final double GEONAMES_RADIUS_CACLCULATION_FACTOR = 10.0;
// TODO make this variable
private static final long DELAY_FOR_CACHE_CLEARING_IN_MILLISECONDS = 7500;
@@ -1431,69 +1420,6 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
}
}
@Override
public Pair<Placemark, Placemark> getStartFinishPlacemarks() {
Pair<Placemark, Placemark> placemarks = new Pair<Placemark, Placemark>(null, null);
Placemark startBest = null;
Placemark finishBest = null;
// Get start postition
Iterator<Buoy> startBuoys = getRace().getCourse().getFirstWaypoint().getBuoys().iterator();
GPSFix startBuoyFix = startBuoys.hasNext() ? getOrCreateTrack(startBuoys.next()).getLastRawFix() : null;
Position startPosition = startBuoyFix != null ? startBuoyFix.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() * GEONAMES_RADIUS_CACLCULATION_FACTOR;
// 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 (ParseException e) {
logger.throwing(TrackedRaceImpl.class.getName(), "getPlaceOrder()", e);
}
}
// Get finish position
Iterator<Buoy> finishBuoys = getRace().getCourse().getFirstWaypoint().getBuoys().iterator();
GPSFix finishBuoyFix = finishBuoys.hasNext() ? getOrCreateTrack(finishBuoys.next()).getLastRawFix() : null;
Position finishPosition = finishBuoyFix != null ? finishBuoyFix.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() * GEONAMES_RADIUS_CACLCULATION_FACTOR;
// 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 (ParseException e) {
logger.throwing(TrackedRaceImpl.class.getName(), "getPlaceOrder()", e);
}
}
}
if (startBest != null) {
placemarks.setA(startBest);
}
if (finishBest != null) {
placemarks.setB(finishBest);
}
return placemarks;
}
@Override
public Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint)
throws NoWindException {
@@ -16,7 +16,8 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.domain.tractracadapter.persistence,
com.google.gwt.osgi;bundle-version="2.4.0",
com.sap.sailing.domain.common,
org.moxieapps.gwt.highcharts;bundle-version="1.1.4"
org.moxieapps.gwt.highcharts;bundle-version="1.1.4",
com.sap.sailing.geocoding
Bundle-Activator: com.sap.sailing.gwt.ui.server.Activator
Bundle-ActivationPolicy: lazy
Export-Package: com.sap.sailing.gwt.ui.client;x-friends:="com.sap.sailing.gwt.ui.test",
@@ -100,10 +100,12 @@ import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.WindImpl;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
import com.sap.sailing.domain.tractracadapter.RaceRecord;
import com.sap.sailing.domain.tractracadapter.TracTracConfiguration;
import com.sap.sailing.geocoding.ReverseGeocoder;
import com.sap.sailing.gwt.ui.client.SailingService;
import com.sap.sailing.gwt.ui.shared.BoatClassDTO;
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
@@ -1211,7 +1213,7 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
if (withAdditionalData) {
//Getting the places of the race
Pair<Placemark, Placemark> startAndFinish = trackedRace.getStartFinishPlacemarks();
Pair<Placemark, Placemark> startAndFinish = getStartFinishPlacemarksForTrackedRace(trackedRace);
PlacemarkOrderDTO racePlaces = new PlacemarkOrderDTO();
if (startAndFinish.getA() != null) {
racePlaces.getPlacemarks().add(convertToPlacemarkDTO(startAndFinish.getA()));
@@ -1237,6 +1239,69 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
return dto;
}
private Pair<Placemark, Placemark> getStartFinishPlacemarksForTrackedRace(TrackedRace race) {
double radiusCalculationFactor = 10.0;
Pair<Placemark, Placemark> placemarks = new Pair<Placemark, Placemark>(null, null);
Placemark startBest = null;
Placemark finishBest = null;
// Get start postition
Iterator<Buoy> startBuoys = race.getRace().getCourse().getFirstWaypoint().getBuoys().iterator();
GPSFix startBuoyFix = startBuoys.hasNext() ? race.getOrCreateTrack(startBuoys.next()).getLastRawFix() : null;
Position startPosition = startBuoyFix != null ? startBuoyFix.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<Buoy> finishBuoys = race.getRace().getCourse().getFirstWaypoint().getBuoys().iterator();
GPSFix finishBuoyFix = finishBuoys.hasNext() ? race.getOrCreateTrack(finishBuoys.next()).getLastRawFix() : null;
Position finishPosition = finishBuoyFix != null ? finishBuoyFix.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);
}
}
}
if (startBest != null) {
placemarks.setA(startBest);
}
if (finishBest != null) {
placemarks.setB(finishBest);
}
return placemarks;
}
@Override
public void updateLeaderboard(String leaderboardName, String newLeaderboardName, int[] newDiscardingThreasholds) {
if (!leaderboardName.equals(newLeaderboardName)) {