Merge branch 'master' into jetty-9.4.53.v20231009

This commit is contained in:
Axel Uhl
2024-02-21 09:50:12 +01:00
88 changed files with 577 additions and 395 deletions
@@ -80,13 +80,13 @@ public class TestSegmentsTackType extends StoredTrackBasedTest {
DynamicGPSFixTrack<Competitor, GPSFixMoving> competitorATrack = trackedRace.getTrack(competitorA);
final KnotSpeedWithBearingImpl sogCog = new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(45));
TimePoint timePoint = trackedRace.getStartOfTracking().plus(10);
GPSFixMovingImpl currentGPS = new GPSFixMovingImpl(new DegreePosition(54.4680424, 10.234451), timePoint, sogCog);
GPSFixMovingImpl currentGPS = new GPSFixMovingImpl(new DegreePosition(54.4680424, 10.234451), timePoint, sogCog, /* optionalTrueHeading */ null);
final Duration timeBetweenFixes = Duration.ofMillis(490);
for (int i=0; i<20; i++) {
competitorATrack.addGPSFix(currentGPS);
final Position currentPosition = sogCog.travelTo(currentGPS.getPosition(), timeBetweenFixes);
timePoint = timePoint.plus(timeBetweenFixes);
currentGPS = new GPSFixMovingImpl(currentPosition, timePoint, sogCog);
currentGPS = new GPSFixMovingImpl(currentPosition, timePoint, sogCog, /* optionalTrueHeading */ null);
}
TimePoint markPassingTimePoint = trackedRace.getStartOfTracking().plus(20);
final List<MarkPassing> markPassingsForCompetitor = new ArrayList<>();
@@ -114,13 +114,13 @@ public class TestSegmentsTackType extends StoredTrackBasedTest {
DynamicGPSFixTrack<Competitor, GPSFixMoving> competitorATrack = trackedRace.getTrack(competitorA);
final KnotSpeedWithBearingImpl sogCog = new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(45));
TimePoint timePoint = trackedRace.getStartOfTracking().plus(10);
GPSFixMovingImpl currentGPS = new GPSFixMovingImpl(new DegreePosition(54.4680424, 10.234451), timePoint, sogCog);
GPSFixMovingImpl currentGPS = new GPSFixMovingImpl(new DegreePosition(54.4680424, 10.234451), timePoint, sogCog, /* optionalTrueHeading */ null);
final Duration timeBetweenFixes = Duration.ofMillis(490);
for (int i=0; i<20; i++) {
competitorATrack.addGPSFix(currentGPS);
final Position currentPosition = sogCog.travelTo(currentGPS.getPosition(), timeBetweenFixes);
timePoint = timePoint.plus(timeBetweenFixes);
currentGPS = new GPSFixMovingImpl(currentPosition, timePoint, sogCog);
currentGPS = new GPSFixMovingImpl(currentPosition, timePoint, sogCog, /* optionalTrueHeading */ null);
}
// now run the actual test:
final Iterable<HasTackTypeSegmentContext> allTTSegments = retrieveData();
@@ -138,14 +138,14 @@ public class TestSegmentsTackType extends StoredTrackBasedTest {
final Position middleOfStartLine = trackedRace.getApproximatePosition(trackedRace.getRace().getCourse().getFirstWaypoint(), timePoint);
final Position topMarkPosition = trackedRace.getApproximatePosition(Util.get(trackedRace.getRace().getCourse().getWaypoints(), 1), timePoint);
// start straight "under" the top mark
GPSFixMovingImpl currentGPS = new GPSFixMovingImpl(new DegreePosition(middleOfStartLine.getLatDeg(), topMarkPosition.getLngDeg()), timePoint, sogCogPortTackUpwind);
GPSFixMovingImpl currentGPS = new GPSFixMovingImpl(new DegreePosition(middleOfStartLine.getLatDeg(), topMarkPosition.getLngDeg()), timePoint, sogCogPortTackUpwind, /* optionalTrueHeading */ null);
expectedSegmentStarts.add(timePoint);
final Duration timeBetweenFixes = Duration.ofMillis(490);
for (int i=0; i<20; i++) {
competitorATrack.addGPSFix(currentGPS);
final Position currentPosition = sogCogPortTackUpwind.travelTo(currentGPS.getPosition(), timeBetweenFixes);
timePoint = timePoint.plus(timeBetweenFixes);
currentGPS = new GPSFixMovingImpl(currentPosition, timePoint, sogCogPortTackUpwind);
currentGPS = new GPSFixMovingImpl(currentPosition, timePoint, sogCogPortTackUpwind, /* optionalTrueHeading */ null);
}
// now tack onto starboard tack:
final KnotSpeedWithBearingImpl sogCogStarboardTackUpwind = new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(315));
@@ -154,7 +154,7 @@ public class TestSegmentsTackType extends StoredTrackBasedTest {
competitorATrack.addGPSFix(currentGPS);
final Position currentPosition = sogCogStarboardTackUpwind.travelTo(currentGPS.getPosition(), timeBetweenFixes);
timePoint = timePoint.plus(timeBetweenFixes);
currentGPS = new GPSFixMovingImpl(currentPosition, timePoint, sogCogStarboardTackUpwind);
currentGPS = new GPSFixMovingImpl(currentPosition, timePoint, sogCogStarboardTackUpwind, /* optionalTrueHeading */ null);
}
final List<MarkPassing> markPassingsForCompetitor = new ArrayList<>();
final TimePoint startMarkPassingTimePoint = trackedRace.getStartOfTracking().plus(20);
@@ -170,7 +170,7 @@ public class TestSegmentsTackType extends StoredTrackBasedTest {
competitorATrack.addGPSFix(currentGPS);
final Position currentPosition = sogCogStarboardTackDownwind.travelTo(currentGPS.getPosition(), timeBetweenFixes);
timePoint = timePoint.plus(timeBetweenFixes);
currentGPS = new GPSFixMovingImpl(currentPosition, timePoint, sogCogPortTackUpwind);
currentGPS = new GPSFixMovingImpl(currentPosition, timePoint, sogCogPortTackUpwind, /* optionalTrueHeading */ null);
}
// now gybe onto port tack:
final KnotSpeedWithBearingImpl sogCogPortTackDownwind = new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(135));
@@ -179,7 +179,7 @@ public class TestSegmentsTackType extends StoredTrackBasedTest {
competitorATrack.addGPSFix(currentGPS);
final Position currentPosition = sogCogPortTackDownwind.travelTo(currentGPS.getPosition(), timeBetweenFixes);
timePoint = timePoint.plus(timeBetweenFixes);
currentGPS = new GPSFixMovingImpl(currentPosition, timePoint, sogCogPortTackDownwind);
currentGPS = new GPSFixMovingImpl(currentPosition, timePoint, sogCogPortTackDownwind, /* optionalTrueHeading */ null);
}
// now run the actual test:
final Iterable<HasTackTypeSegmentContext> allTTSegments = retrieveData();
@@ -5,9 +5,9 @@ Bundle-SymbolicName: com.sap.sailing.domain.bravoadapter
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: org.osgi.framework;version="1.8.0"
Require-Bundle: org.eclipse.osgi,
com.sap.sailing.domain,
Import-Package: com.sap.sailing.declination,
org.osgi.framework;version="1.8.0"
Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.server.trackfiles,
com.sap.sailing.domain.common,
com.sap.sse.common,
@@ -3,10 +3,14 @@ package com.sap.sailing.domain.bravoadapter.impl;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.declination.DeclinationService;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.sensordata.BravoExtendedSensorDataMetadata;
@@ -19,9 +23,12 @@ import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
import com.sap.sailing.domain.trackimport.GPSFixImporter;
import com.sap.sailing.server.gateway.windimport.bravo.FunnyDegreeConverter;
import com.sap.sailing.server.trackfiles.impl.BravoExtendedDataImporterImpl;
import com.sap.sse.common.Bearing;
import com.sap.sse.common.impl.DegreeBearingImpl;
public class BravoGPSFixImporter implements GPSFixImporter {
private static final Logger logger = Logger.getLogger(BravoGPSFixImporter.class.getName());
@Override
public boolean importFixes(InputStream inputStream, Charset charset, Callback callback, boolean inferSpeedAndBearing, final String filename)
throws FormatNotSupportedException, IOException {
@@ -30,12 +37,27 @@ public class BravoGPSFixImporter implements GPSFixImporter {
new BravoExtendedDataImporterImpl().importFixes(inputStream,
charset, (Iterable<DoubleVectorFix> fixes, TrackFileImportDeviceIdentifier deviceIdentifier)->{
for (final DoubleVectorFix fix : fixes) {
final DegreePosition position = new DegreePosition(FunnyDegreeConverter.funnyLatLng(fix.get(BravoExtendedSensorDataMetadata.LAT.getColumnIndex())),
FunnyDegreeConverter.funnyLatLng(fix.get(BravoExtendedSensorDataMetadata.LON.getColumnIndex())));
Bearing optionalTrueHeading;
if (fix.get(BravoExtendedSensorDataMetadata.EXPEDITION_HDG.getColumnIndex()) != null) {
try {
optionalTrueHeading = new DegreeBearingImpl(fix.get(BravoExtendedSensorDataMetadata.EXPEDITION_HDG.getColumnIndex())).add(
DeclinationService.INSTANCE.getDeclination(fix.getTimePoint(), position, /* timeout for online lookup in millis */ 100)
.getBearingCorrectedTo(fix.getTimePoint()));
} catch (IOException | ParseException e) {
logger.log(Level.WARNING, "Problem looking up magnetic declination for Bravo fix", e);
optionalTrueHeading = null;
}
} else {
optionalTrueHeading = null;
}
GPSFixMoving gpsFix = new GPSFixMovingImpl(
new DegreePosition(FunnyDegreeConverter.funnyLatLng(fix.get(BravoExtendedSensorDataMetadata.LAT.getColumnIndex())),
FunnyDegreeConverter.funnyLatLng(fix.get(BravoExtendedSensorDataMetadata.LON.getColumnIndex()))),
position,
fix.getTimePoint(),
new KnotSpeedWithBearingImpl(fix.get(BravoExtendedSensorDataMetadata.SOG.getColumnIndex()),
new DegreeBearingImpl(fix.get(BravoExtendedSensorDataMetadata.COG.getColumnIndex()))));
new DegreeBearingImpl(fix.get(BravoExtendedSensorDataMetadata.COG.getColumnIndex()))),
optionalTrueHeading);
callback.addFix(gpsFix, device);
importedFixes.set(true);
}
@@ -1,6 +1,15 @@
package com.sap.sailing.domain.common.tracking;
import com.sap.sailing.domain.common.Moving;
import com.sap.sse.common.Bearing;
public interface GPSFixMoving extends GPSFix, Moving {
/**
* Some sensors have a compass or IMU built in that can deliver a true heading. This usually requires a fixed mount
* that guarantees a well-defined orientation of the sensor relative to the object it tracks.
*
* @return a true (free of magnetic declination) heading of the object tracked, e.g., for a boat the true direction
* the bow points to; or {@code null} if the sensor did not deliver this attribute
*/
Bearing getOptionalTrueHeading();
}
@@ -10,6 +10,7 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sse.common.Bearing;
import com.sap.sse.common.Speed;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
/**
* A memory-conserving representation of a {@link GPSFixMoving} object that produces the fine-grained
@@ -96,6 +97,7 @@ public abstract class AbstractCompactGPSFixMovingImpl extends AbstractCompactGPS
@Override
public boolean equals(Object other) {
return super.equals(other) && other instanceof GPSFixMoving && getSpeed().equals(((GPSFixMoving) other).getSpeed());
return super.equals(other) && other instanceof GPSFixMoving && getSpeed().equals(((GPSFixMoving) other).getSpeed())
&& Util.equalsWithNull(getOptionalTrueHeading(), ((GPSFixMoving) other).getOptionalTrueHeading());
}
}
@@ -19,4 +19,6 @@ public class FlatSmartphoneUuidAndGPSFixMovingJsonSerializer {
public static final String TIME_ISO = "timestamp-iso";
public static final String SPEED_M_PER_S = "speed";
public static final String BEARING_DEG = "course";
public static final String TRUE_HEADING_DEG = "hdt";
public static final String MAGNETIC_HEADING_DEG = "hdg";
}
@@ -5,6 +5,7 @@ import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sse.common.Bearing;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.DegreeBearingImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -12,10 +13,12 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
public class GPSFixMovingImpl extends GPSFixImpl implements GPSFixMoving {
private static final long serialVersionUID = 6508021498142383100L;
private final SpeedWithBearing speed;
private final Bearing optionalTrueHeading;
public GPSFixMovingImpl(Position position, TimePoint timePoint, SpeedWithBearing speed) {
public GPSFixMovingImpl(Position position, TimePoint timePoint, SpeedWithBearing speed, Bearing optionalTrueHeading) {
super(position, timePoint);
this.speed = speed;
this.optionalTrueHeading = optionalTrueHeading;
}
@Override
@@ -23,6 +26,11 @@ public class GPSFixMovingImpl extends GPSFixImpl implements GPSFixMoving {
return speed;
}
@Override
public Bearing getOptionalTrueHeading() {
return optionalTrueHeading;
}
@Override
public String toString() {
return super.toString()+" with "+getSpeed();
@@ -39,9 +47,10 @@ public class GPSFixMovingImpl extends GPSFixImpl implements GPSFixMoving {
}
public static GPSFixMovingImpl create(double lonDeg, double latDeg, long timeMillis,
double speedInKnots, double bearingDeg) {
double speedInKnots, double bearingDeg, Double optionalTrueHeadingDeg) {
return new GPSFixMovingImpl(new DegreePosition(latDeg, lonDeg),
new MillisecondsTimePoint(timeMillis), new KnotSpeedWithBearingImpl(
speedInKnots, new DegreeBearingImpl(bearingDeg)));
speedInKnots, new DegreeBearingImpl(bearingDeg)),
optionalTrueHeadingDeg==null?null:new DegreeBearingImpl(optionalTrueHeadingDeg));
}
}
@@ -24,6 +24,12 @@ public class PreciseCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingI
private final double lngDeg;
private final double knotSpeed;
private final double degBearing;
/**
* Valid only if {@link #trueHeadingDegSet} is {@code true}
*/
private final double trueHeadingDeg;
private final boolean trueHeadingDegSet;
/**
* When <code>{@link #whatIsCached}&amp;{@link #IS_ESTIMATED_SPEED_CACHED} != 0</code>, this field tells the estimated speed's
@@ -61,6 +67,15 @@ public class PreciseCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingI
}
}
private class PreciseCompactTrueHeading extends AbstractBearing {
private static final long serialVersionUID = -1837422977159746992L;
@Override
public double getDegrees() {
return trueHeadingDeg;
}
}
public class PreciseCompactPosition extends AbstractPosition {
private static final long serialVersionUID = 5621506820766614178L;
@@ -98,16 +113,23 @@ public class PreciseCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingI
}
}
public PreciseCompactGPSFixMovingImpl(Position position, TimePoint timePoint, SpeedWithBearing speed) {
public PreciseCompactGPSFixMovingImpl(Position position, TimePoint timePoint, SpeedWithBearing speed, Bearing optionalTrueHeading) {
super(timePoint);
latDeg = position.getLatDeg();
lngDeg = position.getLngDeg();
knotSpeed = speed==null?0:speed.getKnots();
degBearing = speed==null?0:speed.getBearing().getDegrees();
if (optionalTrueHeading == null) {
trueHeadingDegSet = false;
trueHeadingDeg = 0.0;
} else {
trueHeadingDegSet = true;
trueHeadingDeg = optionalTrueHeading.getDegrees();
}
}
public PreciseCompactGPSFixMovingImpl(GPSFixMoving gpsFixMoving) {
this(gpsFixMoving.getPosition(), gpsFixMoving.getTimePoint(), gpsFixMoving.getSpeed());
this(gpsFixMoving.getPosition(), gpsFixMoving.getTimePoint(), gpsFixMoving.getSpeed(), gpsFixMoving.getOptionalTrueHeading());
}
@Override
@@ -119,6 +141,11 @@ public class PreciseCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingI
public Position getPosition() {
return new PreciseCompactPosition();
}
@Override
public Bearing getOptionalTrueHeading() {
return trueHeadingDegSet ? new PreciseCompactTrueHeading() : null;
}
@Override
public SpeedWithBearing getCachedEstimatedSpeed() {
@@ -46,6 +46,13 @@ public class VeryCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingImpl
*/
private final short degreeBearingScaled;
/**
* See {@link CompactPositionHelper}; valid if and only if {@link #trueHeadingDegreesSet} is {@code true}.
*/
private final short trueHeadingDegreesScaled;
private final boolean trueHeadingDegreesSet;
/**
* When <code>{@link #whatIsCached}&amp;{@link #IS_ESTIMATED_SPEED_CACHED} != 0</code>, this field tells the estimated speed's
* true "bearing" (true course over ground) in degrees, scaled into a short value using {@link CompactPositionHelper}.
@@ -95,6 +102,15 @@ public class VeryCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingImpl
}
}
private class VeryCompactTrueHeading extends AbstractBearing {
private static final long serialVersionUID = 1130980861113826462L;
@Override
public double getDegrees() {
return CompactPositionHelper.getDegreeBearing(trueHeadingDegreesScaled);
}
}
private class VeryCompactEstimatedSpeedBearing extends AbstractBearing {
private static final long serialVersionUID = 8549231429037883121L;
@@ -118,7 +134,7 @@ public class VeryCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingImpl
}
}
public VeryCompactGPSFixMovingImpl(Position position, TimePoint timePoint, SpeedWithBearing speed) throws CompactionNotPossibleException {
public VeryCompactGPSFixMovingImpl(Position position, TimePoint timePoint, SpeedWithBearing speed, Bearing optionalTrueHeading) throws CompactionNotPossibleException {
super(timePoint);
latDegScaled = CompactPositionHelper.getLatDegScaled(position);
lngDegScaled = CompactPositionHelper.getLngDegScaled(position);
@@ -129,16 +145,28 @@ public class VeryCompactGPSFixMovingImpl extends AbstractCompactGPSFixMovingImpl
speedInKnotsScaled = CompactPositionHelper.getKnotSpeedScaled(speed);
degreeBearingScaled = CompactPositionHelper.getDegreeBearingScaled(speed.getBearing());
}
if (optionalTrueHeading == null) {
trueHeadingDegreesSet = false;
trueHeadingDegreesScaled = 0;
} else {
trueHeadingDegreesSet = true;
trueHeadingDegreesScaled = CompactPositionHelper.getDegreeBearingScaled(optionalTrueHeading);
}
}
public VeryCompactGPSFixMovingImpl(GPSFixMoving gpsFixMoving) throws CompactionNotPossibleException {
this(gpsFixMoving.getPosition(), gpsFixMoving.getTimePoint(), gpsFixMoving.getSpeed());
this(gpsFixMoving.getPosition(), gpsFixMoving.getTimePoint(), gpsFixMoving.getSpeed(), gpsFixMoving.getOptionalTrueHeading());
}
@Override
public SpeedWithBearing getSpeed() {
return new VeryCompactSpeedWithBearing();
}
@Override
public Bearing getOptionalTrueHeading() {
return trueHeadingDegreesSet ? new VeryCompactTrueHeading() : null;
}
@Override
public Position getPosition() {
@@ -10,6 +10,7 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.domain.shared.android,
com.sap.sailing.server.trackfiles,
com.sap.sse.common
Import-Package: org.osgi.framework
Import-Package: com.sap.sailing.declination,
org.osgi.framework
Bundle-Activator: com.sap.sailing.domain.deckmanadapter.impl.Activator
Automatic-Module-Name: com.sap.sailing.domain.deckmanadapter
@@ -1,11 +1,15 @@
package com.sap.sailing.domain.deckmanadapter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.declination.DeclinationService;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Positioned;
import com.sap.sailing.domain.common.SpeedWithBearing;
@@ -16,12 +20,15 @@ import com.sap.sailing.domain.common.impl.WindImpl;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.deckmanadapter.impl.FieldType;
import com.sap.sse.common.Bearing;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Timed;
import com.sap.sse.common.impl.DegreeBearingImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class Record implements Timed, Positioned {
private static final Logger logger = Logger.getLogger(Record.class.getName());
private static final long serialVersionUID = -7939775022865795801L;
private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
@@ -47,9 +54,18 @@ public class Record implements Timed, Positioned {
Double.valueOf(this.fieldsAsString.get(FieldType.longitude)));
final SpeedWithBearing speed = new KnotSpeedWithBearingImpl(Double.valueOf(this.fieldsAsString.get(FieldType.sog)),
new DegreeBearingImpl(Double.valueOf(this.fieldsAsString.get(FieldType.cog))));
Bearing optionalTrueHeading;
try {
optionalTrueHeading = this.fieldsAsString.get(FieldType.heading) == null ? null :
new DegreeBearingImpl(Double.valueOf(this.fieldsAsString.get(FieldType.heading))).add(
DeclinationService.INSTANCE.getDeclination(timePoint, position, /* timeout in ms */ 1000).getBearingCorrectedTo(timePoint));
} catch (NumberFormatException | IOException | ParseException e) {
logger.log(Level.WARNING, "Problem obtaining magnetic declination for converting Deckman magnetic heading value to true", e);
optionalTrueHeading = null;
}
wind = new WindImpl(position, timePoint, new KnotSpeedWithBearingImpl(Double.valueOf(this.fieldsAsString
.get(FieldType.tws)), new DegreeBearingImpl(Double.valueOf(this.fieldsAsString.get(FieldType.twd)))));
gpsFix = new GPSFixMovingImpl(position, timePoint, speed);
gpsFix = new GPSFixMovingImpl(position, timePoint, speed, optionalTrueHeading);
}
public String getField(FieldType fieldType) {
@@ -29,7 +29,7 @@ public class DeckmanGPSFixImporter implements GPSFixImporter {
try {
for (Iterator<Record> i = deckmanAdapter.parseLogFile(new InputStreamReader(inputStream)); i.hasNext();) {
Record record = i.next();
callback.addFix(new GPSFixMovingImpl(record.getPosition(), record.getTimePoint(), record.getGpsFix().getSpeed()),
callback.addFix(new GPSFixMovingImpl(record.getPosition(), record.getTimePoint(), record.getGpsFix().getSpeed(), record.getGpsFix().getOptionalTrueHeading()),
device);
importedFixes.set(true);
}
@@ -5,7 +5,8 @@ Bundle-SymbolicName: com.sap.sailing.domain.expeditionadapter
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: org.osgi.framework
Import-Package: com.sap.sailing.declination,
org.osgi.framework
Require-Bundle: com.sap.sailing.server.trackfiles,
com.sap.sailing.domain,
com.sap.sse.common,
@@ -5,11 +5,15 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.declination.DeclinationService;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
@@ -21,13 +25,17 @@ import com.sap.sailing.domain.trackimport.GPSFixImporter;
import com.sap.sailing.server.trackfiles.impl.CompressedStreamsUtil;
import com.sap.sailing.server.trackfiles.impl.ExpeditionExtendedDataImporterImpl;
import com.sap.sailing.server.trackfiles.impl.ExpeditionImportFileHandler;
import com.sap.sse.common.Bearing;
import com.sap.sse.common.impl.DegreeBearingImpl;
public class ExpeditionGPSFixImporter implements GPSFixImporter {
private static final Logger logger = Logger.getLogger(ExpeditionGPSFixImporter.class.getName());
private static final String LAT_COLUMN_HEADING = ExpeditionExtendedDataImporterImpl.COL_NAME_LAT;
private static final String LON_COLUMN_HEADING = ExpeditionExtendedDataImporterImpl.COL_NAME_LON;
private static final String COG_COLUMN_HEADING = "cog";
private static final String SOG_COLUMN_HEADING = "sog";
private static final String HDT_COLUMN_HEADING = "hdt";
@Override
public boolean importFixes(InputStream inputStream, Charset charset, Callback callback,
@@ -56,10 +64,23 @@ public class ExpeditionGPSFixImporter implements GPSFixImporter {
.parseDouble(columnValues[columns.get(COG_COLUMN_HEADING)]);
final double sogKnots = Double
.parseDouble(columnValues[columns.get(SOG_COLUMN_HEADING)]);
final DegreePosition position = new DegreePosition(latDeg, lonDeg);
Bearing optionalTrueHeading;
if (columns.containsKey(HDT_COLUMN_HEADING)) {
try {
optionalTrueHeading = new DegreeBearingImpl(Double.parseDouble(columnValues[columns.get(HDT_COLUMN_HEADING)]))
.add(DeclinationService.INSTANCE.getDeclination(timePoint, position, /* timeout ms */ 1000).getBearingCorrectedTo(timePoint));
} catch (NumberFormatException | IOException | ParseException e) {
logger.log(Level.WARNING, "Problem obtaining declination for Expedition fix heading", e);
optionalTrueHeading = null;
}
} else {
optionalTrueHeading = null;
}
final GPSFixMoving fix = new GPSFixMovingImpl(
new DegreePosition(latDeg, lonDeg), timePoint,
position, timePoint,
new KnotSpeedWithBearingImpl(sogKnots,
new DegreeBearingImpl(cogDeg)));
new DegreeBearingImpl(cogDeg)), optionalTrueHeading);
callback.addFix(fix, device);
importedFixes.set(true);
});
@@ -100,7 +100,7 @@ public class OceanRaceGPSFixImporter implements GPSFixImporter {
} else {
sogInKnots = 0.0;
}
return new GPSFixMovingImpl(position, timePoint, new KnotSpeedWithBearingImpl(sogInKnots, cog));
return new GPSFixMovingImpl(position, timePoint, new KnotSpeedWithBearingImpl(sogInKnots, cog), /* optionalTrueHeading */ null);
}
@Override
@@ -3,7 +3,7 @@ package com.sap.sailing.domain.persistence;
public enum FieldNames {
// general:
TIME_AS_MILLIS, KNOT_SPEED, DEGREE_BEARING, LAT_DEG, LNG_DEG,
TIME_AS_MILLIS, KNOT_SPEED, DEGREE_BEARING, LAT_DEG, LNG_DEG, TRUE_HEADING_DEG,
FLEET, RACE_IDENTIFIERS,
@@ -389,6 +389,16 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
return new KnotSpeedWithBearingImpl(((Number) object.get(FieldNames.KNOT_SPEED.name())).doubleValue(),
new DegreeBearingImpl(((Number) object.get(FieldNames.DEGREE_BEARING.name())).doubleValue()));
}
public Bearing loadOptionalTrueHeading(Document object) {
final Bearing result;
if (object.containsKey(FieldNames.TRUE_HEADING_DEG.name())) {
result = new DegreeBearingImpl(((Number) object.get(FieldNames.TRUE_HEADING_DEG.name())).doubleValue());
} else {
result = null;
}
return result;
}
@Override
public RaceIdentifier loadRaceIdentifier(Document dbObject) {
@@ -238,7 +238,12 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
public void storeSpeedWithBearing(SpeedWithBearing speedWithBearing, Document result) {
storeSpeed(speedWithBearing, result);
storeBearing(speedWithBearing.getBearing(), result);
}
public void storeOptionalTrueHeading(Bearing optionalTrueHeading, Document result) {
if (optionalTrueHeading != null) {
result.put(FieldNames.TRUE_HEADING_DEG.name(), optionalTrueHeading.getDegrees());
}
}
public void storeBearing(Bearing bearing, Document result) {
@@ -1,5 +1,7 @@
package com.sap.sailing.domain.persistence.racelog.tracking.impl;
import static com.sap.sailing.shared.persistence.impl.DomainObjectFactoryImpl.loadPosition;
import org.bson.Document;
import com.sap.sailing.domain.common.Position;
@@ -11,7 +13,7 @@ import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl;
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
import com.sap.sailing.domain.persistence.racelog.tracking.FixMongoHandler;
import static com.sap.sailing.shared.persistence.impl.DomainObjectFactoryImpl.loadPosition;
import com.sap.sse.common.Bearing;
import com.sap.sse.common.TimePoint;
public class GPSFixMovingMongoHandlerImpl implements FixMongoHandler<GPSFixMoving> {
@@ -27,17 +29,19 @@ public class GPSFixMovingMongoHandlerImpl implements FixMongoHandler<GPSFixMovin
public Document transformForth(GPSFixMoving fix) throws IllegalArgumentException {
Document result = new Document();
mof.storeTimed(fix, result);
mof.storePositioned(fix, result);
mof.storeSpeedWithBearing(fix.getSpeed(), result);
mof.storePositioned(fix, result);
mof.storeSpeedWithBearing(fix.getSpeed(), result);
mof.storeOptionalTrueHeading(fix.getOptionalTrueHeading(), result);
return result;
}
@Override
public GPSFixMoving transformBack(Document dbObject) {
TimePoint timePoint = dof.loadTimePoint(dbObject);
Position position = loadPosition(dbObject);
SpeedWithBearing speed = dof.loadSpeedWithBearing(dbObject);
return new GPSFixMovingImpl(position, timePoint, speed);
final TimePoint timePoint = dof.loadTimePoint(dbObject);
final Position position = loadPosition(dbObject);
final SpeedWithBearing speed = dof.loadSpeedWithBearing(dbObject);
final Bearing optionalTrueHeading = dof.loadOptionalTrueHeading(dbObject);
return new GPSFixMovingImpl(position, timePoint, speed, optionalTrueHeading);
}
}
@@ -73,7 +73,7 @@ public class AbstractGPSFixStoreTest extends RaceLogTrackingTestHelper {
protected GPSFixMoving createFix(long millis, double lat, double lng, double knots, double degrees) {
return new GPSFixMovingImpl(new DegreePosition(lat, lng),
new MillisecondsTimePoint(millis), new KnotSpeedWithBearingImpl(knots, new DegreeBearingImpl(degrees)));
new MillisecondsTimePoint(millis), new KnotSpeedWithBearingImpl(knots, new DegreeBearingImpl(degrees)), /* optionalTrueHeading */ null);
}
protected GPSFix createFix(long millis, double lat, double lng) {
@@ -169,9 +169,9 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
private void addFixes0(DeviceIdentifier dev1) throws TransformationException,
NoCorrespondingServiceRegisteredException {
sensorFixStore.storeFix(dev1, new GPSFixMovingImpl(new DegreePosition(0, 0), t(5), new KnotSpeedWithBearingImpl(
10, new DegreeBearingImpl(5))));
10, new DegreeBearingImpl(5)), /* optionalTrueHeading */ null));
sensorFixStore.storeFix(dev1, new GPSFixMovingImpl(new DegreePosition(0, 0), t(15), new KnotSpeedWithBearingImpl(
10, new DegreeBearingImpl(5))));
10, new DegreeBearingImpl(5)), /* optionalTrueHeading */ null));
}
private void addFixes1(TrackedRace race, Competitor comp1, DeviceIdentifier dev1) throws TransformationException,
@@ -180,9 +180,9 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
testSize(race.getTrack(comp1), 1);
// further fix arrives in race
sensorFixStore.storeFix(dev1, new GPSFixMovingImpl(new DegreePosition(0, 0), t(7), new KnotSpeedWithBearingImpl(
10, new DegreeBearingImpl(5))));
10, new DegreeBearingImpl(5)), /* optionalTrueHeading */ null));
sensorFixStore.storeFix(dev1, new GPSFixMovingImpl(new DegreePosition(0, 0), t(14), new KnotSpeedWithBearingImpl(
10, new DegreeBearingImpl(5)))); // outside mapping range
10, new DegreeBearingImpl(5)), /* optionalTrueHeading */ null)); // outside mapping range
testSize(race.getTrack(comp1), 2);
}
@@ -192,7 +192,7 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
testSize(race.getTrack(comp1), 4);
// add another fix in new mapping range
sensorFixStore.storeFix(dev1, new GPSFixMovingImpl(new DegreePosition(0, 0), t(18), new KnotSpeedWithBearingImpl(
10, new DegreeBearingImpl(5))));
10, new DegreeBearingImpl(5)), /* optionalTrueHeading */ null));
testSize(race.getTrack(comp1), 5);
}
@@ -200,7 +200,7 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
NoCorrespondingServiceRegisteredException {
// stop tracking, then no more fixes arrive at race
sensorFixStore.storeFix(dev1, new GPSFixMovingImpl(new DegreePosition(0, 0), t(8), new KnotSpeedWithBearingImpl(
10, new DegreeBearingImpl(5))));
10, new DegreeBearingImpl(5)), /* optionalTrueHeading */ null));
testSize(race.getTrack(comp1), 5);
}
@@ -38,10 +38,6 @@ import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.CompetitorRegistrationType;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.persistence.PersistenceFactory;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.MongoSensorFixStoreImpl;
import com.sap.sailing.domain.racelog.RaceLogAndTrackedRaceResolver;
@@ -62,8 +58,6 @@ import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sse.common.Timed;
import com.sap.sse.common.impl.DegreeBearingImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class RaceLogFixTrackerManagerTest {
protected final MockSmartphoneImeiServiceFinderFactory serviceFinderFactory = new MockSmartphoneImeiServiceFinderFactory();
@@ -83,11 +77,6 @@ public class RaceLogFixTrackerManagerTest {
protected final AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0);
private DynamicTrackedRace trackedRace;
protected GPSFixMoving createFix(long millis, double lat, double lng, double knots, double degrees) {
return new GPSFixMovingImpl(new DegreePosition(lat, lng), new MillisecondsTimePoint(millis),
new KnotSpeedWithBearingImpl(knots, new DegreeBearingImpl(degrees)));
}
@Before
public void setUp() throws UnknownHostException, MongoException {
raceLog = new RaceLogImpl("racelog");
@@ -141,11 +141,6 @@ public class SensorFixStoreAndLoadTest {
protected final AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0);
private DynamicTrackedRace trackedRace;
protected GPSFixMoving createFix(long millis, double lat, double lng, double knots, double degrees) {
return new GPSFixMovingImpl(new DegreePosition(lat, lng), new MillisecondsTimePoint(millis),
new KnotSpeedWithBearingImpl(knots, new DegreeBearingImpl(degrees)));
}
@Before
public void setUp() throws UnknownHostException, MongoException {
dropPersistedData();
@@ -691,11 +686,11 @@ public class SensorFixStoreAndLoadTest {
final MillisecondsTimePoint timePoint2 = new MillisecondsTimePoint(FIX_TIMESTAMP2);
final MillisecondsTimePoint timePoint3 = new MillisecondsTimePoint(FIX_TIMESTAMP3);
final TimePoint timePointBetween2And3 = new MillisecondsTimePoint((FIX_TIMESTAMP2+FIX_TIMESTAMP3)/2);
final GPSFixMoving fix1 = new GPSFixMovingImpl(pos1, timePoint, speed);
final GPSFixMoving fix1 = new GPSFixMovingImpl(pos1, timePoint, speed, /* optionalTrueHeading */ null);
final Position pos2 = pos1.translateGreatCircle(course, speed.travel(timePoint.until(timePoint2)));
final GPSFixMoving fix2 = new GPSFixMovingImpl(pos2, timePoint2, speed);
final GPSFixMoving fix2 = new GPSFixMovingImpl(pos2, timePoint2, speed, /* optionalTrueHeading */ null);
final Position pos3 = pos2.translateGreatCircle(course, speed.travel(timePoint2.until(timePoint3)));
final GPSFixMoving fix3 = new GPSFixMovingImpl(pos3, timePoint3, speed);
final GPSFixMoving fix3 = new GPSFixMovingImpl(pos3, timePoint3, speed, /* optionalTrueHeading */ null);
gpsFixTrack.add(fix1);
gpsFixTrack.add(fix2);
gpsFixTrack.add(fix3);
@@ -710,7 +705,7 @@ public class SensorFixStoreAndLoadTest {
final DegreeBearingImpl temporaryCourse = new DegreeBearingImpl(90);
final GPSFixMoving fixBetween2And3 = new GPSFixMovingImpl(
pos2.translateGreatCircle(temporaryCourse, speed.add(new KnotSpeedWithBearingImpl(5, temporaryCourse)).travel(timePoint2.until(timePointBetween2And3))),
timePointBetween2And3, speed);
timePointBetween2And3, speed, /* optionalTrueHeading */ null);
gpsFixTrack.add(fixBetween2And3);
final Distance distanceTraveledDifferently = gpsFixTrack.getDistanceTraveled(timePoint, timePoint3);
assertTrue(distanceTraveledDifferently.compareTo(distanceTraveled) > 0);
@@ -721,7 +716,7 @@ public class SensorFixStoreAndLoadTest {
final SpeedWithBearing doubledSpeed = speed.add(speed);
final GPSFixMoving fix3Faster = new GPSFixMovingImpl(
pos2.translateGreatCircle(course, doubledSpeed.travel(timePoint2.until(timePoint3))),
timePoint3, doubledSpeed);
timePoint3, doubledSpeed, /* optionalTrueHeading */ null);
gpsFixTrack.add(fix3Faster, /* replace */ true);
final Distance distanceTraveledFaster = gpsFixTrack.getDistanceTraveled(timePoint, timePoint3);
assertTrue(distanceTraveledFaster.compareTo(distanceTraveled) > 0);
@@ -18,13 +18,9 @@ import com.mongodb.ReadConcern;
import com.mongodb.WriteConcern;
import com.mongodb.client.MongoDatabase;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata;
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.common.tracking.impl.DoubleVectorFixImpl;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.persistence.PersistenceFactory;
import com.sap.sailing.domain.persistence.impl.CollectionNames;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.MongoSensorFixStoreImpl;
@@ -35,7 +31,6 @@ import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifie
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.Timed;
import com.sap.sse.common.TransformationException;
import com.sap.sse.common.impl.DegreeBearingImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.impl.TimeRangeImpl;
@@ -49,11 +44,6 @@ public class SensorFixStoreTest {
protected final DeviceIdentifier device2 = new SmartphoneImeiIdentifier("b");
protected SensorFixStore store;
protected GPSFixMoving createFix(long millis, double lat, double lng, double knots, double degrees) {
return new GPSFixMovingImpl(new DegreePosition(lat, lng), new MillisecondsTimePoint(millis),
new KnotSpeedWithBearingImpl(knots, new DegreeBearingImpl(degrees)));
}
@Before
public void setUp() throws UnknownHostException, MongoException {
dropPersistedData();
@@ -88,7 +88,7 @@ public class PostFixes extends AbstractJsonOverHttpTest {
lastFix = fix;
try {
recordFix(new GPSFixMovingImpl(fix.getPosition(), fix.getTimePoint(), speed));
recordFix(new GPSFixMovingImpl(fix.getPosition(), fix.getTimePoint(), speed, /* optionalTrueHeading */ null));
} catch (IOException e) {
e.printStackTrace();
}
@@ -379,7 +379,7 @@ public class DomainFactoryImpl implements DomainFactory {
@Override
public GPSFixMoving createGPSFix(TimePoint timePointOfTransmission, Fix fix) {
GPSFixMoving result = new GPSFixMovingImpl(fix.getPosition(), new MillisecondsTimePoint(
timePointOfTransmission.asMillis() + fix.getAgeOfDataInMilliseconds()), fix.getSpeed());
timePointOfTransmission.asMillis() + fix.getAgeOfDataInMilliseconds()), fix.getSpeed(), /* optionalTrueHeading */ null);
return result;
}
@@ -494,7 +494,7 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i
TimePoint raceTimePoint = raceTimePerRaceID.containsKey(currentRaceID) ? raceTimePerRaceID.get(currentRaceID) : referenceTimePoint;
Bearing bearing = new DegreeBearingImpl(cog);
SpeedWithBearing speed = new KnotSpeedWithBearingImpl(((double) sog_Knots_x10) / 10., bearing);
GPSFixMoving fix = new GPSFixMovingImpl(position, raceTimePoint, speed);
GPSFixMoving fix = new GPSFixMovingImpl(position, raceTimePoint, speed, /* optionalTrueHeading */ null);
Mark mark = markByHashValue.get(hashValue);
if (mark != null) {
Iterator<Entry<ControlPoint, SpeedWithBearing>> i = windAtControlPoint.entrySet().iterator();
@@ -188,9 +188,9 @@ public class CandidateFinderImplWhiteBoxTest {
final Position beforeStartPosition = startLinePosition.translateGreatCircle(startLineCrossingSpeed.getBearing().reverse(), startLineCrossingSpeed.travel(Duration.ONE_SECOND));
final Position atStartPosition = startLinePosition;
final Position afterStartPosition = startLinePosition.translateGreatCircle(startLineCrossingSpeed.getBearing(), startLineCrossingSpeed.travel(Duration.ONE_SECOND));
trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(beforeStartPosition, timeForStartLinePassing.minus(Duration.ONE_SECOND), startLineCrossingSpeed));
trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(atStartPosition, timeForStartLinePassing, startLineCrossingSpeed));
trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(afterStartPosition, timeForStartLinePassing.plus(Duration.ONE_SECOND), startLineCrossingSpeed));
trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(beforeStartPosition, timeForStartLinePassing.minus(Duration.ONE_SECOND), startLineCrossingSpeed, /* optionalTrueHeading */ null));
trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(atStartPosition, timeForStartLinePassing, startLineCrossingSpeed, /* optionalTrueHeading */ null));
trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(afterStartPosition, timeForStartLinePassing.plus(Duration.ONE_SECOND), startLineCrossingSpeed, /* optionalTrueHeading */ null));
}
@Test
@@ -50,7 +50,7 @@ public class StationarySequenceBasedFilterTest extends AbstractCandidateFilterTe
if (previousTimePoint != null) {
position = verySmallSpeed.travelTo(position, durationBetweenFixes);
}
track.add(new GPSFixMovingImpl(position, timePoint, verySmallSpeed));
track.add(new GPSFixMovingImpl(position, timePoint, verySmallSpeed, /* optionalTrueHeading */ null));
timePoint = timePoint.plus(durationBetweenFixes);
}
previousTimePoint = candidate.getTimePoint();
@@ -88,7 +88,7 @@ public class StationarySequenceBasedFilterTest extends AbstractCandidateFilterTe
outlierCourse, StationarySequence.CANDIDATE_FILTER_DISTANCE.scale(2));
final TimePoint inBetweenTimePoint = fixAtC2.getTimePoint().plus(fixAtC2.getTimePoint().until(fixAfterFixAtC2.getTimePoint()).divide(2));
final Speed outlierSpeed = fixAtC2.getPosition().getDistance(outlierPosition).inTime(fixAtC2.getTimePoint().until(inBetweenTimePoint));
final GPSFixMoving fixInBetween = new GPSFixMovingImpl(outlierPosition, inBetweenTimePoint, new KnotSpeedWithBearingImpl(outlierSpeed.getKnots(), outlierCourse));
final GPSFixMoving fixInBetween = new GPSFixMovingImpl(outlierPosition, inBetweenTimePoint, new KnotSpeedWithBearingImpl(outlierSpeed.getKnots(), outlierCourse), /* optionalTrueHeading */ null);
track.add(fixInBetween);
TreeSet<Candidate> candidatesEffectivelyAdded = new TreeSet<>(candidateComparator);
TreeSet<Candidate> candidatesEffectivelyRemoved = new TreeSet<>(candidateComparator);
@@ -69,7 +69,7 @@ public class StationarySequenceTest extends AbstractCandidateFilterTestSupport {
if (previousTimePoint != null) {
position = verySmallSpeed.travelTo(position, durationBetweenFixes);
}
track.add(new GPSFixMovingImpl(position, timePoint, verySmallSpeed));
track.add(new GPSFixMovingImpl(position, timePoint, verySmallSpeed, /* optionalTrueHeading */ null));
timePoint = timePoint.plus(durationBetweenFixes);
}
previousTimePoint = candidate.getTimePoint();
@@ -108,7 +108,7 @@ public class StationarySequenceTest extends AbstractCandidateFilterTestSupport {
final Position originalPosition = track.getEstimatedPosition(timePointForNewFix, /* extrapolate */ false);
final Position westPosition = originalPosition.translateGreatCircle(new DegreeBearingImpl(270), StationarySequence.CANDIDATE_FILTER_DISTANCE.scale(0.5));
final Position eastPosition = originalPosition.translateGreatCircle(new DegreeBearingImpl(90), StationarySequence.CANDIDATE_FILTER_DISTANCE.scale(0.5));
final GPSFixMovingImpl westFix = new GPSFixMovingImpl(westPosition, timePointForNewFix, originalPosition.getSpeedWithBearingToReachOnGreatCircle(westPosition, c2.getTimePoint().until(timePointForNewFix)));
final GPSFixMovingImpl westFix = new GPSFixMovingImpl(westPosition, timePointForNewFix, originalPosition.getSpeedWithBearingToReachOnGreatCircle(westPosition, c2.getTimePoint().until(timePointForNewFix)), /* optionalTrueHeading */ null);
track.add(westFix);
final Set<Candidate> candidatesEffectivelyAdded = new HashSet<>();
final Set<Candidate> candidatesEffectivelyRemoved = new HashSet<>();
@@ -118,7 +118,7 @@ public class StationarySequenceTest extends AbstractCandidateFilterTestSupport {
assertEquals(3, Util.size(stationarySequence.getAllCandidates())); // and all candidates should still be part of the sequence
assertTrue(candidatesEffectivelyAdded.isEmpty());
assertTrue(candidatesEffectivelyRemoved.isEmpty());
final GPSFixMovingImpl eastFix = new GPSFixMovingImpl(eastPosition, timePointForNewFix, originalPosition.getSpeedWithBearingToReachOnGreatCircle(eastPosition, c2.getTimePoint().until(timePointForNewFix)));
final GPSFixMovingImpl eastFix = new GPSFixMovingImpl(eastPosition, timePointForNewFix, originalPosition.getSpeedWithBearingToReachOnGreatCircle(eastPosition, c2.getTimePoint().until(timePointForNewFix)), /* optionalTrueHeading */ null);
track.add(eastFix, /* replace */ true);
final StationarySequence resultForEastFix = stationarySequence.tryToAddFix(eastFix, candidatesEffectivelyAdded, candidatesEffectivelyRemoved, stationarySequenceSetToUpdate, /* isReplacement */ true);
assertNull(resultForEastFix); // again no split should have been necessary
@@ -232,7 +232,7 @@ public class TestCrossFleetScoring extends LeaderboardScoringAndRankingTestBase
Competitor competitor = competitors.get(competitorName);
MarkPassingImpl markPassing = new MarkPassingImpl(startOfRace, start, competitor);
GPSFixMovingImpl gpsFix = new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(45)));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(45)), /* optionalTrueHeading */ null);
addMarkPassingAndGPSFix(competitorsAndMarkPassingsWithGpsFixes, competitor, markPassing, gpsFix);
}
@@ -257,7 +257,7 @@ public class TestCrossFleetScoring extends LeaderboardScoringAndRankingTestBase
Map<Competitor, Pair<List<MarkPassing>, List<GPSFixMovingImpl>>> competitorsAndMarkPassingsWithGpsFixes,
String competitorName, DegreePosition position, TimePoint timePoint) {
GPSFixMovingImpl gpsFix = new GPSFixMovingImpl(position, timePoint,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(45)));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(45)), /* optionalTrueHeading */ null);
competitorsAndMarkPassingsWithGpsFixes.get(competitors.get(competitorName)).getB().add(gpsFix);
}
@@ -478,13 +478,13 @@ public class TestCrossFleetScoring extends LeaderboardScoringAndRankingTestBase
Competitor fastYellow = competitors.get("FastYellowBoat");
MarkPassingImpl markPassingFastYellow = new MarkPassingImpl(markRounding, windward, fastYellow);
GPSFixMovingImpl gpsFixFastYellow = new GPSFixMovingImpl(new DegreePosition(1.0, 0), markRounding,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(180)));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(180)), /* optionalTrueHeading */ null);
addMarkPassingAndGPSFix(competitorsAndMarkPassingsWithGpsFixes, fastYellow, markPassingFastYellow, gpsFixFastYellow);
// markRounding for SlowYellow
Competitor slowYellow = competitors.get("SlowYellowBoat");
MarkPassingImpl markPassingSlowYellow = new MarkPassingImpl(markRounding, windward, slowYellow);
GPSFixMovingImpl gpsFixSlowYellow = new GPSFixMovingImpl(new DegreePosition(1.0, 0), markRounding,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(180)));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(180)), /* optionalTrueHeading */ null);
addMarkPassingAndGPSFix(competitorsAndMarkPassingsWithGpsFixes, slowYellow, markPassingSlowYellow, gpsFixSlowYellow);
// add current Position
appendGPSFixForCompetitor(competitorsAndMarkPassingsWithGpsFixes, "FastYellowBoat", new DegreePosition(0.4, 0),
@@ -516,25 +516,25 @@ public class TestCrossFleetScoring extends LeaderboardScoringAndRankingTestBase
Competitor fastYellow = competitors.get("FastYellowBoat");
MarkPassingImpl markPassingFastYellow = new MarkPassingImpl(markRounding, windward, fastYellow);
GPSFixMovingImpl gpsFixFastYellow = new GPSFixMovingImpl(new DegreePosition(1.0, 0), markRounding,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(180)));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(180)), /* optionalTrueHeading */ null);
addMarkPassingAndGPSFix(competitorsAndMarkPassingsWithGpsFixes, fastYellow, markPassingFastYellow, gpsFixFastYellow);
// markRounding for SlowYellow
Competitor slowYellow = competitors.get("SlowYellowBoat");
MarkPassingImpl markPassingSlowYellow = new MarkPassingImpl(markRounding, windward, slowYellow);
GPSFixMovingImpl gpsFixSlowYellow = new GPSFixMovingImpl(new DegreePosition(1.0, 0), markRounding,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(180)));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(180)), /* optionalTrueHeading */ null);
addMarkPassingAndGPSFix(competitorsAndMarkPassingsWithGpsFixes, slowYellow, markPassingSlowYellow, gpsFixSlowYellow);
// markRounding for FastBlue
Competitor fastBlue = competitors.get("FastYellowBoat");
MarkPassingImpl markPassingFastBlue = new MarkPassingImpl(markRounding, windward, fastBlue);
GPSFixMovingImpl gpsFixFastBlue = new GPSFixMovingImpl(new DegreePosition(1.0, 0), markRounding,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(180)));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(180)), /* optionalTrueHeading */ null);
addMarkPassingAndGPSFix(competitorsAndMarkPassingsWithGpsFixes, fastBlue, markPassingFastBlue, gpsFixFastBlue);
// markRounding for SlowYellow
Competitor slowBlue = competitors.get("SlowYellowBoat");
MarkPassingImpl markPassingSlowslowBlue = new MarkPassingImpl(markRounding, windward, slowBlue);
GPSFixMovingImpl gpsFixSlowslowBlue = new GPSFixMovingImpl(new DegreePosition(1.0, 0), markRounding,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(180)));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(180)), /* optionalTrueHeading */ null);
addMarkPassingAndGPSFix(competitorsAndMarkPassingsWithGpsFixes, slowBlue, markPassingSlowslowBlue, gpsFixSlowslowBlue);
// add current Position
appendGPSFixForCompetitor(competitorsAndMarkPassingsWithGpsFixes, "FastYellowBoat", new DegreePosition(0.1, 0),
@@ -154,16 +154,16 @@ public class TestFarthestAheadWithSkippedMarkPassing {
Arrays.<MarkPassing> asList(new MarkPassingImpl(startOfRace, start, c1)));
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
new DegreeBearingImpl(315)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
new DegreeBearingImpl(315)), /* optionalTrueHeading */ null));
// Both boats have climbed half of the first upwind beat; c1 is rated the faster boat (2.0), c2 has time-on-time factor 1.0.
// Therefore, c2 is expected to lead after applying the corrections.
final RankingInfo rankingInfo = rankingMetric.getRankingInfo(middleOfFirstLeg);
@@ -192,24 +192,24 @@ public class TestFarthestAheadWithSkippedMarkPassing {
// they both start at the start line
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
new DegreeBearingImpl(315)), /* optionalTrueHeading */ null));
// both round the windward mark at the same time
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(1.0, 0), endOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(1.0, 0), endOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
new DegreeBearingImpl(315)), /* optionalTrueHeading */ null));
// c2 is further down the wind already at the middle of the second leg:
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfSecondLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(180))));
new DegreeBearingImpl(180)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.2, 0), middleOfSecondLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(180))));
new DegreeBearingImpl(180)), /* optionalTrueHeading */ null));
// Assert that c2 is the boat farthest ahead
final RankingInfo rankingInfo = rankingMetric.getRankingInfo(middleOfSecondLeg);
assertSame(c2, rankingInfo.getCompetitorFarthestAhead());
@@ -129,16 +129,16 @@ public class TestSimpleTimeOnTimeRankingWithOneUpwindLeg {
.getFirstWaypoint(), c2)));
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
new DegreeBearingImpl(315)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
new DegreeBearingImpl(315)), /* optionalTrueHeading */ null));
// Both boats have climbed half of the first upwind beat; c1 is rated the faster boat (2.0), c2 has time-on-time factor 1.0.
// Therefore, c2 is expected to lead after applying the corrections.
Comparator<Competitor> comparator = tot.getRaceRankingComparator(middleOfFirstLeg);
@@ -160,16 +160,16 @@ public class TestSimpleTimeOnTimeRankingWithOneUpwindLeg {
.getFirstWaypoint(), c2)));
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
new DegreeBearingImpl(315)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(1.0, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
new DegreeBearingImpl(315)), /* optionalTrueHeading */ null));
// Using a white-box test, assert that the ranking-relevant numbers are sufficiently close to each other
final RankingMetric.RankingInfo rankingInfo = tot.getRankingInfo(middleOfFirstLeg);
assertSame(c1, rankingInfo.getCompetitorFarthestAhead());
@@ -195,16 +195,16 @@ public class TestSimpleTimeOnTimeRankingWithOneUpwindLeg {
.getFirstWaypoint(), c2)));
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
new DegreeBearingImpl(315)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
new DegreeBearingImpl(315)), /* optionalTrueHeading */ null));
// Both boats have climbed half of the first upwind beat; c1 is rated the faster boat (2.0), c2 has time-on-time factor 1.0.
// Therefore, c2 is expected to lead after applying the corrections.
Comparator<Competitor> comparator = tot.getRaceRankingComparator(middleOfFirstLeg);
@@ -226,16 +226,16 @@ public class TestSimpleTimeOnTimeRankingWithOneUpwindLeg {
.getFirstWaypoint(), c2)));
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.0, 0), startOfRace, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
new DegreeBearingImpl(315)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c1).add(
new GPSFixMovingImpl(new DegreePosition(1.0, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(45))));
new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
trackedRace.getTrack(c2).add(
new GPSFixMovingImpl(new DegreePosition(0.5, 0), middleOfFirstLeg, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(315))));
new DegreeBearingImpl(315)), /* optionalTrueHeading */ null));
// Using a white-box test, assert that the ranking-relevant numbers are sufficiently close to each other,
// in this case .05 seconds per nautical mile for the reciproke VMG measured in seconds per nautical mile
final RankingMetric.RankingInfo rankingInfo = tot.getRankingInfo(middleOfFirstLeg);
@@ -220,7 +220,7 @@ public class BravoFixTrackFoiledDistanceCacheTest {
private GPSFixMoving createGPSFix(long timePointAsMillis, double lat, double lng, double cogInDeg, double sogInKnots) {
return new GPSFixMovingImpl(new DegreePosition(lat, lng), new MillisecondsTimePoint(timePointAsMillis),
new KnotSpeedWithBearingImpl(sogInKnots, new DegreeBearingImpl(cogInDeg)));
new KnotSpeedWithBearingImpl(sogInKnots, new DegreeBearingImpl(cogInDeg)), /* optionalTrueHeading */ null);
}
private MillisecondsTimePoint t(long timePointAsMillis) {
@@ -61,12 +61,12 @@ public class CourseChangeBasedTrackApproximationTest {
}
private GPSFixMoving fix(long timepoint, double lat, double lon, double speedInKnots, double cogDeg) {
return new GPSFixMovingImpl(new DegreePosition(lat, lon), new MillisecondsTimePoint(timepoint), new KnotSpeedWithBearingImpl(speedInKnots, new DegreeBearingImpl(cogDeg)));
return new GPSFixMovingImpl(new DegreePosition(lat, lon), new MillisecondsTimePoint(timepoint), new KnotSpeedWithBearingImpl(speedInKnots, new DegreeBearingImpl(cogDeg)), /* optionalTrueHeading */ null);
}
private GPSFixMoving travel(GPSFixMoving fix, long durationInMillis, double speedInKnots, double cogDeg) {
return new GPSFixMovingImpl(fix.getPosition().translateGreatCircle(new DegreeBearingImpl(cogDeg), new KnotSpeedImpl(speedInKnots).travel(new MillisecondsDurationImpl(durationInMillis))),
fix.getTimePoint().plus(durationInMillis), new KnotSpeedWithBearingImpl(speedInKnots, new DegreeBearingImpl(cogDeg)));
fix.getTimePoint().plus(durationInMillis), new KnotSpeedWithBearingImpl(speedInKnots, new DegreeBearingImpl(cogDeg)), /* optionalTrueHeading */ null);
}
}
@@ -57,9 +57,9 @@ public class DistanceCacheInvalidationAfterLoadingFinishedTest extends TrackBase
final Position startPos = new DegreePosition(0, 0);
final DegreeBearingImpl bearing = new DegreeBearingImpl(10);
final KnotSpeedWithBearingImpl speed = new KnotSpeedWithBearingImpl(10, bearing);
trackedRace.recordFix(competitor, new GPSFixMovingImpl(startPos, now, speed));
trackedRace.recordFix(competitor, new GPSFixMovingImpl(startPos, now, speed, /* optionalTrueHeading */ null));
final Distance distance = speed.travel(Duration.ONE_SECOND);
trackedRace.recordFix(competitor, new GPSFixMovingImpl(startPos.translateGreatCircle(bearing, distance), now.plus(Duration.ONE_SECOND), speed));
trackedRace.recordFix(competitor, new GPSFixMovingImpl(startPos.translateGreatCircle(bearing, distance), now.plus(Duration.ONE_SECOND), speed, /* optionalTrueHeading */ null));
trackedRace.onStatusChanged(tdl, new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, /* progress */ 1.0));
assertEquals(distance.getMeters(), trackedRace.getDistanceTraveled(competitor, now.plus(Duration.ONE_SECOND.times(2))).getMeters(), 0.01); // ask 1s after the second fix
}
@@ -70,7 +70,7 @@ public class LineAnalysisTest extends TrackBasedTest {
final Position lineMiddle = leftPos.translateGreatCircle(lineBearingFromLeftToRight, leftPos.getDistance(rightPos).scale(0.5));
final Distance distanceBehindLine = new MeterDistance(10);
final Position behindMiddleOfLine = lineMiddle.translateGreatCircle(awayFromCourseSideOrthogonalToLine, distanceBehindLine);
trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(behindMiddleOfLine, now, new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45))));
trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(behindMiddleOfLine, now, new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
assertEquals(distanceBehindLine.getMeters(), trackedRace.getDistanceToStartLine(competitor, now).getMeters(), 0.01);
}
@@ -85,7 +85,7 @@ public class LineAnalysisTest extends TrackBasedTest {
final Position outsideOfLine = rightPos.translateGreatCircle(lineBearingFromLeftToRight, new MeterDistance(30)); // 30m right of start boat
final Distance distanceBehindLine = new MeterDistance(10);
final Position behindOutsideOfLine = outsideOfLine.translateGreatCircle(awayFromCourseSideOrthogonalToLine, distanceBehindLine);
trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(behindOutsideOfLine, now, new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45))));
trackedRace.getTrack(competitor).add(new GPSFixMovingImpl(behindOutsideOfLine, now, new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
// the distance is that of the hypotenuse formed by the two cathesuses of 10m and 30m length, respectively:
assertEquals(Math.sqrt(10.*10.+30.*30.), trackedRace.getDistanceToStartLine(competitor, now).getMeters(), 0.01);
}
@@ -51,7 +51,7 @@ public class MarkPositionTimeFilterTest {
@Test
public void testAddFixForMark() {
trackedRace.recordFix(m, new GPSFixMovingImpl(new DegreePosition(12, 13), MillisecondsTimePoint.now(),
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))), /* onlyWhenInTrackingInterval */ true);
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null), /* onlyWhenInTrackingInterval */ true);
track.lockForRead();
try {
assertEquals(1, track.getRawFixes().size());
@@ -68,7 +68,7 @@ public class MarkPositionTimeFilterTest {
when(trackedRace.getStartOfTracking()).thenReturn(start);
when(trackedRace.getEndOfTracking()).thenReturn(end);
trackedRace.recordFix(m, new GPSFixMovingImpl(new DegreePosition(12, 13), fix,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))), /* onlyWhenInTrackingInterval */ true);
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null), /* onlyWhenInTrackingInterval */ true);
track.lockForRead();
try {
assertEquals(1, track.getRawFixes().size());
@@ -85,7 +85,7 @@ public class MarkPositionTimeFilterTest {
when(trackedRace.getStartOfTracking()).thenReturn(start);
when(trackedRace.getEndOfTracking()).thenReturn(end);
trackedRace.recordFix(m, new GPSFixMovingImpl(new DegreePosition(12, 13), fix,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))), /* onlyWhenInTrackingInterval */ true);
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null), /* onlyWhenInTrackingInterval */ true);
track.lockForRead();
try {
assertTrue(track.getRawFixes().isEmpty());
@@ -102,7 +102,7 @@ public class MarkPositionTimeFilterTest {
when(trackedRace.getStartOfTracking()).thenReturn(start);
when(trackedRace.getEndOfTracking()).thenReturn(end);
trackedRace.recordFix(m, new GPSFixMovingImpl(new DegreePosition(12, 13), fix,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))), /* onlyWhenInTrackingInterval */ true);
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null), /* onlyWhenInTrackingInterval */ true);
track.lockForRead();
try {
assertTrue(track.getRawFixes().isEmpty());
@@ -111,7 +111,7 @@ public class MarkPositionTimeFilterTest {
}
when(trackedRace.getEndOfTracking()).thenReturn(fix.plus(10000));
trackedRace.recordFix(m, new GPSFixMovingImpl(new DegreePosition(12, 13), fix,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))), /* onlyWhenInTrackingInterval */ true);
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null), /* onlyWhenInTrackingInterval */ true);
track.lockForRead();
try {
assertEquals(1, track.getRawFixes().size());
@@ -64,7 +64,7 @@ public class PositionTest {
public void testEqualityBetweenCompactAndVerboseSpeedWithBearing() throws CompactionNotPossibleException {
Position p1 = new DegreePosition(49.2, 008.3);
SpeedWithBearing swb = new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123));
VeryCompactGPSFixMovingImpl compactFix = new VeryCompactGPSFixMovingImpl(p1, MillisecondsTimePoint.now(), swb);
VeryCompactGPSFixMovingImpl compactFix = new VeryCompactGPSFixMovingImpl(p1, MillisecondsTimePoint.now(), swb, /* optionalTrueHeading */ null);
assertNotSame(p1, compactFix.getPosition());
PositionAssert.assertPositionEquals(p1, compactFix.getPosition(), 0.000001);
assertNotSame(swb, compactFix.getSpeed());
@@ -193,11 +193,11 @@ public class ReachingLegTest extends TrackBasedTest {
getTrackedRace().recordFix(
hunger,
new GPSFixMovingImpl(offsetMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(270))));
new DegreeBearingImpl(270)), /* optionalTrueHeading */ null));
getTrackedRace().recordFix(
plattner,
new GPSFixMovingImpl(windwardMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(270))));
new DegreeBearingImpl(270)), /* optionalTrueHeading */ null));
assertEquals(0.,
getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
.getDistance(offsetMarkPos).getMeters(), 0.00001);
@@ -223,11 +223,11 @@ public class ReachingLegTest extends TrackBasedTest {
getTrackedRace().recordFix(
hunger,
new GPSFixMovingImpl(offsetMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(270))));
new DegreeBearingImpl(270)), /* optionalTrueHeading */ null));
getTrackedRace().recordFix(
plattner,
new GPSFixMovingImpl(windwardMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(270))));
new DegreeBearingImpl(270)), /* optionalTrueHeading */ null));
assertEquals(0.,
getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
.getDistance(offsetMarkPos).getMeters(), 0.00001);
@@ -253,11 +253,11 @@ public class ReachingLegTest extends TrackBasedTest {
getTrackedRace().recordFix(
hunger,
new GPSFixMovingImpl(offsetMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(270))));
new DegreeBearingImpl(270)), /* optionalTrueHeading */ null));
getTrackedRace().recordFix(
plattner,
new GPSFixMovingImpl(windwardMarkPos, timePointInReaching, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(270))));
new DegreeBearingImpl(270)), /* optionalTrueHeading */ null));
assertEquals(0.,
getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointInReaching, /* extrapolate */false)
.getDistance(offsetMarkPos).getMeters(), 0.00001);
@@ -288,11 +288,11 @@ public class ReachingLegTest extends TrackBasedTest {
getTrackedRace().recordFix(
hunger,
new GPSFixMovingImpl(offsetMarkPos, timePointToConsider, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(270))));
new DegreeBearingImpl(270)), /* optionalTrueHeading */ null));
getTrackedRace().recordFix(
plattner,
new GPSFixMovingImpl(leewardPos, timePointToConsider, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(0))));
new DegreeBearingImpl(0)), /* optionalTrueHeading */ null));
assertEquals(0.,
getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointToConsider, /* extrapolate */false)
.getDistance(offsetMarkPos).getMeters(), 0.00001);
@@ -326,17 +326,17 @@ public class ReachingLegTest extends TrackBasedTest {
getTrackedRace().recordFix(
hunger,
new GPSFixMovingImpl(offsetMarkPos, timePointToConsider, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(270))));
new DegreeBearingImpl(270)), /* optionalTrueHeading */ null));
getTrackedRace().recordFix(
schomaeker,
new GPSFixMovingImpl(offsetMarkPos.translateGreatCircle(
offsetMarkPos.getBearingGreatCircle(leewardPos), offsetMarkPos.getDistance(leewardPos)
.scale(0.5)), timePointToConsider, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(180))));
new DegreeBearingImpl(180)), /* optionalTrueHeading */ null));
getTrackedRace().recordFix(
plattner,
new GPSFixMovingImpl(leewardPos, timePointToConsider, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(0))));
new DegreeBearingImpl(0)), /* optionalTrueHeading */ null));
assertEquals(0.,
getTrackedRace().getTrack(hunger).getEstimatedPosition(timePointToConsider, /* extrapolate */false)
.getDistance(offsetMarkPos).getMeters(), 0.00001);
@@ -367,13 +367,13 @@ public class ReachingLegTest extends TrackBasedTest {
hunger,
new GPSFixMovingImpl(windwardMarkPos.translateGreatCircle(new DegreeBearingImpl(reachingLegBearing.getDegrees()-45),
distanceOfReachingLeg.scale(1./Math.sqrt(2.))), timePointToConsider, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(270))));
new DegreeBearingImpl(270)), /* optionalTrueHeading */ null));
// Plattner turns right after the windward mark; both travel the same distance projected along the leg
getTrackedRace().recordFix(
plattner,
new GPSFixMovingImpl(windwardMarkPos.translateGreatCircle(new DegreeBearingImpl(reachingLegBearing.getDegrees()+45),
distanceOfReachingLeg.scale(1./Math.sqrt(2.))), timePointToConsider, new KnotSpeedWithBearingImpl(12,
new DegreeBearingImpl(270))));
new DegreeBearingImpl(270)), /* optionalTrueHeading */ null));
// with 90deg separating them, traveling 1/sqrt(2) the distance of the leg should put them the distance of the leg apart geometrically
assertEquals(
distanceOfReachingLeg.getMeters(),
@@ -124,7 +124,7 @@ public abstract class StoredTrackBasedTest extends TrackBasedTest {
TimePoint timePoint = new MillisecondsTimePoint(oi.readLong());
Position position = new DegreePosition(oi.readDouble(), oi.readDouble());
SpeedWithBearing speedWithBearing = new KnotSpeedWithBearingImpl(oi.readDouble(), new DegreeBearingImpl(oi.readDouble()));
return new GPSFixMovingImpl(position, timePoint, speedWithBearing);
return new GPSFixMovingImpl(position, timePoint, speedWithBearing, /* optionalTrueHeading */ null); // legacy fixes only; no need to worry about true heading
}
protected void storeTrack(Competitor competitor, Boat boat, DynamicGPSFixTrack<Competitor, GPSFixMoving> track, String regattaName)
@@ -67,7 +67,7 @@ public class TackTest extends StoredTrackBasedTestWithTrackedRace {
DynamicGPSFixTrack<Competitor, GPSFixMoving> hassosTrack = getTrackedRace().getTrack(competitor);
TimePoint now = MillisecondsTimePoint.now();
hassosTrack.addGPSFix(new GPSFixMovingImpl(new DegreePosition(54.4680424, 10.234451), now,
new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(45))));
new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(45)), /* optionalTrueHeading */ null));
assertEquals(Tack.PORT, getTrackedRace().getTack(competitor, now));
}
@@ -76,7 +76,7 @@ public class TackTest extends StoredTrackBasedTestWithTrackedRace {
DynamicGPSFixTrack<Competitor, GPSFixMoving> hassosTrack = getTrackedRace().getTrack(competitor);
TimePoint now = MillisecondsTimePoint.now();
hassosTrack.addGPSFix(new GPSFixMovingImpl(new DegreePosition(54.4680424, 10.234451), now,
new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(270))));
new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(270)), /* optionalTrueHeading */ null));
assertEquals(Tack.STARBOARD, getTrackedRace().getTack(competitor, now));
}
@@ -85,7 +85,7 @@ public class TackTest extends StoredTrackBasedTestWithTrackedRace {
DynamicGPSFixTrack<Competitor, GPSFixMoving> hassosTrack = getTrackedRace().getTrack(competitor);
TimePoint now = MillisecondsTimePoint.now();
hassosTrack.addGPSFix(new GPSFixMovingImpl(new DegreePosition(54.4680424, 10.234451), now,
new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(180))));
new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(180)), /* optionalTrueHeading */ null));
assertEquals(Tack.PORT, getTrackedRace().getTack(competitor, now));
}
@@ -85,25 +85,25 @@ public class TrackTest {
gpsFix1 = new GPSFixMovingImpl(
position1, now1, new KnotSpeedWithBearingImpl(position1.getDistance(position2)
.inTime(now2.asMillis() - now1.asMillis()).getKnots(),
new DegreeBearingImpl(90)));
new DegreeBearingImpl(90)), /* optionalTrueHeading */ null);
gpsFix2 = new GPSFixMovingImpl(position2, now2, new KnotSpeedWithBearingImpl(position1.getDistance(position2)
.inTime(now2.asMillis() - gpsFix1.getTimePoint().asMillis()).getKnots(), new DegreeBearingImpl(90)));
.inTime(now2.asMillis() - gpsFix1.getTimePoint().asMillis()).getKnots(), new DegreeBearingImpl(90)), /* optionalTrueHeading */ null);
TimePoint now3 = addMillisToTimepoint(now2, MILLIS_BETWEEN_FIXES);
Position position3 = new DegreePosition(1, 4);
gpsFix3 = new GPSFixMovingImpl(
position3, now3, new KnotSpeedWithBearingImpl(position2.getDistance(position3)
.inTime(now3.asMillis() - gpsFix2.getTimePoint().asMillis()).getKnots(),
new DegreeBearingImpl(0)));
new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
TimePoint now4 = addMillisToTimepoint(now3, MILLIS_BETWEEN_FIXES);
Position position4 = new DegreePosition(3, 4);
gpsFix4 = new GPSFixMovingImpl(
position4, now4, new KnotSpeedWithBearingImpl(position3.getDistance(position4)
.inTime(now4.asMillis() - gpsFix3.getTimePoint().asMillis()).getKnots(),
new DegreeBearingImpl(0)));
new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
TimePoint now5 = addMillisToTimepoint(now4, MILLIS_BETWEEN_FIXES);
Position position5 = new DegreePosition(5, 4);
gpsFix5 = new GPSFixMovingImpl(position5, now5, new KnotSpeedWithBearingImpl(position4.getDistance(position5)
.inTime(now5.asMillis() - gpsFix4.getTimePoint().asMillis()).getKnots(), new DegreeBearingImpl(0)));
.inTime(now5.asMillis() - gpsFix4.getTimePoint().asMillis()).getKnots(), new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
track.addGPSFix(gpsFix1);
track.addGPSFix(gpsFix2);
track.addGPSFix(gpsFix3);
@@ -136,8 +136,8 @@ public class TrackTest {
DegreePosition p2 = new DegreePosition(90, 0);
TimePoint t1 = MillisecondsTimePoint.now();
TimePoint t2 = t1.plus(30);
gpsFix1 = new GPSFixMovingImpl(p1, t1, new KnotSpeedWithBearingImpl(0, new DegreeBearingImpl(0)));
gpsFix2 = new GPSFixMovingImpl(p2, t2, new KnotSpeedWithBearingImpl(0, new DegreeBearingImpl(0)));
gpsFix1 = new GPSFixMovingImpl(p1, t1, new KnotSpeedWithBearingImpl(0, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
gpsFix2 = new GPSFixMovingImpl(p2, t2, new KnotSpeedWithBearingImpl(0, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
track.addGPSFix(gpsFix1);
track.addGPSFix(gpsFix2);
track.lockForRead();
@@ -246,7 +246,7 @@ public class TrackTest {
TimePoint start, Position pos, SpeedWithBearing speed, int numberOfFixes) {
TimePoint now = start;
for (int i = 0; i < numberOfFixes; i++) {
GPSFixMoving fix1 = new GPSFixMovingImpl(pos, now, speed);
GPSFixMoving fix1 = new GPSFixMovingImpl(pos, now, speed, /* optionalTrueHeading */ null);
track.addGPSFix(fix1);
now = now.plus(1000);
}
@@ -299,7 +299,7 @@ public class TrackTest {
}
};
GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(
1, new DegreeBearingImpl(123)));
1, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fix1);
// The following getMaximumSpeedOverGround call will trigger a computeMaxSpeed(...) and a cache(...) call
new Thread(()->
@@ -308,17 +308,17 @@ public class TrackTest {
// now don't release the cacheBarrier as yet but add more fixes
new Thread(() -> {
GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(3600000),
new KnotSpeedWithBearingImpl(2, new DegreeBearingImpl(123)));
new KnotSpeedWithBearingImpl(2, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fix2);
}).start();
new Thread(() -> {
GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(7200000),
new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(123)));
new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fix3);
}).start();
new Thread(() -> {
GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(10800000),
new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(123)));
new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fix4);
}).start();
cacheBarrier.await(); // releasing the creation of the cache entry from way above; this would now add a stale entry
@@ -375,18 +375,18 @@ public class TrackTest {
public void testMaxSpeedForMovingTrackWithFixAtIntervalBoundary() {
DynamicGPSFixMovingTrackImpl<Object> track = new DynamicGPSFixMovingTrackImpl<Object>(new Object(), /* millisecondsOverWhichToAverage */ 30000l);
GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(
1, new DegreeBearingImpl(123)));
1, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fix1);
GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(3600000), new KnotSpeedWithBearingImpl(
2, new DegreeBearingImpl(123)));
2, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fix2);
GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(7200000), new KnotSpeedWithBearingImpl(
1, new DegreeBearingImpl(123)));
1, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fix3);
assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(7200000)).
getB().getKnots(), 0.01); // produces a cache entry that ends
GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(10800000), new KnotSpeedWithBearingImpl(
1, new DegreeBearingImpl(123)));
1, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fix4);
assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(10800000)).
getB().getKnots(), 0.01);
@@ -396,9 +396,9 @@ public class TrackTest {
public void testMaxSpeedForFixOverwrittenWithLowerSpeed() {
DynamicGPSFixMovingTrackImpl<Object> track = new DynamicGPSFixMovingTrackImpl<Object>(new Object(), /* millisecondsOverWhichToAverage */ 30000l);
GPSFixMoving slow = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(3600000), new KnotSpeedWithBearingImpl(
1, new DegreeBearingImpl(123)));
1, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
GPSFixMoving fast = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(3600000), new KnotSpeedWithBearingImpl(
2, new DegreeBearingImpl(123)));
2, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fast);
assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(10800000)).
getB().getKnots(), 0.01);
@@ -417,18 +417,18 @@ public class TrackTest {
public void testMaxSpeedForMovingTrackWithFixAtIntervalBoundaryAfterQuery() {
DynamicGPSFixMovingTrackImpl<Object> track = new DynamicGPSFixMovingTrackImpl<Object>(new Object(), /* millisecondsOverWhichToAverage */ 30000l);
GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(0), new KnotSpeedWithBearingImpl(
1, new DegreeBearingImpl(123)));
1, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fix1);
GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(3600000), new KnotSpeedWithBearingImpl(
2, new DegreeBearingImpl(123)));
2, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fix2);
assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(7200000)).
getB().getKnots(), 0.01); // produces a cache entry that ends
GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(7200000), new KnotSpeedWithBearingImpl(
1, new DegreeBearingImpl(123)));
1, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fix3);
GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(10800000), new KnotSpeedWithBearingImpl(
1, new DegreeBearingImpl(123)));
1, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
track.addGPSFix(fix4);
assertEquals(2., track.getMaximumSpeedOverGround(new MillisecondsTimePoint(0), new MillisecondsTimePoint(10800000)).
getB().getKnots(), 0.01);
@@ -489,9 +489,9 @@ public class TrackTest {
TimePoint t1 = new MillisecondsTimePoint(1000);
TimePoint t2 = new MillisecondsTimePoint(2000);
TimePoint t3 = new MillisecondsTimePoint(3000);
GPSFixMoving f1 = new GPSFixMovingImpl(new DegreePosition(1./3600.*1./60., 0), t1, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)));
GPSFixMoving f2 = new GPSFixMovingImpl(new DegreePosition(2./3600.*1./60., 0), t2, new KnotSpeedWithBearingImpl(150, new DegreeBearingImpl(0))); // outrageous speed; to be ignored by getEstimatedSpeed
GPSFixMoving f3 = new GPSFixMovingImpl(new DegreePosition(3./3600.*1./60., 0), t3, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)));
GPSFixMoving f1 = new GPSFixMovingImpl(new DegreePosition(1./3600.*1./60., 0), t1, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
GPSFixMoving f2 = new GPSFixMovingImpl(new DegreePosition(2./3600.*1./60., 0), t2, new KnotSpeedWithBearingImpl(150, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null); // outrageous speed; to be ignored by getEstimatedSpeed
GPSFixMoving f3 = new GPSFixMovingImpl(new DegreePosition(3./3600.*1./60., 0), t3, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
track.addGPSFix(f1);
track.addGPSFix(f2);
track.addGPSFix(f3);
@@ -504,9 +504,9 @@ public class TrackTest {
TimePoint t1 = new MillisecondsTimePoint(1000);
TimePoint t2 = new MillisecondsTimePoint(2000);
TimePoint t3 = new MillisecondsTimePoint(3000);
GPSFixMoving f1 = new GPSFixMovingImpl(new DegreePosition(1./3600.*1./60., 0), t1, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)));
GPSFixMoving f2 = new GPSFixMovingImpl(new DegreePosition(150./3600.*1./60., 0), t2, new KnotSpeedWithBearingImpl(150, new DegreeBearingImpl(0))); // outrageous speed; to be ignored by getEstimatedSpeed
GPSFixMoving f3 = new GPSFixMovingImpl(new DegreePosition(3./3600.*1./60., 0), t3, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)));
GPSFixMoving f1 = new GPSFixMovingImpl(new DegreePosition(1./3600.*1./60., 0), t1, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
GPSFixMoving f2 = new GPSFixMovingImpl(new DegreePosition(150./3600.*1./60., 0), t2, new KnotSpeedWithBearingImpl(150, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null); // outrageous speed; to be ignored by getEstimatedSpeed
GPSFixMoving f3 = new GPSFixMovingImpl(new DegreePosition(3./3600.*1./60., 0), t3, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
track.addGPSFix(f1);
track.addGPSFix(f2);
track.addGPSFix(f3);
@@ -519,9 +519,9 @@ public class TrackTest {
TimePoint t1 = new MillisecondsTimePoint(1000);
TimePoint t2 = new MillisecondsTimePoint(2000);
TimePoint t3 = new MillisecondsTimePoint(3000);
GPSFixMoving f1 = new GPSFixMovingImpl(new DegreePosition(1./3600.*1./60., 0), t1, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)));
GPSFixMoving f2 = new GPSFixMovingImpl(new DegreePosition(2./3600.*1./60., 0), t2, new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(0))); // outrageous speed; to be ignored by getEstimatedSpeed
GPSFixMoving f3 = new GPSFixMovingImpl(new DegreePosition(3./3600.*1./60., 0), t3, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)));
GPSFixMoving f1 = new GPSFixMovingImpl(new DegreePosition(1./3600.*1./60., 0), t1, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
GPSFixMoving f2 = new GPSFixMovingImpl(new DegreePosition(2./3600.*1./60., 0), t2, new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null); // outrageous speed; to be ignored by getEstimatedSpeed
GPSFixMoving f3 = new GPSFixMovingImpl(new DegreePosition(3./3600.*1./60., 0), t3, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
track.addGPSFix(f1);
track.addGPSFix(f2);
track.addGPSFix(f3);
@@ -535,9 +535,9 @@ public class TrackTest {
TimePoint t1 = new MillisecondsTimePoint(1000);
TimePoint t2 = new MillisecondsTimePoint(2000);
TimePoint t3 = new MillisecondsTimePoint(3000);
GPSFixMoving f1 = new GPSFixMovingImpl(new DegreePosition(1./3600.*1./60., 0), t1, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)));
GPSFixMoving f2 = new GPSFixMovingImpl(new DegreePosition(2./3600.*1./60., 0), t2, new KnotSpeedWithBearingImpl(150, new DegreeBearingImpl(0))); // outrageous speed; to be ignored by getEstimatedSpeed
GPSFixMoving f3 = new GPSFixMovingImpl(new DegreePosition(3./3600.*1./60., 0), t3, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)));
GPSFixMoving f1 = new GPSFixMovingImpl(new DegreePosition(1./3600.*1./60., 0), t1, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
GPSFixMoving f2 = new GPSFixMovingImpl(new DegreePosition(2./3600.*1./60., 0), t2, new KnotSpeedWithBearingImpl(150, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null); // outrageous speed; to be ignored by getEstimatedSpeed
GPSFixMoving f3 = new GPSFixMovingImpl(new DegreePosition(3./3600.*1./60., 0), t3, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
track.addGPSFix(f1);
track.addGPSFix(f2);
track.addGPSFix(f3);
@@ -552,9 +552,9 @@ public class TrackTest {
TimePoint t1 = new MillisecondsTimePoint(1000);
TimePoint t2 = new MillisecondsTimePoint(2000);
TimePoint t3 = new MillisecondsTimePoint(3000);
GPSFixMoving f1 = new GPSFixMovingImpl(new DegreePosition(0, 0), t1, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(45)));
GPSFixMoving f2 = new GPSFixMovingImpl(new DegreePosition(0.00001, 0.00001), t2, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)));
GPSFixMoving f3 = new GPSFixMovingImpl(new DegreePosition(0.00002, 0), t3, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(315)));
GPSFixMoving f1 = new GPSFixMovingImpl(new DegreePosition(0, 0), t1, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(45)), /* optionalTrueHeading */ null);
GPSFixMoving f2 = new GPSFixMovingImpl(new DegreePosition(0.00001, 0.00001), t2, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
GPSFixMoving f3 = new GPSFixMovingImpl(new DegreePosition(0.00002, 0), t3, new KnotSpeedWithBearingImpl(1, new DegreeBearingImpl(315)), /* optionalTrueHeading */ null);
track.addGPSFix(f1);
track.addGPSFix(f2);
track.addGPSFix(f3);
@@ -582,7 +582,7 @@ public class TrackTest {
// now add a fix:
TimePoint now6 = addMillisToTimepoint(gpsFix5.getTimePoint(), 3);
track.addGPSFix(new GPSFixMovingImpl(
new DegreePosition(6, 5), now6, new KnotSpeedWithBearingImpl(2, new DegreeBearingImpl(0))));
new DegreePosition(6, 5), now6, new KnotSpeedWithBearingImpl(2, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null));
try {
GPSFixMoving secondOfSubset = subsetIter.next();
PositionAssert.assertGPSFixEquals(gpsFix3, secondOfSubset, /* pos deg delta */ 0.000001, /* bearing deg delta */ 0.01, /* knot delta */ 0.01);
@@ -903,7 +903,7 @@ public class TrackTest {
TimePoint next = null;
GPSFixMoving fix = null;
for (int i=0; i<steps; i++) {
fix = new GPSFixMovingImpl(p, start, speed);
fix = new GPSFixMovingImpl(p, start, speed, /* optionalTrueHeading */ null);
track.addGPSFix(fix);
next = start.plus(timeBetweenFixesInMillis);
p = p.translateGreatCircle(bearing, speed.travel(start, next));
@@ -918,7 +918,7 @@ public class TrackTest {
assertEquals(distance1, distance3); // no progress after time point "next" because no further fixes are known
assertEquals(distance1, distance4); // no progress after time point "next" because no further fixes are known
// now add one more fix
fix = new GPSFixMovingImpl(p, start, speed);
fix = new GPSFixMovingImpl(p, start, speed, /* optionalTrueHeading */ null);
track.addGPSFix(fix);
Distance distance1_new = track.getDistanceTraveled(now, next.minus(timeBetweenFixesInMillis));
Distance distance2_new = track.getDistanceTraveled(now, next.minus(2*timeBetweenFixesInMillis/3));
@@ -1065,7 +1065,7 @@ public class TrackTest {
SpeedWithBearing estimatedSpeed = track.getEstimatedSpeed(normalFixesTime);
GPSFixMovingImpl gpsFixFarInTheFuture = new GPSFixMovingImpl(
new DegreePosition(89, 180), new MillisecondsTimePoint(
System.currentTimeMillis()+10000000l), new KnotSpeedWithBearingImpl(200000, new DegreeBearingImpl(0)));
System.currentTimeMillis()+10000000l), new KnotSpeedWithBearingImpl(200000, new DegreeBearingImpl(0)), /* optionalTrueHeading */ null);
track.addGPSFix(gpsFixFarInTheFuture);
Position estimatedPosNew = track.getEstimatedPosition(normalFixesTime, /* extrapolate */ false);
// expecting to get the coordinates of gpsFix2's position
@@ -1084,8 +1084,8 @@ public class TrackTest {
AbstractBearing bearing = new DegreeBearingImpl(90);
Position position1 = new DegreePosition(1, 2);
Position position2 = position1.translateGreatCircle(bearing, new MeterDistance(1));
GPSFixMovingImpl myGpsFix1 = new GPSFixMovingImpl(position1, now1, new MeterPerSecondSpeedWithDegreeBearingImpl(1, bearing));
GPSFixMovingImpl myGpsFix2 = new GPSFixMovingImpl(position2, now2, new MeterPerSecondSpeedWithDegreeBearingImpl(1, bearing));
GPSFixMovingImpl myGpsFix1 = new GPSFixMovingImpl(position1, now1, new MeterPerSecondSpeedWithDegreeBearingImpl(1, bearing), /* optionalTrueHeading */ null);
GPSFixMovingImpl myGpsFix2 = new GPSFixMovingImpl(position2, now2, new MeterPerSecondSpeedWithDegreeBearingImpl(1, bearing), /* optionalTrueHeading */ null);
myTrack.addGPSFix(myGpsFix1);
myTrack.addGPSFix(myGpsFix2);
myTrack.lockForRead();
@@ -1105,8 +1105,8 @@ public class TrackTest {
AbstractBearing bearing = new DegreeBearingImpl(90);
Position position1 = new DegreePosition(1, 2);
Position position2 = position1.translateGreatCircle(bearing, new MeterDistance(1));
GPSFixMovingImpl myGpsFix1 = new GPSFixMovingImpl(position1, now1, new MeterPerSecondSpeedWithDegreeBearingImpl(10, bearing));
GPSFixMovingImpl myGpsFix2 = new GPSFixMovingImpl(position2, now2, new MeterPerSecondSpeedWithDegreeBearingImpl(10, bearing));
GPSFixMovingImpl myGpsFix1 = new GPSFixMovingImpl(position1, now1, new MeterPerSecondSpeedWithDegreeBearingImpl(10, bearing), /* optionalTrueHeading */ null);
GPSFixMovingImpl myGpsFix2 = new GPSFixMovingImpl(position2, now2, new MeterPerSecondSpeedWithDegreeBearingImpl(10, bearing), /* optionalTrueHeading */ null);
myTrack.addGPSFix(myGpsFix1);
myTrack.addGPSFix(myGpsFix2);
myTrack.lockForRead();
@@ -1126,8 +1126,8 @@ public class TrackTest {
AbstractBearing bearing = new DegreeBearingImpl(90);
Position position1 = new DegreePosition(1, 2);
Position position2 = position1.translateGreatCircle(bearing, new MeterDistance(1));
GPSFixMovingImpl myGpsFix1 = new GPSFixMovingImpl(position1, now1, new MeterPerSecondSpeedWithDegreeBearingImpl(0.1, bearing));
GPSFixMovingImpl myGpsFix2 = new GPSFixMovingImpl(position2, now2, new MeterPerSecondSpeedWithDegreeBearingImpl(0.1, bearing));
GPSFixMovingImpl myGpsFix1 = new GPSFixMovingImpl(position1, now1, new MeterPerSecondSpeedWithDegreeBearingImpl(0.1, bearing), /* optionalTrueHeading */ null);
GPSFixMovingImpl myGpsFix2 = new GPSFixMovingImpl(position2, now2, new MeterPerSecondSpeedWithDegreeBearingImpl(0.1, bearing), /* optionalTrueHeading */ null);
myTrack.addGPSFix(myGpsFix1);
myTrack.addGPSFix(myGpsFix2);
myTrack.lockForRead();
@@ -1155,7 +1155,7 @@ public class TrackTest {
TimePoint slightlyBeforeFirstFix = firstFixSoFar.getTimePoint().minus(timespan);
Position newPosition = firstFixSoFar.getPosition().translateGreatCircle(speed.getBearing().reverse(),
speed.travel(firstFixSoFar.getTimePoint(), firstFixSoFar.getTimePoint().plus(timespan)));
GPSFixMoving newFirstFix = new GPSFixMovingImpl(newPosition, slightlyBeforeFirstFix, speed);
GPSFixMoving newFirstFix = new GPSFixMovingImpl(newPosition, slightlyBeforeFirstFix, speed, /* optionalTrueHeading */ null);
track.addGPSFix(newFirstFix);
TimeRange intervalAffected = track.getEstimatedPositionTimePeriodAffectedBy(newFirstFix);
Position newPositionAtBeginningOfTime = track.getEstimatedPosition(beginningOfTime, /* extrapolate */false);
@@ -1174,7 +1174,7 @@ public class TrackTest {
TimePoint slightlyAfterLastFix = lastFixSoFar.getTimePoint().plus(timespan);
Position newPosition = lastFixSoFar.getPosition().translateGreatCircle(speed.getBearing(),
speed.travel(lastFixSoFar.getTimePoint(), lastFixSoFar.getTimePoint().plus(timespan)));
GPSFixMoving newLastFix = new GPSFixMovingImpl(newPosition, slightlyAfterLastFix, speed);
GPSFixMoving newLastFix = new GPSFixMovingImpl(newPosition, slightlyAfterLastFix, speed, /* optionalTrueHeading */ null);
track.addGPSFix(newLastFix);
TimeRange intervalAffected = track.getEstimatedPositionTimePeriodAffectedBy(newLastFix);
Position newPositionAtEndOfTime = track.getEstimatedPosition(endOfTime, /* extrapolate */false);
@@ -1192,7 +1192,7 @@ public class TrackTest {
Position positionAtEndOfTime = myTrack.getEstimatedPosition(endOfTime, /* extrapolate */false);
assertNull(positionAtBeginningOfTime);
assertNull(positionAtEndOfTime);
GPSFixMoving newFix = new GPSFixMovingImpl(new DegreePosition(12, 34), now, new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)));
GPSFixMoving newFix = new GPSFixMovingImpl(new DegreePosition(12, 34), now, new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
myTrack.addGPSFix(newFix);
TimeRange intervalAffected = myTrack.getEstimatedPositionTimePeriodAffectedBy(newFix);
Position newPositionAtBeginningOfTime = myTrack.getEstimatedPosition(beginningOfTime, /* extrapolate */false);
@@ -1273,7 +1273,7 @@ public class TrackTest {
TimePoint timePoint = new MillisecondsTimePoint(dateFormatter.parse(isoDateTime));
Position position = new DegreePosition(lat, lng);
SpeedWithBearing speed = new KnotSpeedWithBearingImpl(knotSpeed, new DegreeBearingImpl(bearingDeg));
GPSFixMoving fix = new GPSFixMovingImpl(position, timePoint, speed);
GPSFixMoving fix = new GPSFixMovingImpl(position, timePoint, speed, /* optionalTrueHeading */ null);
return fix;
}
@@ -1286,7 +1286,7 @@ public class TrackTest {
@Test
public void testEstimatedSpeedCaching() throws CompactionNotPossibleException {
GPSFixMoving originalFix = new GPSFixMovingImpl(new DegreePosition(12, 34), MillisecondsTimePoint.now(),
new KnotSpeedWithBearingImpl(9, new DegreeBearingImpl(123)));
new KnotSpeedWithBearingImpl(9, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
GPSFixMoving fix = new VeryCompactGPSFixMovingImpl(originalFix);
assertFalse(fix.isEstimatedSpeedCached());
final KnotSpeedWithBearingImpl estimatedSpeed = new KnotSpeedWithBearingImpl(9.1, new DegreeBearingImpl(124));
@@ -1309,7 +1309,7 @@ public class TrackTest {
/* bearing deg delta */ 0.1, /* knot speed delta */ 0.1); // fetch again from the cache
// assuming that all test fixes are within a few milliseconds and the averaging interval is much larger than that,
// adding a single fix in the middle should invalidate the cache
track.add(new GPSFixMovingImpl(gpsFix3.getPosition(), gpsFix3.getTimePoint().plus(1), gpsFix3.getSpeed()));
track.add(new GPSFixMovingImpl(gpsFix3.getPosition(), gpsFix3.getTimePoint().plus(1), gpsFix3.getSpeed(), /* optionalTrueHeading */ null));
assertFalse(compactFix3.isEstimatedSpeedCached());
}
}
@@ -104,7 +104,7 @@ public class WindEstimationOnConstructedTracksTest extends StoredTrackBasedTest
} finally {
competitorTrack.unlockAfterRead();
}
competitorTrack.addGPSFix(new GPSFixMovingImpl(position, timePoint, speed));
competitorTrack.addGPSFix(new GPSFixMovingImpl(position, timePoint, speed, /* optionalTrueHeading */ null));
}
/**
@@ -157,7 +157,7 @@ public abstract class AbstractExportedPositionsBasedTest {
GPSFixMoving fix = new GPSFixMovingImpl(new DegreePosition((Double) fixAsJson.get("lat-deg"), (Double) fixAsJson.get("lng-deg")),
new MillisecondsTimePoint((Long) fixAsJson.get("timepoint-ms")),
new KnotSpeedWithBearingImpl((Double) fixAsJson.get("speed-kts"),
new DegreeBearingImpl((Double) fixAsJson.get("truebearing-deg"))));
new DegreeBearingImpl((Double) fixAsJson.get("truebearing-deg"))), /* optionalTrueHeading */ null);
fixes.add(fix);
}
result.put(competitor, fixes);
@@ -104,6 +104,6 @@ public class MarkPassingCalculatorPerformanceTest extends AbstractMockedRaceMark
0.0002 - rnd.nextDouble() * 0.0004);
final TimePoint p = new MillisecondsTimePoint((long) (rnd.nextDouble() * 200000));
final SpeedWithBearing speed = new KnotSpeedWithBearingImpl(rnd.nextInt(11), new DegreeBearingImpl(rnd.nextInt(360)));
return new GPSFixMovingImpl(position, p, speed);
return new GPSFixMovingImpl(position, p, speed, /* optionalTrueHeading */ null);
}
}
@@ -41,13 +41,13 @@ public class MarkPassingWhiteBoxTest extends AbstractMockedRaceMarkPassingTest {
public void testNormalPassingAndSuppressingPassings() {
// Normal Passing of Single mark
GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(0.000003, 0.000049), new MillisecondsTimePoint(
40000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(330)));
40000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(330)), /* optionalTrueHeading */ null);
GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(0.000062, 0.000029), new MillisecondsTimePoint(
44000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(270)));
44000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(270)), /* optionalTrueHeading */ null);
GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(0.000026, -0.000024), new MillisecondsTimePoint(
47000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(225)));
47000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(225)), /* optionalTrueHeading */ null);
GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(-0.000056, -0.000049), new MillisecondsTimePoint(
50000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(190)));
50000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(190)), /* optionalTrueHeading */ null);
race.recordFix(ron, fix1);
race.recordFix(ron, fix2);
CandidateFinder finder = new CandidateFinderImpl(race);
@@ -85,11 +85,11 @@ public class MarkPassingWhiteBoxTest extends AbstractMockedRaceMarkPassingTest {
public void testDistance() {
// 3 fixes all on one side of crossing Bearing, therefore no XTE-Candidate
GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(-0.000155, 0.000103), new MillisecondsTimePoint(
60000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(330)));
60000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(330)), /* optionalTrueHeading */ null);
GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(0.000038, 0.000021), new MillisecondsTimePoint(
65000), new KnotSpeedWithBearingImpl(4, new DegreeBearingImpl(280)));
65000), new KnotSpeedWithBearingImpl(4, new DegreeBearingImpl(280)), /* optionalTrueHeading */ null);
GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(-0.000268, 0.000135), new MillisecondsTimePoint(
80000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(170)));
80000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(170)), /* optionalTrueHeading */ null);
CandidateFinderImpl finder = new CandidateFinderImpl(race);
race.recordFix(tom, fix1);
@@ -115,13 +115,13 @@ public class MarkPassingWhiteBoxTest extends AbstractMockedRaceMarkPassingTest {
public void testPastGate() {
// Competitor sails closely past one mark of gate and rounds the other mark further away
GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(-0.000967, -0.000124), new MillisecondsTimePoint(
100000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(100)));
100000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(100)), /* optionalTrueHeading */ null);
GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(-0.000989, -0.000001), new MillisecondsTimePoint(
110000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(160)));
110000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(160)), /* optionalTrueHeading */ null);
GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(-0.001079, 0.000045), new MillisecondsTimePoint(
115000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(90)));
115000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(90)), /* optionalTrueHeading */ null);
GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(-0.000982, 0.000143), new MillisecondsTimePoint(
125000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45)));
125000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45)), /* optionalTrueHeading */ null);
CandidateFinderImpl finder = new CandidateFinderImpl(race);
race.recordFix(tom, fix1);
race.recordFix(tom, fix2);
@@ -157,9 +157,9 @@ public class MarkPassingWhiteBoxTest extends AbstractMockedRaceMarkPassingTest {
public void testGateAfterLine() {
// The problem of passing a gate right after the start line is crossed, solved by the distance estimation
GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(-0.001051, -0.000008), new MillisecondsTimePoint(
10000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(5)));
10000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(5)), /* optionalTrueHeading */ null);
GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(-0.000942, 0.000022), new MillisecondsTimePoint(
14000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(15)));
14000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(15)), /* optionalTrueHeading */ null);
race.recordFix(tom, fix1);
race.recordFix(tom, fix2);
Candidate c1 = new CandidateImpl(1, new MillisecondsTimePoint(11000), 0.99, waypoints.get(0));
@@ -181,15 +181,15 @@ public class MarkPassingWhiteBoxTest extends AbstractMockedRaceMarkPassingTest {
public void testSailingInFrontAndAroundMark() {
CandidateFinder finder = new CandidateFinderImpl(race);
GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(-0.000037, -0.000126), new MillisecondsTimePoint(
40000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(80)));
40000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(80)), /* optionalTrueHeading */ null);
GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(-0.000022, 0.000001), new MillisecondsTimePoint(
43000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45)));
43000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(45)), /* optionalTrueHeading */ null);
GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(0.000018, 0.000038), new MillisecondsTimePoint(
46000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(330)));
46000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(330)), /* optionalTrueHeading */ null);
GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(0.000084, -0.000004), new MillisecondsTimePoint(
49000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(260)));
49000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(260)), /* optionalTrueHeading */ null);
GPSFixMoving fix5 = new GPSFixMovingImpl(new DegreePosition(0.000054, -0.000153), new MillisecondsTimePoint(
52000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(200)));
52000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(200)), /* optionalTrueHeading */ null);
race.recordFix(ben, fix1);
race.recordFix(ben, fix2);
race.recordFix(ben, fix3);
@@ -208,15 +208,15 @@ public class MarkPassingWhiteBoxTest extends AbstractMockedRaceMarkPassingTest {
public void fixAndUnfixMarkPassing() {
GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(-0.001027, -0.000001), new MillisecondsTimePoint(
11000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(340)));
11000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(340)), /* optionalTrueHeading */ null);
GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(-0.000396, -0.000602), new MillisecondsTimePoint(
35000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(315)));
35000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(315)), /* optionalTrueHeading */ null);
GPSFixMoving fix3 = new GPSFixMovingImpl(new DegreePosition(0.000164, -0.000012), new MillisecondsTimePoint(
60000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(90)));
60000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(90)), /* optionalTrueHeading */ null);
GPSFixMoving fix4 = new GPSFixMovingImpl(new DegreePosition(-0.000402, 0.00043), new MillisecondsTimePoint(
85000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(135)));
85000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(135)), /* optionalTrueHeading */ null);
GPSFixMoving fix5 = new GPSFixMovingImpl(new DegreePosition(-0.001027, -0.000001), new MillisecondsTimePoint(
115000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(90)));
115000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(90)), /* optionalTrueHeading */ null);
race.recordFix(tom, fix1);
race.recordFix(tom, fix2);
@@ -259,9 +259,9 @@ public class MarkPassingWhiteBoxTest extends AbstractMockedRaceMarkPassingTest {
@Test
public void testAddingAndRemovingWaypointToFinder() {
GPSFixMoving fix1 = new GPSFixMovingImpl(new DegreePosition(-0.00045, -0.00052), new MillisecondsTimePoint(
40000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(200)));
40000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(200)), /* optionalTrueHeading */ null);
GPSFixMoving fix2 = new GPSFixMovingImpl(new DegreePosition(-0.0006, -0.00052),
new MillisecondsTimePoint(44000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(160)));
new MillisecondsTimePoint(44000), new KnotSpeedWithBearingImpl(5, new DegreeBearingImpl(160)), /* optionalTrueHeading */ null);
race.recordFix(ron, fix1);
race.recordFix(ron, fix2);
@@ -245,7 +245,7 @@ public class MarkPassingRaceFingerprintJsonSerializationTest extends OnlineTracT
Position pos = firstFix.getPosition();
TimePoint tp = firstFix.getTimePoint();
DegreePosition degPos = new DegreePosition(pos.getLatDeg() + 0.05, pos.getLngDeg() + 0.05);
GPSFixMoving gpsM = new GPSFixMovingImpl(degPos, tp, speed);
GPSFixMoving gpsM = new GPSFixMovingImpl(degPos, tp, speed, /* optionalTrueHeading */ null);
testRace.getTrack(firstCompetitor).add(gpsM, true);
MarkPassingRaceFingerprint fingerprint2 = factory.createFingerprint(testRace);
assertFalse(fingerprint1.matches(testRace));
@@ -37,7 +37,7 @@ public class PositionInterpolationAndExtrapolationWithSpeedInfoTest extends Posi
@Test
public void testFixBeforeNow() {
final GPSFixMoving fixBeforeNow = new GPSFixMovingImpl(p1, now.minus(Duration.ONE_HOUR), speed);
final GPSFixMoving fixBeforeNow = new GPSFixMovingImpl(p1, now.minus(Duration.ONE_HOUR), speed, /* optionalTrueHeading */ null);
getTrack().add(fixBeforeNow);
assertPos(p1, /* extrapolate */ false);
assertPos(p1.translateGreatCircle(speed.getBearing(), speed.travel(now.minus(Duration.ONE_HOUR), now)), /* extrapolate */ true);
@@ -45,7 +45,7 @@ public class PositionInterpolationAndExtrapolationWithSpeedInfoTest extends Posi
@Test
public void testFixAfterNow() {
GPSFixMoving fixAfterNow = new GPSFixMovingImpl(p1, now.plus(Duration.ONE_HOUR), speed);
GPSFixMoving fixAfterNow = new GPSFixMovingImpl(p1, now.plus(Duration.ONE_HOUR), speed, /* optionalTrueHeading */ null);
getTrack().add(fixAfterNow);
assertPos(p1, /* extrapolate */ false);
assertPos(p1.translateGreatCircle(speed.getBearing().reverse() /* travel backwards */, speed.travel(now.minus(Duration.ONE_HOUR), now)), /* extrapolate */ true);
@@ -53,7 +53,7 @@ public class PositionInterpolationAndExtrapolationWithSpeedInfoTest extends Posi
@Test
public void testExactMatch() {
GPSFixMoving fixNow = new GPSFixMovingImpl(p1, now, speed);
GPSFixMoving fixNow = new GPSFixMovingImpl(p1, now, speed, /* optionalTrueHeading */ null);
getTrack().add(fixNow);
assertPos(p1, /* extrapolate */ false);
assertPos(p1, /* extrapolate */ true);
@@ -61,9 +61,9 @@ public class PositionInterpolationAndExtrapolationWithSpeedInfoTest extends Posi
@Test
public void testInBetween() {
GPSFixMoving fixBeforeNow = new GPSFixMovingImpl(p1, now.minus(Duration.ONE_HOUR), speed);
GPSFixMoving fixBeforeNow = new GPSFixMovingImpl(p1, now.minus(Duration.ONE_HOUR), speed, /* optionalTrueHeading */ null);
getTrack().add(fixBeforeNow);
GPSFixMoving fixAfterNow = new GPSFixMovingImpl(p2, now.plus(Duration.ONE_HOUR), speed);
GPSFixMoving fixAfterNow = new GPSFixMovingImpl(p2, now.plus(Duration.ONE_HOUR), speed, /* optionalTrueHeading */ null);
getTrack().add(fixAfterNow);
Position middle = p1.translateGreatCircle(p1.getBearingGreatCircle(p2), p1.getDistance(p2).scale(0.5));
assertPos(middle, /* extrapolate */ false);
@@ -187,7 +187,8 @@ public class DomainFactoryImpl implements DomainFactory {
@Override
public GPSFixMoving createGPSFixMoving(IPosition position) {
GPSFixMoving result = new GPSFixMovingImpl(createPosition(position), new MillisecondsTimePoint(position.getTimestamp()),
new KilometersPerHourSpeedWithBearingImpl(position.getSpeed(), new DegreeBearingImpl(position.getDirection())));
new KilometersPerHourSpeedWithBearingImpl(position.getSpeed(), new DegreeBearingImpl(position.getDirection())),
position.getTrueHeading() == null ? null : new DegreeBearingImpl(position.getTrueHeading()));
return result;
}
@@ -344,7 +344,7 @@ public class Simulator {
private <T> void scheduleFixRecording(final T object, GPSFixMoving fix, final RecordGPSFix<T> recorder) {
final TimePoint transformedTimepoint = advance(fix.getTimePoint());
final GPSFixMoving transformedFix = new GPSFixMovingImpl(fix.getPosition(), transformedTimepoint, fix.getSpeed());
final GPSFixMoving transformedFix = new GPSFixMovingImpl(fix.getPosition(), transformedTimepoint, fix.getSpeed(), fix.getOptionalTrueHeading());
long waitTime = getWaitTimeInMillisUntil(transformedFix.getTimePoint());
if (waitTime <= 0) {
recorder.recordFix(object, transformedFix);
@@ -41,7 +41,7 @@ public class TeamPosition implements Timed {
}
public GPSFixMoving getGPSFixMoving() {
return new GPSFixMovingImpl(getPosition(), getTimePoint(), getMotionVector());
return new GPSFixMovingImpl(getPosition(), getTimePoint(), getMotionVector(), /* optionalTrueHeading */ null);
}
@Override
@@ -207,7 +207,7 @@ implements TrackingDataLoader {
for (final TeamPositions teamPositions : storedData.getTeams()) {
progressCallback.ifPresent(cb->cb.accept((double) i[0]++ / numberOfTeams));
for (final TeamPosition position : teamPositions.getPositions()) {
final GPSFixMoving fix = new GPSFixMovingImpl(position.getPosition(), position.getTimePoint(), position.getMotionVector());
final GPSFixMoving fix = new GPSFixMovingImpl(position.getPosition(), position.getTimePoint(), position.getMotionVector(), /* optionalTrueHeading */ null);
final int deviceSerialNumber = teamPositions.getDeviceSerialNumber();
trackedRace.getTrack(competitorByDeviceSerialNumber.get(deviceSerialNumber)).add(fix);
updateTimePointOfLastFixPerDeviceSerialNumber(deviceSerialNumber, position.getTimePoint());
@@ -1,48 +0,0 @@
package com.sap.sailing.domain.maneuverdetection.impl;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.maneuverdetection.GpsFixWithEstimationData;
import com.sap.sse.common.Bearing;
import com.sap.sse.common.Distance;
import com.sap.sse.common.TimePoint;
/**
*
* @author Vladislav Chumak (D069712)
*
*/
public class GpsFixWithEstimationDataImpl extends GPSFixMovingImpl implements GpsFixWithEstimationData {
private static final long serialVersionUID = -6952863819352430365L;
private Wind wind;
private Bearing relativeBearingToNextMarkAfterManeuver;
private Distance distanceToClosestMark;
public GpsFixWithEstimationDataImpl(Position position, TimePoint timePoint, SpeedWithBearing speedWithBearing,
Wind wind, Bearing relativeBearingToNextMarkAfterManeuver, Distance distanceToClosestMark) {
super(position, timePoint, speedWithBearing);
this.wind = wind;
this.relativeBearingToNextMarkAfterManeuver = relativeBearingToNextMarkAfterManeuver;
this.distanceToClosestMark = distanceToClosestMark;
}
@Override
public Wind getWind() {
return wind;
}
@Override
public Bearing getRelativeBearingToNextMarkAfterManeuver() {
return relativeBearingToNextMarkAfterManeuver;
}
@Override
public Distance getDistanceToClosestMark() {
return distanceToClosestMark;
}
}
@@ -11,6 +11,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
@@ -71,7 +72,7 @@ public class MarkPassingCalculator {
* This CALCULATOR_VERSION variable indicates the Version of the {@link MarkPassingCalculator} and must be changed
* manually when changing the calculator. It should be changed by adding +1;
*/
public static final int CALCULATOR_VERSION = 1;
public static final int CALCULATOR_VERSION = 2;
/**
* An "end marker" that can be {@link #enqueueUpdate(StorePositionUpdateStrategy) enqueued} in order to tell the
@@ -592,6 +593,7 @@ public class MarkPassingCalculator {
suspended = false;
} else {
suspended = false;
final CountDownLatch latchForRunningListenRun = new CountDownLatch(1);
enqueueUpdate(new StorePositionUpdateStrategy() {
@Override
public void storePositionUpdate(Map<Competitor, List<GPSFixMoving>> competitorFixes,
@@ -603,14 +605,23 @@ public class MarkPassingCalculator {
List<Pair<Competitor, Integer>> suppressedMarkPassings,
List<Competitor> unSuppressedMarkPassings, CandidateFinder candidateFinder,
CandidateChooser candidateChooser) {
latchForRunningListenRun.countDown();
assert latchForRunningListenRun.getCount() == 0;
}
});
if (markPassingRaceFingerprintRegistry != null) {
// FIXME bug5971: the thread must not be started before Listen.run() has obtained the MarkPassingCalculator's write lock!
new Thread(()->{
final Map<Competitor, Map<Waypoint, MarkPassing>> markPassings = race.getMarkPassings(/* waitForLatestUpdates */ true);
markPassingRaceFingerprintRegistry.storeMarkPassings(race.getRaceIdentifier(),
MarkPassingRaceFingerprintFactory.INSTANCE.createFingerprint(race),
markPassings, race.getRace().getCourse());
try {
latchForRunningListenRun.await();
final Map<Competitor, Map<Waypoint, MarkPassing>> markPassings = race.getMarkPassings(/* waitForLatestUpdates */ true);
markPassingRaceFingerprintRegistry.storeMarkPassings(race.getRaceIdentifier(),
MarkPassingRaceFingerprintFactory.INSTANCE.createFingerprint(race),
markPassings, race.getRace().getCourse());
} catch (InterruptedException e) {
logger.log(Level.SEVERE, "Exception while waiting for Listen.run() to start processing in MarkPassingCalculator for "+
race.getName(), e);
}
}, "Waiting for mark passings for "+race.getName()+" after having resumed to store the results in registry")
.start();
}
@@ -1,8 +0,0 @@
package com.sap.sailing.domain.tracking;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
public interface MarkGPSFix extends GPSFixMoving {
Mark getMark();
}
@@ -431,7 +431,7 @@ public class CourseChangeBasedTrackApproximation implements Serializable, GPSTra
}
private GPSFixMovingImpl createDummyFix(TimePoint timePoint) {
return new GPSFixMovingImpl(/* position */ null, timePoint, /* speed */ null);
return new GPSFixMovingImpl(/* position */ null, timePoint, /* speed */ null, /* optionalTrueHeading */ null);
}
@Override
@@ -227,7 +227,7 @@ public class OutlierFilter {
// between the adjacent fixes proportionately based on "fix"'s distances to each of the two adjacent fixes:
final TimePoint inferredTimePointForFix = lastFix.getTimePoint().plus(lastFix.getTimePoint().until(currentFix.getTimePoint()).times(
alongTrackDistanceFromLastFix.divide(lastFix.getPosition().getDistance(currentFix.getPosition()))));
result = new GPSFixMovingImpl(fixPosition, inferredTimePointForFix, fix.getSpeed());
result = new GPSFixMovingImpl(fixPosition, inferredTimePointForFix, fix.getSpeed(), fix.getOptionalTrueHeading());
distanceRatio = distanceFromSegment.divide(lastFix.getPosition().getDistance(currentFix.getPosition()));
} else { // we found a minimum after fix:
foundMinimum = true;
@@ -1,5 +1,7 @@
package com.sap.sailing.expeditionconnector.impl;
import java.io.IOException;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
@@ -8,7 +10,10 @@ import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.declination.DeclinationService;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
@@ -23,6 +28,8 @@ import com.sap.sse.common.impl.DegreeBearingImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class ExpeditionMessageImpl implements ExpeditionMessage {
private static final Logger logger = Logger.getLogger(ExpeditionMessageImpl.class.getName());
private final String originalMessage;
private final int boatID;
private final Map<Integer, Double> values;
@@ -148,8 +155,21 @@ public class ExpeditionMessageImpl implements ExpeditionMessage {
if (hasValue(ID_GPS_LAT) && hasValue(ID_GPS_LNG)) {
final SpeedWithBearing cogSog = getSpeedOverGround();
if (cogSog != null) {
result = new GPSFixMovingImpl(new DegreePosition(getValue(ID_GPS_LAT), getValue(ID_GPS_LNG)), getTimePoint(),
getSpeedOverGround());
final DegreePosition position = new DegreePosition(getValue(ID_GPS_LAT), getValue(ID_GPS_LNG));
Bearing optionalTrueHeading;
if (hasValue(ID_HEADING)) {
try {
optionalTrueHeading = new DegreeBearingImpl(getValue(ID_HEADING)).add(
DeclinationService.INSTANCE.getDeclination(getTimePoint(), position, /* timeoutForOnlineFetchInMilliseconds */ 1000).getBearingCorrectedTo(getTimePoint()));
} catch (IOException | ParseException e) {
logger.log(Level.WARNING, "Problem obtaining the magnetic declination for Expedition fix", e);
optionalTrueHeading = null;
}
} else {
optionalTrueHeading = null;
}
result = new GPSFixMovingImpl(position, getTimePoint(),
getSpeedOverGround(), optionalTrueHeading);
} else {
result = null;
}
@@ -28,7 +28,7 @@ public final class PreciseCompactGPSFixMovingImpl {
final double latDeg = streamReader.readDouble();
final double lngDeg = streamReader.readDouble();
return (PreciseCompactPosition) new com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixMovingImpl(
new DegreePosition(latDeg, lngDeg), /* timePoint */null, /* speedWithBearing */ null).getPosition();
new DegreePosition(latDeg, lngDeg), /* timePoint */null, /* speedWithBearing */ null, /* optionalTrueHeading */ null).getPosition();
}
@Override
@@ -70,7 +70,7 @@ public final class PreciseCompactGPSFixMovingImpl {
final double speedInKnots = streamReader.readDouble();
final double bearingDeg = streamReader.readDouble();
return (PreciseCompactSpeedWithBearing) new com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixMovingImpl(
/* dummy position */ new DegreePosition(0, 0), /* timePoint */null, new KnotSpeedWithBearingImpl(speedInKnots, new DegreeBearingImpl(bearingDeg))).getSpeed();
/* dummy position */ new DegreePosition(0, 0), /* timePoint */null, new KnotSpeedWithBearingImpl(speedInKnots, new DegreeBearingImpl(bearingDeg)), /* optionalTrueHeading */ null).getSpeed();
}
@Override
@@ -113,7 +113,7 @@ public final class PreciseCompactGPSFixMovingImpl {
final double bearingDeg = streamReader.readDouble();
final KnotSpeedWithBearingImpl speed = new KnotSpeedWithBearingImpl(speedInKnots, new DegreeBearingImpl(bearingDeg));
final com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixMovingImpl preciseCompactGPSFixMovingImpl = new com.sap.sailing.domain.common.tracking.impl.PreciseCompactGPSFixMovingImpl(
/* dummy position */ new DegreePosition(0, 0), /* timePoint */null, speed);
/* dummy position */ new DegreePosition(0, 0), /* timePoint */null, speed, /* optionalTrueHeading */ null);
preciseCompactGPSFixMovingImpl.cacheEstimatedSpeed(speed);
return (PreciseCompactEstimatedSpeed) preciseCompactGPSFixMovingImpl.getSpeed();
}
@@ -35,7 +35,7 @@ public final class VeryCompactGPSFixMovingImpl {
final double lngDeg = streamReader.readDouble();
try {
return (VeryCompactPosition) new com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl(
new DegreePosition(latDeg, lngDeg), /* timePoint */null, /* speed with bearing */ null).getPosition();
new DegreePosition(latDeg, lngDeg), /* timePoint */null, /* speed with bearing */ null, /* optionalTrueHeading */ null).getPosition();
} catch (CompactionNotPossibleException e) {
logger.log(Level.SEVERE, "Internal error: an object that was a very compact position and was serialized "+
"couldn't be de-serialized again as such an object", e);
@@ -83,7 +83,7 @@ public final class VeryCompactGPSFixMovingImpl {
final double bearingDeg = streamReader.readDouble();
try {
return (VeryCompactSpeedWithBearing) new com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl(
/* position */ null, /* timePoint */null, new KnotSpeedWithBearingImpl(knotSpeed, new DegreeBearingImpl(bearingDeg))).getSpeed();
/* position */ null, /* timePoint */null, new KnotSpeedWithBearingImpl(knotSpeed, new DegreeBearingImpl(bearingDeg)), /* optionalTrueHeading */ null).getSpeed();
} catch (CompactionNotPossibleException e) {
logger.log(Level.SEVERE, "Internal error: an object that was a very compact position and was serialized "+
"couldn't be de-serialized again as such an object", e);
@@ -132,7 +132,7 @@ public final class VeryCompactGPSFixMovingImpl {
try {
final KnotSpeedWithBearingImpl speed = new KnotSpeedWithBearingImpl(knotSpeed, new DegreeBearingImpl(bearingDeg));
com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl fix = new com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl(
/* dummy position */ new DegreePosition(0, 0), /* timePoint */null, speed);
/* dummy position */ new DegreePosition(0, 0), /* timePoint */null, speed, /* optionalTrueHeading */ null);
fix.cacheEstimatedSpeed(speed);
return (VeryCompactEstimatedSpeed) fix.getCachedEstimatedSpeed();
} catch (CompactionNotPossibleException e) {
@@ -15,6 +15,8 @@ import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.gwt.ui.shared.GPSFixDTOWithSpeedWindTackAndLegType;
import com.sap.sailing.gwt.ui.shared.GPSFixDTOWithSpeedWindTackAndLegTypeIterable;
import com.sap.sailing.gwt.ui.shared.SpeedWithBearingDTO;
import com.sap.sse.common.Bearing;
import com.sap.sse.common.impl.DegreeBearingImpl;
/**
* Serializes the {@link GPSFixDTOWithSpeedWindTackAndLegType} objects one by one, writing only primitive values to the
@@ -33,6 +35,7 @@ public class GPSFixDTOWithSpeedWindTackAndLegTypeIterable_CustomFieldSerializer
private static final int MASK_HAS_TACK = 1 << 4;
private static final int MASK_HAS_POSITION = 1 << 5;
private static final int MASK_HAS_TIMEPOINT = 1 << 6;
private static final int MASK_HAS_TRUE_HEADING = 1 << 7;
@Override
public void serializeInstance(SerializationStreamWriter streamWriter, GPSFixDTOWithSpeedWindTackAndLegTypeIterable instance)
@@ -68,6 +71,9 @@ public class GPSFixDTOWithSpeedWindTackAndLegTypeIterable_CustomFieldSerializer
if (fix.timepoint != null) {
streamWriter.writeLong(fix.timepoint.getTime());
}
if (fix.optionalTrueHeading != null) {
streamWriter.writeDouble(fix.optionalTrueHeading.getDegrees());
}
}
streamWriter.writeInt(-1); // encodes a "mask" that marks the end of the iterable
}
@@ -124,7 +130,13 @@ public class GPSFixDTOWithSpeedWindTackAndLegTypeIterable_CustomFieldSerializer
} else {
timepoint = null;
}
list.add(new GPSFixDTOWithSpeedWindTackAndLegType(timepoint, position, speedWithBearing, degreesBoatToTheWind, tack, legType, extrapolated, detailValue));
final Bearing optionalTrueHeading;
if ((mask & MASK_HAS_TRUE_HEADING) != 0) {
optionalTrueHeading = new DegreeBearingImpl(streamReader.readDouble());
} else {
optionalTrueHeading = null;
}
list.add(new GPSFixDTOWithSpeedWindTackAndLegType(timepoint, position, speedWithBearing, optionalTrueHeading, degreesBoatToTheWind, tack, legType, extrapolated, detailValue));
}
return new GPSFixDTOWithSpeedWindTackAndLegTypeIterable(list);
}
@@ -138,6 +150,7 @@ public class GPSFixDTOWithSpeedWindTackAndLegTypeIterable_CustomFieldSerializer
| (fix.tack == null ? 0 : MASK_HAS_TACK)
| (fix.position == null ? 0 : MASK_HAS_POSITION)
| (fix.timepoint == null ? 0 : MASK_HAS_TIMEPOINT)
| (fix.optionalTrueHeading == null ? 0 : MASK_HAS_TRUE_HEADING)
;
}
@@ -10,6 +10,10 @@
<li>Fixed an issue for users with event update rights that resulted in them being
unable to see the media tab of single regatta events for events without
pre-existing media objects.</li>
<li>When connectors support providing a heading (magnetic as in HDG, or true as
in HDT), the heading will be used for the boat orientation on the map. The
TracTrac connector, starting with its version 3.15.2, does support this if
the trackers in use provide a true heading value.</li>
</ul>
<h5 class="articleSubheadline">January 2024</h5>
<ul class="bulletList">
@@ -614,7 +614,7 @@ public class EditMarkPositionPanel extends AbstractRaceChart<AbstractSettings> i
}
public void addMarkFix(final MarkDTO mark, final Date timepoint, final Position fixPosition) {
final GPSFixDTOWithSpeedWindTackAndLegType fix = new GPSFixDTOWithSpeedWindTackAndLegType(timepoint, fixPosition, null, new WindDTO(), null, null, false);
final GPSFixDTOWithSpeedWindTackAndLegType fix = new GPSFixDTOWithSpeedWindTackAndLegType(timepoint, fixPosition, null, /* optionalTrueHeading */ null, new WindDTO(), null, null, false);
markPositionService.addMarkFix(
raceIdentifierToLeaderboardRaceColumnAndFleetMapper.getLeaderboardNameAndRaceColumnNameAndFleetName(selectedRaceIdentifier),
mark, fix, new AsyncCallback<Void>() {
@@ -96,7 +96,7 @@ public class FixPositionChooser {
fix = new GPSFixDTO(oldFix.timepoint, oldFix.position);
this.moveOverlay = new FixOverlay(map, overlay.getZIndex(), fix, overlay.getType(), "#f00", coordinateSystem, stringMessages.dragToChangePosition());
} else {
fix = new GPSFixDTOWithSpeedWindTackAndLegType(editMarkPositionPanel.getTimepoint(), coordinateSystem.getPosition(startPos), null, new WindDTO(), null, null, false);
fix = new GPSFixDTOWithSpeedWindTackAndLegType(editMarkPositionPanel.getTimepoint(), coordinateSystem.getPosition(startPos), null, /* optionalTrueHeading */ null, new WindDTO(), null, null, false);
this.moveOverlay = new FixOverlay(map, EditMarkPositionPanel.FIX_OVERLAY_Z_ORDER+1, fix, FixType.BUOY, "#f00", coordinateSystem, stringMessages.dragToChangePosition());
}
redTimeLine.setValue(fix.timepoint.getTime());
@@ -12,7 +12,6 @@ import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.dto.BoatClassDTO;
import com.sap.sailing.domain.common.dto.BoatDTO;
import com.sap.sailing.gwt.ui.shared.GPSFixDTOWithSpeedWindTackAndLegType;
import com.sap.sailing.gwt.ui.shared.SpeedWithBearingDTO;
import com.sap.sailing.gwt.ui.shared.racemap.BoatClassVectorGraphics;
import com.sap.sailing.gwt.ui.shared.racemap.CanvasOverlayV3;
import com.sap.sse.common.Color;
@@ -99,11 +98,10 @@ public class BoatOverlay extends CanvasOverlayV3 {
setCanvasPosition(boatPositionInPx.getX() - getCanvas().getCoordinateSpaceWidth() / 2,
boatPositionInPx.getY() - getCanvas().getCoordinateSpaceHeight() / 2);
// now rotate the canvas accordingly
SpeedWithBearingDTO speedWithBearing = boatFix.speedWithBearing;
if (speedWithBearing == null) {
speedWithBearing = new SpeedWithBearingDTO(0, 0);
}
updateDrawingAngleAndSetCanvasRotation(coordinateSystem.mapDegreeBearing(speedWithBearing.bearingInDegrees - ORIGINAL_BOAT_IMAGE_ROTATIION_ANGLE));
final double trueHeadingInDegrees = boatFix.optionalTrueHeading != null
? boatFix.optionalTrueHeading.getDegrees()
: (boatFix.speedWithBearing == null ? 0 : boatFix.speedWithBearing.bearingInDegrees);
updateDrawingAngleAndSetCanvasRotation(coordinateSystem.mapDegreeBearing(trueHeadingInDegrees - ORIGINAL_BOAT_IMAGE_ROTATIION_ANGLE));
}
}
@@ -3011,7 +3011,7 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
final GPSFixDTOWithSpeedWindTackAndLegType result;
final List<GPSFixDTOWithSpeedWindTackAndLegType> competitorFixes = fixesAndTails.getFixes(competitorDTO);
if (competitorFixes != null && !competitorFixes.isEmpty()) {
int i = Collections.binarySearch(competitorFixes, new GPSFixDTOWithSpeedWindTackAndLegType(date, null, null, (WindDTO) null, null, null, false),
int i = Collections.binarySearch(competitorFixes, new GPSFixDTOWithSpeedWindTackAndLegType(date, null, null, /* optionalTrueHeading */ null, (WindDTO) null, null, null, false),
new Comparator<GPSFixDTOWithSpeedWindTackAndLegType>() {
@Override
public int compare(GPSFixDTOWithSpeedWindTackAndLegType o1, GPSFixDTOWithSpeedWindTackAndLegType o2) {
@@ -3060,8 +3060,9 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
factorForBefore*(fixBefore.speedWithBearing==null?0:fixBefore.speedWithBearing.speedInKnots) +
factorForAfter*(fixAfter.speedWithBearing==null?0:fixAfter.speedWithBearing.speedInKnots),
betweenBearing);
result = new GPSFixDTOWithSpeedWindTackAndLegType(date, betweenPosition, betweenSpeed, closer.degreesBoatToTheWind,
closer.tack, closer.legType, fixBefore.extrapolated || fixAfter.extrapolated);
result = new GPSFixDTOWithSpeedWindTackAndLegType(date, betweenPosition, betweenSpeed,
interpolateOptionalTrueHeading(fixBefore, factorForBefore, fixAfter, factorForAfter),
closer.degreesBoatToTheWind, closer.tack, closer.legType, fixBefore.extrapolated || fixAfter.extrapolated);
}
} else {
// perfect match
@@ -3073,6 +3074,16 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
}
return result;
}
private Bearing interpolateOptionalTrueHeading(GPSFixDTOWithSpeedWindTackAndLegType fixBefore, double factorForBefore, GPSFixDTOWithSpeedWindTackAndLegType fixAfter, double factorForAfter) {
assert fixBefore != null && fixAfter != null;
return (fixBefore == null || fixBefore.optionalTrueHeading == null) ? (fixAfter == null || fixAfter.optionalTrueHeading == null)
? null
: fixAfter.optionalTrueHeading
: (fixAfter == null || fixAfter.optionalTrueHeading == null)
? fixBefore.optionalTrueHeading
: new DegreeBearingImpl(factorForBefore * fixBefore.optionalTrueHeading.getDegrees() + factorForAfter * fixAfter.optionalTrueHeading.getDegrees());
}
public RaceMapSettings getSettings() {
return settings;
@@ -1912,9 +1912,10 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
.getBearing().getDegrees());
}
public GPSFixDTOWithSpeedWindTackAndLegType createGPSFixDTO(GPSFix fix, SpeedWithBearing speedWithBearing, WindDTO windDTO, Tack tack, LegType legType, boolean extrapolated, Double detailValue) {
public GPSFixDTOWithSpeedWindTackAndLegType createGPSFixDTO(GPSFix fix, SpeedWithBearing speedWithBearing,
Bearing optionalTrueHeading, WindDTO windDTO, Tack tack, LegType legType, boolean extrapolated, Double detailValue) {
return new GPSFixDTOWithSpeedWindTackAndLegType(fix.getTimePoint().asDate(), fix.getPosition()==null?null:fix.getPosition(),
speedWithBearing==null?null:createSpeedWithBearingDTO(speedWithBearing), windDTO, tack, legType, extrapolated, detailValue);
speedWithBearing==null?null:createSpeedWithBearingDTO(speedWithBearing), optionalTrueHeading, windDTO, tack, legType, extrapolated, detailValue);
}
@Override
@@ -3241,8 +3242,8 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
trackedLegOfCompetitor.getLeg()).getLegType(fix.getTimePoint());
Wind wind = trackedRace.getWind(fix.getPosition(), fix.getTimePoint());
WindDTO windDTO = createWindDTOFromAlreadyAveraged(wind, fix.getTimePoint());
GPSFixDTOWithSpeedWindTackAndLegType fixDTO = createGPSFixDTO(fix, speedWithBearing, windDTO, tack, legType, /* extrapolated */
false, null);
GPSFixDTOWithSpeedWindTackAndLegType fixDTO = createGPSFixDTO(fix, speedWithBearing, /* optionalTrueHeading */ null, windDTO, tack, /* extrapolated */
legType, false, null);
return fixDTO;
}
@@ -6,10 +6,13 @@ import com.google.gwt.user.client.rpc.IsSerializable;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Tack;
import com.sap.sse.common.Bearing;
import com.sap.sse.common.impl.DegreeBearingImpl;
public class GPSFixDTOWithSpeedWindTackAndLegType extends GPSFixDTO implements IsSerializable {
public SpeedWithBearingDTO speedWithBearing;
public Bearing optionalTrueHeading;
/**
* tells if this fix was computed by extrapolation instead of having been captured by a device directly
@@ -37,33 +40,35 @@ public class GPSFixDTOWithSpeedWindTackAndLegType extends GPSFixDTO implements I
public Double detailValue;
public GPSFixDTOWithSpeedWindTackAndLegType() {}
@Deprecated // GWT serialization only
GPSFixDTOWithSpeedWindTackAndLegType() {}
public GPSFixDTOWithSpeedWindTackAndLegType(Date timepoint, Position position, SpeedWithBearingDTO speedWithBearing, WindDTO wind,
Tack tack, LegType legType, boolean extrapolated) {
this(timepoint, position, speedWithBearing, (speedWithBearing != null && wind != null) ?
new DegreeBearingImpl(speedWithBearing.bearingInDegrees).getDifferenceTo(
new DegreeBearingImpl(wind.dampenedTrueWindFromDeg)).getDegrees() : null, tack, legType, extrapolated);
public GPSFixDTOWithSpeedWindTackAndLegType(Date timepoint, Position position, SpeedWithBearingDTO speedWithBearing, Bearing optionalTrueHeading,
WindDTO wind, Tack tack, LegType legType, boolean extrapolated) {
this(timepoint, position, speedWithBearing, optionalTrueHeading, (speedWithBearing != null && wind != null) ?
new DegreeBearingImpl(speedWithBearing.bearingInDegrees).getDifferenceTo(
new DegreeBearingImpl(wind.dampenedTrueWindFromDeg)).getDegrees() : null, tack, legType, extrapolated);
}
public GPSFixDTOWithSpeedWindTackAndLegType(Date timepoint, Position position, SpeedWithBearingDTO speedWithBearing, WindDTO wind,
Tack tack, LegType legType, boolean extrapolated, Double detailValue) {
this(timepoint, position, speedWithBearing, (speedWithBearing != null && wind != null) ?
new DegreeBearingImpl(speedWithBearing.bearingInDegrees).getDifferenceTo(
new DegreeBearingImpl(wind.dampenedTrueWindFromDeg)).getDegrees() : null, tack, legType, extrapolated, detailValue);
public GPSFixDTOWithSpeedWindTackAndLegType(Date timepoint, Position position, SpeedWithBearingDTO speedWithBearing, Bearing optionalTrueHeading,
WindDTO wind, Tack tack, LegType legType, boolean extrapolated, Double detailValue) {
this(timepoint, position, speedWithBearing, optionalTrueHeading, (speedWithBearing != null && wind != null) ?
new DegreeBearingImpl(speedWithBearing.bearingInDegrees).getDifferenceTo(
new DegreeBearingImpl(wind.dampenedTrueWindFromDeg)).getDegrees() : null, tack, legType, extrapolated, detailValue);
}
public GPSFixDTOWithSpeedWindTackAndLegType(Date timepoint, Position position, SpeedWithBearingDTO speedWithBearing, Double degreesBoatToTheWind,
Tack tack, LegType legType, boolean extrapolated) {
this(timepoint, position, speedWithBearing, degreesBoatToTheWind, tack, legType, extrapolated, /* detailValue */ null);
public GPSFixDTOWithSpeedWindTackAndLegType(Date timepoint, Position position, SpeedWithBearingDTO speedWithBearing, Bearing optionalTrueHeading,
Double degreesBoatToTheWind, Tack tack, LegType legType, boolean extrapolated) {
this(timepoint, position, speedWithBearing, optionalTrueHeading, degreesBoatToTheWind, tack, legType, extrapolated, /* detailValue */ null);
}
public GPSFixDTOWithSpeedWindTackAndLegType(Date timepoint, Position position, SpeedWithBearingDTO speedWithBearing, Double degreesBoatToTheWind,
Tack tack, LegType legType, boolean extrapolated, Double detailValue) {
public GPSFixDTOWithSpeedWindTackAndLegType(Date timepoint, Position position, SpeedWithBearingDTO speedWithBearing, Bearing optionalTrueHeading,
Double degreesBoatToTheWind, Tack tack, LegType legType, boolean extrapolated, Double detailValue) {
super(timepoint, position);
this.timepoint = timepoint;
this.position = position;
this.speedWithBearing = speedWithBearing;
this.optionalTrueHeading = optionalTrueHeading;
this.tack = tack;
this.legType = legType;
this.extrapolated = extrapolated;
@@ -213,7 +213,7 @@ public class GPSFixDTOWithSpeedWindTackAndLegTypeIterable implements IsSerializa
Position estimatedPosition = track.getEstimatedPosition(middle, extrapolate);
SpeedWithBearing estimatedSpeed = track.getEstimatedSpeed(middle);
if (estimatedPosition != null && estimatedSpeed != null) {
GPSFixMoving estimatedFix = new GPSFixMovingImpl(estimatedPosition, middle, estimatedSpeed);
GPSFixMoving estimatedFix = new GPSFixMovingImpl(estimatedPosition, middle, estimatedSpeed, /* optionalTrueHeading */ null); // TODO bug5970: could try to estimate heading from neighboring fixes
if (logger.getLevel() != null && logger.getLevel().equals(Level.FINEST)) {
logger.finest(""+competitor.getName()+": " + estimatedFix+" (estimated)");
}
@@ -282,7 +282,8 @@ public class GPSFixDTOWithSpeedWindTackAndLegTypeIterable implements IsSerializa
detailValue = null;
}
}
result = sailingService.createGPSFixDTO(fix, estimatedSpeed, windDTO, tack, legType, /* extrapolate */ extrapolatedFixes.contains(fix), detailValue);
result = sailingService.createGPSFixDTO(fix, estimatedSpeed, fix.getOptionalTrueHeading(), windDTO,
tack, legType, /* extrapolate */ extrapolatedFixes.contains(fix), detailValue);
} else if (isExtrapolate()) {
final TrackedLegOfCompetitor trackedLegOfCompetitor = trackedRace.getTrackedLeg(competitor, lastFix.getTimePoint());
Position position = track.getEstimatedPosition(toTimePointExcluding, extrapolate);
@@ -312,8 +313,8 @@ public class GPSFixDTOWithSpeedWindTackAndLegTypeIterable implements IsSerializa
WindDTO windDTO2 = wind2 == null ? null : sailingService.createWindDTOFromAlreadyAveraged(wind2, toTimePointExcluding);
result = new GPSFixDTOWithSpeedWindTackAndLegType(
toTimePointExcluding.asDate(), position==null?null:position,
estimatedSpeed2==null?null:sailingService.createSpeedWithBearingDTO(estimatedSpeed2), windDTO2,
tack2, legType2, /* extrapolated */ true);
estimatedSpeed2==null?null:sailingService.createSpeedWithBearingDTO(estimatedSpeed2), /* optionalTrueHeading */ null, // no heading for extrapolated fixes
windDTO2, tack2, legType2, /* extrapolated */ true);
} else {
throw new NoSuchElementException();
}
@@ -25,11 +25,9 @@ public class GPSFixMovingJsonDeserializerTest {
@Test
public void testGPSFixMovingDeserializer() throws ParseException, JsonDeserializationException {
GPSFixMoving gpsFix = GPSFixMovingImpl.create(8.0, 55.0, System.currentTimeMillis(), 5.0, 14.0);
GPSFixMoving gpsFix = GPSFixMovingImpl.create(8.0, 55.0, System.currentTimeMillis(), 5.0, 14.0, /* optionalTrueHeadingDeg */ 15.0);
JSONObject gpsFixSerialized = serializer.serialize(gpsFix);
GPSFixMoving gpsFixDeserialized = deserializer.deserialize(gpsFixSerialized);
assertEquals(gpsFix, gpsFixDeserialized);
}
}
@@ -31,14 +31,14 @@ public class FlatSmartphoneUuidAndGPSFixMovingJsonDeserializerTest {
" \"latitude\" : 54.325246,\n" +
" \"longitude\" : 10.148556,\n" +
" \"speed\" : 3.61,\n" +
" \"course\" : 258.11,\n" +
" \"course\" : 258.11\n" +
" },\n" +
" {\n" +
" \"timestamp\" : 14144168490000,\n" +
" \"latitude\" : 55.12456,\n" +
" \"longitude\" : 8.03456,\n" +
" \"speed\" : 5.1,\n" +
" \"course\" : 14.2,\n" +
" \"course\" : 14.2\n" +
" },\n" +
" {\n" +
" \"timestamp-iso\" : \"2418-03-18T15:41:30Z\",\n" +
@@ -46,19 +46,19 @@ public class FlatSmartphoneUuidAndGPSFixMovingJsonDeserializerTest {
" \"longitude\" : -2.03456,\n" +
" \"speed\" : 19.3,\n" +
" \"course\" : 359.99,\n" +
" \"hdt\" : 358.57\n" +
" }\n" +
" ]\n" +
"}";
JsonDeserializer<Pair<UUID, List<GPSFixMoving>>> deserializer =
new FlatSmartphoneUuidAndGPSFixMovingJsonDeserializer();
Pair<UUID, List<GPSFixMoving>> result =
deserializer.deserialize(Helpers.toJSONObjectSafe(JSONValue.parseWithException(json)));
assertThat("uuid", result.getA(), equalTo(UUID.fromString("af855a56-9726-4a9c-a77e-da955bd289bf")));
assertThat("number of fixes", result.getB().size(), equalTo(3));
TimePoint tp3 = result.getB().get(2).getTimePoint();
assertThat(tp3.asMillis(), equalTo(14144168490000L));
assertThat(result.getB().get(2).getOptionalTrueHeading().getDegrees(), equalTo(358.57));
}
@Test
@@ -6,6 +6,7 @@ Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package:
com.sap.sailing.declination,
org.json.simple
Require-Bundle: com.sap.sailing.domain.common,
com.sap.sailing.domain.shared.android,
@@ -1,19 +1,27 @@
package com.sap.sailing.server.gateway.deserialization.impl;
import java.io.IOException;
import java.text.ParseException;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import com.sap.sailing.declination.DeclinationService;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.MeterPerSecondSpeedImpl;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.common.tracking.impl.FlatSmartphoneUuidAndGPSFixMovingJsonSerializer;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.DegreeBearingImpl;
import com.sap.sse.shared.json.JsonDeserializationException;
import com.sap.sse.shared.json.JsonDeserializer;
@@ -23,8 +31,10 @@ import com.sap.sse.shared.json.JsonDeserializer;
* @author Fredrik Teschke
*
*/
public class FlatSmartphoneUuidAndGPSFixMovingJsonDeserializer implements
JsonDeserializer<Pair<UUID, List<GPSFixMoving>>> {
public class FlatSmartphoneUuidAndGPSFixMovingJsonDeserializer
implements JsonDeserializer<Pair<UUID, List<GPSFixMoving>>> {
private static final Logger logger = Logger.getLogger(FlatSmartphoneUuidAndGPSFixMovingJsonDeserializer.class.getName());
public static final String ACCURACY = "accuracy";
@Override
@@ -40,7 +50,23 @@ public class FlatSmartphoneUuidAndGPSFixMovingJsonDeserializer implements
double speedMperS = Double.parseDouble(fixObject.get(FlatSmartphoneUuidAndGPSFixMovingJsonSerializer.SPEED_M_PER_S).toString());
double speedKnots = new MeterPerSecondSpeedImpl(speedMperS).getKnots();
double bearingDeg = Double.parseDouble(fixObject.get(FlatSmartphoneUuidAndGPSFixMovingJsonSerializer.BEARING_DEG).toString());
GPSFixMoving fix = GPSFixMovingImpl.create(lonDeg, latDeg, timeMillis, speedKnots, bearingDeg);
Double optionalTrueHeadingDeg;
if (fixObject.containsKey(FlatSmartphoneUuidAndGPSFixMovingJsonSerializer.TRUE_HEADING_DEG)) {
optionalTrueHeadingDeg = Double.parseDouble(fixObject.get(FlatSmartphoneUuidAndGPSFixMovingJsonSerializer.TRUE_HEADING_DEG).toString());
} else if (fixObject.containsKey(FlatSmartphoneUuidAndGPSFixMovingJsonSerializer.MAGNETIC_HEADING_DEG)) {
final TimePoint timePoint = TimePoint.of(timeMillis);
try {
optionalTrueHeadingDeg = new DegreeBearingImpl(Double.parseDouble(fixObject.get(FlatSmartphoneUuidAndGPSFixMovingJsonSerializer.MAGNETIC_HEADING_DEG).toString()))
.add(DeclinationService.INSTANCE.getDeclination(timePoint, new DegreePosition(latDeg, lonDeg), /* timeout in ms */ 1000)
.getBearingCorrectedTo(timePoint)).getDegrees();
} catch (NumberFormatException | IOException | ParseException e) {
logger.log(Level.WARNING, "Problem obtaining magnetic declination for heading provided in JSON fix", e);
optionalTrueHeadingDeg = null;
}
} else {
optionalTrueHeadingDeg = null;
}
GPSFixMoving fix = GPSFixMovingImpl.create(lonDeg, latDeg, timeMillis, speedKnots, bearingDeg, optionalTrueHeadingDeg);
fixes.add(fix);
}
@@ -17,19 +17,26 @@ public class GPSFixMovingJsonDeserializer extends TypeBasedJsonDeserializer<GPSF
public static final String FIELD_BEARING_DEG = "bearing_deg";
public static final String FIELD_SPEED_KNOTS = "speed_knots";
public static final Object FIELD_TRUE_HEADING_DEG = "true_heading_deg";
@Override
protected GPSFixMoving deserializeAfterCheckingType(JSONObject object) throws JsonDeserializationException {
double bearingDeg = (Double) object.get(FIELD_BEARING_DEG);
double speedKnots = (Double) object.get(FIELD_SPEED_KNOTS);
JSONObject clone = (JSONObject) object.clone();
final double bearingDeg = (Double) object.get(FIELD_BEARING_DEG);
final double speedKnots = (Double) object.get(FIELD_SPEED_KNOTS);
final JSONObject clone = (JSONObject) object.clone();
clone.put(TypeBasedJsonDeserializer.FIELD_TYPE, GPSFixJsonDeserializer.TYPE);
GPSFix baseFix = new GPSFixJsonDeserializer().deserialize(clone);
Bearing bearing = new DegreeBearingImpl(bearingDeg);
SpeedWithBearing speed = new KnotSpeedWithBearingImpl(
final GPSFix baseFix = new GPSFixJsonDeserializer().deserialize(clone);
final Bearing bearing = new DegreeBearingImpl(bearingDeg);
final SpeedWithBearing speed = new KnotSpeedWithBearingImpl(
speedKnots, bearing);
GPSFixMoving fix = new GPSFixMovingImpl(baseFix.getPosition(),
baseFix.getTimePoint(), speed);
final Bearing optionalTrueHeading;
if (object.containsKey(FIELD_TRUE_HEADING_DEG)) {
optionalTrueHeading = new DegreeBearingImpl((Double) object.get(FIELD_TRUE_HEADING_DEG));
} else {
optionalTrueHeading = null;
}
final GPSFixMoving fix = new GPSFixMovingImpl(baseFix.getPosition(),
baseFix.getTimePoint(), speed, optionalTrueHeading);
return fix;
}
@@ -21,7 +21,9 @@ public class GPSFixMovingJsonSerializer implements JsonSerializer<GPSFixMoving>
result.put(TypeBasedJsonDeserializer.FIELD_TYPE, GPSFixMovingJsonDeserializer.TYPE);
result.put(GPSFixMovingJsonDeserializer.FIELD_BEARING_DEG, speedWithCourse.getBearing().getDegrees());
result.put(GPSFixMovingJsonDeserializer.FIELD_SPEED_KNOTS, speedWithCourse.getKnots());
if (object.getOptionalTrueHeading() != null) {
result.put(GPSFixMovingJsonDeserializer.FIELD_TRUE_HEADING_DEG, object.getOptionalTrueHeading().getDegrees());
}
return result;
}
}
@@ -75,13 +75,15 @@ These can be mapped to a competitor or a mark via the DeviceMappings in the Race
"longitude" : 10.148556,
"speed" : 3.61,
"course" : 258.11,
"hdt" : 259.0
},
{
"timestamp" : 14144168490000,
"latitude" : 55.12456,
"longitude" : 8.03456,
"speed" : 5.1,
"course" : 14.2,
"course" : 14.2
"hdt" : 14.7
}
]
}
@@ -89,7 +91,10 @@ These can be mapped to a competitor or a mark via the DeviceMappings in the Race
</td>
</tr>
Note that the "speed" field is provided in meters per second (m/s). The course is the course over ground (COG) in
true degrees.
true degrees. The "hdt" field is optional and may be used to represent a true (not magnetic) heading in degrees.
Note how this is different from "hdg" which can be used instead of "hdt" to specify a magnetic heading in degrees.
The magnetic declination at time and location of the fix will be used then to convert this internally to a true
heading.
</table>
<div style="height: 1em;"></div>
<a href="index.html">Back to Web Service Overview</a>
@@ -526,7 +526,7 @@ public class ImportMasterDataOperation extends
if (fixToAdd instanceof VeryCompactGPSFixMovingImpl) {
VeryCompactGPSFixMovingImpl gpsFix = (VeryCompactGPSFixMovingImpl) fixToAdd;
fixToAdd = new GPSFixMovingImpl(gpsFix.getPosition(), fixToAdd.getTimePoint(),
((VeryCompactGPSFixMovingImpl) fixToAdd).getSpeed());
((VeryCompactGPSFixMovingImpl) fixToAdd).getSpeed(), gpsFix.getOptionalTrueHeading());
} else if (fixToAdd instanceof VeryCompactGPSFixImpl) {
VeryCompactGPSFixImpl gpsFix = (VeryCompactGPSFixImpl) fixToAdd;
fixToAdd = new GPSFixImpl(gpsFix.getPosition(), fixToAdd.getTimePoint());
@@ -128,7 +128,7 @@ public class BoatReplicationTest extends AbstractServerReplicationTest {
EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 3000,
/* millisecondsOverWhichToAverageWind */ 30000l, /* millisecondsOverWhichToAverageSpeed */ 30000l, null));
trackedRace.getTrack(competitor).addGPSFix(new GPSFixMovingImpl(new DegreePosition(49.425, 8.293), MillisecondsTimePoint.now(),
new KnotSpeedWithBearingImpl(12.3, new DegreeBearingImpl(242.3))));
new KnotSpeedWithBearingImpl(12.3, new DegreeBearingImpl(242.3)), /* optionalTrueHeading */ null));
Thread.sleep(1000);
TrackedRace replicatedTrackedRace = replica.getTrackedRace(raceIdentifier);
assertNotNull(replicatedTrackedRace);
@@ -148,7 +148,7 @@ public class CompetitorReplicationTest extends AbstractServerReplicationTest {
EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 3000,
/* millisecondsOverWhichToAverageWind */ 30000l, /* millisecondsOverWhichToAverageSpeed */ 30000l, null));
trackedRace.getTrack(competitor).addGPSFix(new GPSFixMovingImpl(new DegreePosition(49.425, 8.293), MillisecondsTimePoint.now(),
new KnotSpeedWithBearingImpl(12.3, new DegreeBearingImpl(242.3))));
new KnotSpeedWithBearingImpl(12.3, new DegreeBearingImpl(242.3)), /* optionalTrueHeading */ null));
Thread.sleep(1000);
TrackedRace replicatedTrackedRace = replica.getTrackedRace(raceIdentifier);
assertNotNull(replicatedTrackedRace);
@@ -127,7 +127,7 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
@Test
public void testGPSFixReplication() throws InterruptedException {
final GPSFixMovingImpl fix = new GPSFixMovingImpl(new DegreePosition(1, 2), new MillisecondsTimePoint(12345),
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)), /* optionalTrueHeading */ new DegreeBearingImpl(124));
trackedRace.recordFix(competitor, fix);
Thread.sleep(1000);
TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
@@ -137,8 +137,10 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
competitorTrack.lockForRead();
try {
assertEquals(1, Util.size(competitorTrack.getRawFixes()));
PositionAssert.assertGPSFixEquals(fix, competitorTrack.getRawFixes().iterator().next(), /* pos deg delta */ 0.0000001, /* bearing deg delta */ 0.01, /* knot speed delta */ 0.01);
assertNotSame(fix, competitorTrack.getRawFixes().iterator().next());
final GPSFixMoving replicatedFix = competitorTrack.getRawFixes().iterator().next();
PositionAssert.assertGPSFixEquals(fix, replicatedFix, /* pos deg delta */ 0.0000001, /* bearing deg delta */ 0.01, /* knot speed delta */ 0.01);
assertEquals(fix.getOptionalTrueHeading().getDegrees(), replicatedFix.getOptionalTrueHeading().getDegrees(), 0.01);
assertNotSame(fix, replicatedFix);
} finally {
competitorTrack.unlockAfterRead();
}
@@ -166,7 +168,7 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
@Test
public void testMarkFixReplication() throws InterruptedException {
final GPSFixMovingImpl fix = new GPSFixMovingImpl(new DegreePosition(2, 3), new MillisecondsTimePoint(3456),
new KnotSpeedWithBearingImpl(13, new DegreeBearingImpl(234)));
new KnotSpeedWithBearingImpl(13, new DegreeBearingImpl(234)), /* optionalTrueHeading */ null);
final Mark masterMark = trackedRace.getRace().getCourse().getFirstWaypoint().getMarks().iterator().next();
trackedRace.recordFix(masterMark, fix);
Thread.sleep(1000);
@@ -153,7 +153,7 @@ public class TrackedRaceWithSensorFixStoreContentsReplicationTest extends Abstra
@Test
public void testGPSFixReplication() throws InterruptedException {
final GPSFixMovingImpl fix = new GPSFixMovingImpl(new DegreePosition(1, 2), new MillisecondsTimePoint(12345),
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)));
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)), /* optionalTrueHeading */ null);
trackedRace.recordFix(competitor, fix);
Thread.sleep(1000);
final TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
@@ -112,47 +112,47 @@ public class StatisticsTest {
public void testTrackedRaceStatisticsCacheWithFixes() throws Exception {
trackedRace.recordFix(comp,
new GPSFixMovingImpl(new DegreePosition(49.295970, 8.638958), new MillisecondsTimePoint(START_OF_RACE),
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100))));
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100)), /* optionalTrueHeading */ null));
trackedRace.recordFix(comp,
new GPSFixMovingImpl(new DegreePosition(49.295911, 8.638971),
new MillisecondsTimePoint(START_OF_RACE + 10),
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100))));
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100)), /* optionalTrueHeading */ null));
trackedRace.recordFix(comp,
new GPSFixMovingImpl(new DegreePosition(49.295866, 8.638986),
new MillisecondsTimePoint(START_OF_RACE + 20),
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100))));
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100)), /* optionalTrueHeading */ null));
trackedRace.recordFix(comp,
new GPSFixMovingImpl(new DegreePosition(49.295822, 8.639010),
new MillisecondsTimePoint(START_OF_RACE + 30),
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100))));
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100)), /* optionalTrueHeading */ null));
trackedRace.recordFix(comp,
new GPSFixMovingImpl(new DegreePosition(49.295785, 8.639057),
new MillisecondsTimePoint(START_OF_RACE + 40),
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100))));
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100)), /* optionalTrueHeading */ null));
trackedRace.recordFix(comp,
new GPSFixMovingImpl(new DegreePosition(49.295768, 8.639108),
new MillisecondsTimePoint(START_OF_RACE + 50),
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100))));
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100)), /* optionalTrueHeading */ null));
trackedRace.recordFix(comp,
new GPSFixMovingImpl(new DegreePosition(49.295761, 8.639180),
new MillisecondsTimePoint(START_OF_RACE + 60),
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100))));
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100)), /* optionalTrueHeading */ null));
trackedRace.recordFix(comp,
new GPSFixMovingImpl(new DegreePosition(49.295765, 8.639278),
new MillisecondsTimePoint(START_OF_RACE + 70),
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100))));
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100)), /* optionalTrueHeading */ null));
trackedRace.recordFix(comp,
new GPSFixMovingImpl(new DegreePosition(49.295785, 8.639353),
new MillisecondsTimePoint(START_OF_RACE + 80),
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100))));
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100)), /* optionalTrueHeading */ null));
trackedRace.recordFix(comp,
new GPSFixMovingImpl(new DegreePosition(49.295817, 8.639406),
new MillisecondsTimePoint(START_OF_RACE + 90),
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100))));
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100)), /* optionalTrueHeading */ null));
trackedRace.recordFix(comp,
new GPSFixMovingImpl(new DegreePosition(49.295861, 8.639449),
new MillisecondsTimePoint(START_OF_RACE + 100),
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100))));
new KilometersPerHourSpeedWithBearingImpl(1, new DegreeBearingImpl(100)), /* optionalTrueHeading */ null));
List<MarkPassing> markPassings = new ArrayList<>();
markPassings.add(new MarkPassingImpl(new MillisecondsTimePoint(START_OF_RACE), waypoint1, comp));
@@ -360,7 +360,7 @@ public class MasterDataImportTest {
logTimePoint3);
regatta.getRegattaLog().add(mappingEvent);
GPSFix gpsFix = new GPSFixMovingImpl(new DegreePosition(54.333, 10.133), logTimePoint2,
new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(90)));
new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(90)), /* optionalTrueHeading */ null);
sourceService.getSensorFixStore().storeFix(deviceIdentifier, gpsFix);
// test to check that batch-import of fixes works as intended
DeviceIdentifier deviceBatch1 = addDeviceMappingWithFixes(sourceService, regatta, competitor, logTimePoint, logTimePoint3, logTimePoint4, "x", 4999);
@@ -524,7 +524,7 @@ public class MasterDataImportTest {
List<GPSFix> fixesToSave = new ArrayList<>(numFixes);
for(int i = 1; i <= numFixes; i++) {
fixesToSave.add(new GPSFixMovingImpl(new DegreePosition(54.333, 10.133), logTimePoint.plus(i),
new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(90))));
new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(90)), /* optionalTrueHeading */ null));
}
sourceService.getSensorFixStore().storeFixes(deviceIdentifier, fixesToSave, /* returnManeuverUpdate */ false, /* returnLiveDelay */ false);
return deviceIdentifier;
@@ -33,7 +33,7 @@ public abstract class BaseGPSFixImporterImpl implements GPSFixImporter {
return;
}
SpeedWithBearing speedWithBearing = previousFix.getSpeedAndBearingRequiredToReach(fix);
fix = new GPSFixMovingImpl(fix.getPosition(), fix.getTimePoint(), speedWithBearing);
fix = new GPSFixMovingImpl(fix.getPosition(), fix.getTimePoint(), speedWithBearing, /* optionalTrueHeading */ null);
}
previousFix = fix;
callback.addFix(fix, device);
@@ -209,7 +209,7 @@ public class RouteConverterGPSFixImporterImpl extends BaseRouteConverterGPSFixIm
if (speedInKilometersPerHour != null && heading != null) {
SpeedWithBearing speedWithBearing = new KilometersPerHourSpeedWithBearingImpl(
speedInKilometersPerHour, new DegreeBearingImpl(heading));
result = new GPSFixMovingImpl(pos, timePoint, speedWithBearing);
result = new GPSFixMovingImpl(pos, timePoint, speedWithBearing, /* optionalTrueHeading */ null); // we assume the Wgs84Position.getHeading() method returns COG, not HDG/HDT
} else {
result = new GPSFixImpl(pos, timePoint);
}
@@ -27,6 +27,8 @@
<ul class="bulletList">
<li>The TracTrac API now offers <tt>STP</tt> and <tt>SCP</tt> as new race competitor status values
that we now map to our corresponding "IRM" / penalty codes.</li>
<li>A bug in the way mark passing calculation results were stored persistently lead to some races
"losing" their mark passings when the server was re-started. This bug is fixed now.</li>
</ul>
<h2 class="articleSubheadline">January 2024</h2>
<ul class="bulletList">
@@ -36,7 +36,6 @@ Export-Package: com.tractrac.asio.lib.api,
com.tractrac.dataflow.lib.prov.live.ascii,
com.tractrac.dataflow.lib.prov.live.provider,
com.tractrac.dataflow.lib.prov.live.server,
com.tractrac.dataflow.lib.prov.live.tcp,
com.tractrac.dataflow.lib.prov.live.tcp.provider,
com.tractrac.dataflow.lib.prov.live.tcp.server,
com.tractrac.dataflow.lib.prov.stored.mtb,