Merged ess-singapore containing the temporary fix for the igtimi windbot gps miscalculation, the update of MAX_HOPS for tractrac stored data, the fix for the race committee app and max_speed for xml export

This commit is contained in:
Simon Pamies
2014-02-24 10:19:13 +08:00
parent 76ed76542a
commit b3e2d28753
8 changed files with 169 additions and 5 deletions
@@ -0,0 +1,119 @@
package com.sap.sailing.domain.igtimiadapter.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.igtimiadapter.datatypes.GpsLatLong;
import com.sap.sailing.domain.igtimiadapter.impl.FixFactory;
/**
* See bug 1794: http://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=1794. Here is an offending string:
* <p>
* {"DD-EE-AAHE":{"1":{"t":[1392881700000,1392881732500,1392881772500,1392881812500,1392881852500,1392881892500,
* 1392881932500
* ,1392881972500,1392882012500,1392882052500,1392882092500,1392882132500,1392882172500,1392882212500,1392882252500
* ,1392882292500
* ,1392882332500,1392882372500,1392882412500,1392882452500,1392882492500,1392882532500,1392882572500,1392882612500
* ,1392882652500
* ,1392882692500,1392882732500,1392882772500,1392882812500,1392882852500,1392882892500,1392882932500,1392882972500
* ,1392883012500
* ,1392883052500,1392883092500,1392883132500,1392883172500,1392883212500,1392883252500,1392883292500,1392883332500
* ,1392883359750
* ,1392883360000,1392883360500,1392883400500,1392883462000],"1":[103.85452,103.854519,103.854514,103.854511333333
* ,103.8545015
* ,103.854510666667,103.854509833333,103.854512333333,103.854507833333,103.854507166667,103.854510833333,103.854509
* ,103.854512
* ,103.854511166667,103.854514333333,103.854517833333,103.854509833333,103.8545115,103.854516833333,103.854520833333
* ,103.854525666667
* ,103.854527166667,103.854529333333,103.854525166667,103.854525,103.854524333333,103.854520333333,103.854518166667
* ,103.8545165
* ,103.854516666667,103.854511666667,103.854515,103.854514666667,103.8545145,103.854514,103.854517,103.854527
* ,103.854531166667
* ,103.854531666667,103.8545335,103.8545335,103.854534,103.854534666667,103.854534833333,103.854537833333
* ,103.854537166667
* ,103.854540166667],"2":[11.1155463333333,11.1155478333333,11.1155546666667,11.1155586666667,11.1155595
* ,11.1155543333333
* ,11.115552,11.1155461666667,11.1155483333333,11.115549,11.1155618333333,11.1155745,11.1155771666667,11.1155746666667
* ,11.1155708333333
* ,11.1155701666667,11.1155716666667,11.1155733333333,11.1155781666667,11.1155795,11.1155785,11.1155735
* ,11.1155711666667
* ,11.1155741666667,11.1155763333333,11.1155748333333,11.1155756666667,11.1155768333333,11.1155791666667
* ,11.1155798333333
* ,11.1155795,11.1155746666667,11.1155781666667,11.1155813333333,11.1155773333333,11.115566,11.1155595,
* 11.1155568333333,
* 11.1155596666667,11.1155646666667,11.1155635,11.115557,11.1155571666667,11.1155571666667,11.1155565,11.115568
* ,11.1155695]}}}
* </p>
*
* @author Axel Uhl (d043530)
*
*/
public class TestCorrectionOfSingleDigitLatitudesWithSystemPropertySet {
@Before
public void setSystemPropertyToEnableWorkaround() {
System.setProperty(GpsLatLong.IGTIMI_ENABLE_WORKAROUND_FOR_SINGLE_DIGIT_LATITUDES, "true");
}
@After
public void unsetSystemPropertyToDisableWorkaround() {
System.clearProperty(GpsLatLong.IGTIMI_ENABLE_WORKAROUND_FOR_SINGLE_DIGIT_LATITUDES);
assertNull(System.getProperty(GpsLatLong.IGTIMI_ENABLE_WORKAROUND_FOR_SINGLE_DIGIT_LATITUDES));
}
@Test
public void testIntRounding() {
assertEquals(1, (int) 1.1);
assertEquals(1, (int) 1.0);
assertEquals(1, (int) 1.9);
assertEquals(-1, (int) -1.1);
assertEquals(-1, (int) -1.0);
assertEquals(-1, (int) -1.9);
}
@Test
public void testSimpleLatLongConversionForTwoNorthLatDigitsWithTwoDigitMinutes() throws ParseException {
double latitude = 11.0 + 17.0/60.0; // with two-digit minutes it cannot have been an incorrect parse
JSONObject json = (JSONObject) new JSONParser().parse("{ \"AA-AA-AAA-5\":{ \"1\":{ \"t\":[ 1360618858970 ], \"1\":[ 172.04 ], \"2\":[ "+latitude+" ] } } }");
GpsLatLong pos = (GpsLatLong) new FixFactory().createFixes(json).iterator().next();
assertEquals(latitude, pos.getPosition().getLatDeg(), 0.0000001);
assertEquals(172.04, pos.getPosition().getLngDeg(), 0.0000001);
}
@Test
public void testSimpleLatLongConversionForTwoSouthLatDigitsWithTwoDigitMinutes() throws ParseException {
double latitude = -11.0 - 17.0/60.0; // with two-digit minutes it cannot have been an incorrect parse
JSONObject json = (JSONObject) new JSONParser().parse("{ \"AA-AA-AAA-5\":{ \"1\":{ \"t\":[ 1360618858970 ], \"1\":[ 172.04 ], \"2\":[ "+latitude+" ] } } }");
GpsLatLong pos = (GpsLatLong) new FixFactory().createFixes(json).iterator().next();
assertEquals(latitude, pos.getPosition().getLatDeg(), 0.0000001);
assertEquals(172.04, pos.getPosition().getLngDeg(), 0.0000001);
}
@Test
public void testSimpleLatLongConversionForTwoLatDigitsWithOneDigitMinutesFromOriginalSingaporeData() throws ParseException {
// NMEA latitude was "116.9341N", meaning 1° 16.9341' North
final double incorrectLatitude = 11. + 6.9341/60.;
final double correctLatitude = 1.0 + 16.9341/60.;
JSONObject json = (JSONObject) new JSONParser().parse("{\"DD-EE-AAHE\":{\"1\":{\"t\":[1392881700000], \"1\":[ 103.85452 ], \"2\":[ "+incorrectLatitude+" ] } } }");
GpsLatLong pos = (GpsLatLong) new FixFactory().createFixes(json).iterator().next();
assertEquals(correctLatitude, pos.getPosition().getLatDeg(), 0.0000001);
assertEquals(103.85452, pos.getPosition().getLngDeg(), 0.0000001);
}
@Test
public void testSimpleLatLongConversionForTwoSouthLatDigitsWithOneDigitMinutesFromOriginalSingaporeData() throws ParseException {
// NMEA latitude was "116.9341N", meaning 1° 16.9341' North
final double incorrectLatitude = -11. - 6.9341/60.;
final double correctLatitude = -1.0 - 16.9341/60.;
JSONObject json = (JSONObject) new JSONParser().parse("{\"DD-EE-AAHE\":{\"1\":{\"t\":[1392881700000], \"1\":[ 103.85452 ], \"2\":[ "+incorrectLatitude+" ] } } }");
GpsLatLong pos = (GpsLatLong) new FixFactory().createFixes(json).iterator().next();
assertEquals(correctLatitude, pos.getPosition().getLatDeg(), 0.0000001);
assertEquals(103.85452, pos.getPosition().getLngDeg(), 0.0000001);
}
}
@@ -9,12 +9,29 @@ import com.sap.sailing.domain.igtimiadapter.IgtimiFixReceiver;
import com.sap.sailing.domain.igtimiadapter.Sensor;
public class GpsLatLong extends Fix {
public static final String IGTIMI_ENABLE_WORKAROUND_FOR_SINGLE_DIGIT_LATITUDES = "igtimi.enableWorkaroundForSingleDigitLatitudes";
private static final long serialVersionUID = 5056284867725893553L;
private final Position position;
public GpsLatLong(TimePoint timePoint, Sensor sensor, Map<Integer, Object> valuesPerSubindex) {
super(sensor, timePoint);
position = new DegreePosition(((Number) valuesPerSubindex.get(2)).doubleValue(), ((Number) valuesPerSubindex.get(1)).doubleValue());
final double longitudeInDegrees = ((Number) valuesPerSubindex.get(1)).doubleValue();
final double preliminaryLatitudeInDegrees = ((Number) valuesPerSubindex.get(2)).doubleValue();
final double latitudeInDegrees;
if (Boolean.valueOf(System.getProperty(IGTIMI_ENABLE_WORKAROUND_FOR_SINGLE_DIGIT_LATITUDES, "false"))) {
final int degrees = (int) preliminaryLatitudeInDegrees;
final double minutes = (preliminaryLatitudeInDegrees - degrees)*60.0;
if (Math.abs(minutes) >= 10) {
// the minutes have two digits; cannot have been a mis-parse
latitudeInDegrees = preliminaryLatitudeInDegrees;
} else {
final double correctedMinutes = minutes + 10.0*(degrees%10);
latitudeInDegrees = ((int) (degrees/10)) + correctedMinutes/60.0;
}
} else {
latitudeInDegrees = preliminaryLatitudeInDegrees;
}
position = new DegreePosition(latitudeInDegrees, longitudeInDegrees);
}
public Position getPosition() {
@@ -189,7 +189,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
* </ul>
* Potentially, you can create 8 threads per TTCM (connecting only with one single race)."
*/
static final Integer MAX_STORED_PACKET_HOP_ALLOWANCE = 8;
static final Integer MAX_STORED_PACKET_HOP_ALLOWANCE = 1000;
private final Event tractracEvent;
private final com.sap.sailing.domain.base.Regatta regatta;
@@ -16,6 +16,8 @@ import com.sap.sailing.domain.racelog.RaceLogServletConstants;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.gateway.AbstractJsonHttpServlet;
import com.sap.sailing.server.gateway.serialization.impl.BoatClassJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.BoatJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.CompetitorJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.NationalityJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.PersonJsonSerializer;
@@ -74,7 +76,7 @@ public class CompetitorsJsonExportServlet extends AbstractJsonHttpServlet {
if (trackedRace != null) {
CompetitorJsonSerializer serializer = new CompetitorJsonSerializer(new TeamJsonSerializer(
new PersonJsonSerializer(new NationalityJsonSerializer())), null);
new PersonJsonSerializer(new NationalityJsonSerializer())), new BoatJsonSerializer(new BoatClassJsonSerializer()));
for (Competitor competitor : raceColumn.getRaceDefinition(fleet).getCompetitors()) {
result.add(serializer.serialize(competitor));
@@ -23,8 +23,10 @@ import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
@@ -168,6 +170,22 @@ public abstract class ExportAction {
}
return result;
}
public Speed getMaximumSpeedOverGround(Competitor competitor, TrackedRace trackedRace) {
Speed maxSpeed = null;
if (Util.contains(trackedRace.getRace().getCompetitors(), competitor)) {
NavigableSet<MarkPassing> markPassings = trackedRace.getMarkPassings(competitor);
if (!markPassings.isEmpty()) {
TimePoint from = markPassings.first().getTimePoint();
TimePoint to = trackedRace.getEndOfRace();
Pair<GPSFixMoving, Speed> maxSpeedWithGPSFix = trackedRace.getTrack(competitor).getMaximumSpeedOverGround(from, to);
if (maxSpeedWithGPSFix != null) {
maxSpeed = maxSpeedWithGPSFix.getB();
}
}
}
return maxSpeed;
}
public Speed getAverageSpeedOverGround(Leaderboard leaderboard, Competitor competitor, TimePoint timePoint, boolean alsoIncludeNonFinishedRaces) {
Speed result = null;
@@ -312,6 +312,7 @@ public class LeaderboardData extends ExportAction {
addNamedElementWithValue(competitorRaceDataElement, "distance_from_starboard_side_of_start_line_when_passing_start_in_meters", race.getDistanceFromStarboardSideOfStartLineWhenPassingStart(competitor).getMeters());
addNamedElementWithValue(competitorRaceDataElement, "rank_based_on_distance_from_starboard_side_of_start_line", competitorToDistanceRank.get(competitor));
addNamedElementWithValue(competitorRaceDataElement, "speed_when_crossing_start_line_in_knots", race.getSpeedWhenCrossingStartLine(competitor).getKnots());
addNamedElementWithValue(competitorRaceDataElement, "maximum_race_speed_over_ground_in_knots", getMaximumSpeedOverGround(competitor, race).getKnots());
addNamedElementWithValue(competitorRaceDataElement, "start_advantage_in_meters", start.getAdvantage().getMeters());
addNamedElementWithValue(competitorRaceDataElement, "advantageous_side_while_approaching_start_line", start.getAdvantageousSideWhileApproachingLine().name());
Distance distanceTraveledInThisRace = race.getDistanceTraveled(competitor, race.getEndOfRace());
@@ -45,7 +45,7 @@
<com.mobeta.android.dslv.DragSortListView
android:id="@+id/dragSortListPositioning"
android:layout_width="350dp"
android:layout_height="fill_parent"
android:layout_height="584dp"
android:layout_gravity="left"
android:layout_marginLeft="10dp"
android:layout_marginRight="30dp"
@@ -53,11 +53,16 @@ import com.sap.sailing.server.gateway.deserialization.coursedata.impl.CourseBase
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.GateDeserializer;
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.MarkDeserializer;
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.WaypointDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.BoatClassJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.BoatJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.CompetitorJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.CourseAreaJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.DeviceConfigurationJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.EventBaseJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.NationalityJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.PersonJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.RegattaConfigurationJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.TeamJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.VenueJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.racegroup.impl.RaceGroupDeserializer;
@@ -201,7 +206,9 @@ public class OnlineDataManager extends DataManager {
@Override
public Loader<DataLoaderResult<Collection<Competitor>>> create(int id, Bundle args) throws Exception {
ExLog.i(TAG, String.format("Creating Competitor-OnlineDataLoader %d", id));
JsonDeserializer<Competitor> competitorDeserializer = new CompetitorJsonDeserializer(domainFactory.getCompetitorStore());
JsonDeserializer<Competitor> competitorDeserializer = new CompetitorJsonDeserializer(domainFactory.getCompetitorStore(),
new TeamJsonDeserializer(new PersonJsonDeserializer(new NationalityJsonDeserializer(domainFactory))),
new BoatJsonDeserializer(new BoatClassJsonDeserializer(domainFactory)));
DataParser<Collection<Competitor>> parser = new CompetitorsDataParser(competitorDeserializer);
DataHandler<Collection<Competitor>> handler = new CompetitorsDataHandler(OnlineDataManager.this,
managedRace);