mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-20 20:55:31 +00:00
Merge branch 'ubilabs--ios--develop' of ssh://sapsailing.com/home/trac/git into ubilabs--ios--develop--signup
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>ios</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,2 @@
|
||||
CODE_SIGN_IDENTITY = iPhone Distribution
|
||||
PROVISIONING_PROFILE_SPECIFIER = Q3U792Z354/SAP Sail InSight
|
||||
@@ -1,7 +1,6 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.sap.sailing.mobile.ios</groupId>
|
||||
<artifactId>SAPTracker</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
@@ -21,4 +20,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
+1
@@ -19,6 +19,7 @@ public enum BoatClassMasterdata {
|
||||
_470 ("470", true, 4.70, 1.68, BoatHullType.MONOHULL, true, "470er", "470M", "470W", "470 - M", "470 - W"),
|
||||
_5O5 ("5O5", true, 5.03, 1.88, BoatHullType.MONOHULL, true, "505", "5o5", "505er", "5o5er"),
|
||||
_5_5MR ("5.5mR", true, 9.50, 1.92, BoatHullType.MONOHULL, true, "5.5 Meter", "5.5 Metre", "5.5", "5.5M", "5.5-metre", "5.5 metre"),
|
||||
_8MR ("8mR", true, 9.62, 2.45, BoatHullType.MONOHULL, true, "8 Meter", "8 Metre", "8M", "8-metre"),
|
||||
A_CAT ("A-Catamaran", true, 5.49, 2.30, BoatHullType.CATAMARAN, false, "A-Cat", "ACat", "A-Class Catamaran"),
|
||||
ALBIN_EXPRESS ("Albin Express", true, 7.77, 2.50, BoatHullType.MONOHULL, false),
|
||||
ALBIN_BALLAD ("Albin Ballad", true, 9.12, 2.95, BoatHullType.MONOHULL, false),
|
||||
|
||||
+10
-178
@@ -38,13 +38,10 @@ import com.sap.sailing.domain.igtimiadapter.datatypes.SOG;
|
||||
import com.sap.sailing.domain.igtimiadapter.datatypes.Type;
|
||||
import com.sap.sailing.domain.igtimiadapter.websocket.WebSocketConnectionManager;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrack;
|
||||
import com.sap.sailing.domain.tracking.Track;
|
||||
import com.sap.sailing.domain.tracking.WindListener;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackImpl;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
|
||||
/**
|
||||
* Receives Igtimi {@link Fix}es and tries to generate a {@link Wind} object from each {@link AWS} fix. For this to
|
||||
@@ -181,16 +178,12 @@ public class IgtimiWindReceiver implements BulkFixReceiver {
|
||||
|
||||
private Wind getWind(final TimePoint timePoint, String deviceSerialNumber) throws ClassNotFoundException, IOException, ParseException {
|
||||
final Wind result;
|
||||
com.sap.sse.common.Util.Pair<AWA, AWA> awaPair = getSurroundingFixes(getAwaTrack(deviceSerialNumber), timePoint);
|
||||
Bearing awa = getAWA(timePoint, awaPair);
|
||||
com.sap.sse.common.Util.Pair<AWS, AWS> awsPair = getSurroundingFixes(getAwsTrack(deviceSerialNumber), timePoint);
|
||||
Speed aws = getAWS(timePoint, awsPair);
|
||||
com.sap.sse.common.Util.Pair<GpsLatLong, GpsLatLong> gpsPair = getSurroundingFixes(getGpsTrack(deviceSerialNumber), timePoint);
|
||||
Position pos = getPosition(timePoint, gpsPair);
|
||||
Bearing awaFrom = getAwaTrack(deviceSerialNumber).getInterpolatedValue(timePoint, a->new ScalableBearing(a.getApparentWindAngle()));
|
||||
Bearing awa = awaFrom==null?null:awaFrom.reverse();
|
||||
Speed aws = getAwsTrack(deviceSerialNumber).getInterpolatedValue(timePoint, a->new ScalableSpeed(a.getApparentWindSpeed()));
|
||||
Position pos = getGpsTrack(deviceSerialNumber).getInterpolatedValue(timePoint, g->new ScalablePosition(g.getPosition()));
|
||||
if (pos != null) {
|
||||
com.sap.sse.common.Util.Pair<HDG, HDG> hdgPair = getSurroundingFixes(getHdgTrack(deviceSerialNumber), timePoint);
|
||||
com.sap.sse.common.Util.Pair<HDGM, HDGM> hdgmPair = getSurroundingFixes(getHdgmTrack(deviceSerialNumber), timePoint);
|
||||
Bearing heading = getHeading(timePoint, hdgPair, hdgmPair, pos);
|
||||
Bearing heading = getHeading(timePoint, deviceSerialNumber, pos);
|
||||
if (awa != null && aws != null && heading != null) {
|
||||
Bearing apparentWindDirection = heading.add(awa);
|
||||
SpeedWithBearing apparentWindSpeedWithDirection = new KnotSpeedWithBearingImpl(aws.getKnots(), apparentWindDirection);
|
||||
@@ -218,10 +211,8 @@ public class IgtimiWindReceiver implements BulkFixReceiver {
|
||||
* So again, my personal preference would be to work with the data that should be the most accurate
|
||||
* (COG/SOG) and consider algorithms that handle smoothing of that data best."
|
||||
*/
|
||||
com.sap.sse.common.Util.Pair<SOG, SOG> sogPair = getSurroundingFixes(getSogTrack(deviceSerialNumber), timePoint);
|
||||
Speed sog = getSOG(timePoint, sogPair);
|
||||
com.sap.sse.common.Util.Pair<COG, COG> cogPair = getSurroundingFixes(getCogTrack(deviceSerialNumber), timePoint);
|
||||
Bearing cog = getCOG(timePoint, cogPair);
|
||||
Speed sog = getSogTrack(deviceSerialNumber).getInterpolatedValue(timePoint, s->new ScalableSpeed(s.getSpeedOverGround()));
|
||||
Bearing cog = getCogTrack(deviceSerialNumber).getInterpolatedValue(timePoint, c->new ScalableBearing(c.getCourseOverGround()));
|
||||
if (sog != null && cog != null) {
|
||||
SpeedWithBearing sogCog = new KnotSpeedWithBearingImpl(sog.getKnots(), cog);
|
||||
SpeedWithBearing trueWindSpeedAndDirection = apparentWindSpeedWithDirection.add(sogCog);
|
||||
@@ -238,153 +229,13 @@ public class IgtimiWindReceiver implements BulkFixReceiver {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Bearing getAWA(TimePoint timePoint, com.sap.sse.common.Util.Pair<AWA, AWA> awaPair) {
|
||||
final Bearing awaFrom;
|
||||
if (awaPair.getA() == null) {
|
||||
if (awaPair.getB() == null) {
|
||||
awaFrom = null;
|
||||
} else {
|
||||
awaFrom = awaPair.getB().getApparentWindAngle();
|
||||
}
|
||||
} else {
|
||||
if (awaPair.getB() == null) {
|
||||
awaFrom = awaPair.getA().getApparentWindAngle();
|
||||
} else {
|
||||
awaFrom = timeBasedAgerage(timePoint,
|
||||
new ScalableBearing(awaPair.getA().getApparentWindAngle()), awaPair.getA().getTimePoint(),
|
||||
new ScalableBearing(awaPair.getB().getApparentWindAngle()), awaPair.getB().getTimePoint());
|
||||
}
|
||||
}
|
||||
return awaFrom == null ? null : awaFrom.reverse();
|
||||
}
|
||||
|
||||
private Speed getAWS(TimePoint timePoint, com.sap.sse.common.Util.Pair<AWS, AWS> awsPair) {
|
||||
final Speed aws;
|
||||
if (awsPair.getA() == null) {
|
||||
if (awsPair.getB() == null) {
|
||||
aws = null;
|
||||
} else {
|
||||
aws = awsPair.getB().getApparentWindSpeed();
|
||||
}
|
||||
} else {
|
||||
if (awsPair.getB() == null) {
|
||||
aws = awsPair.getA().getApparentWindSpeed();
|
||||
} else {
|
||||
aws = timeBasedAgerage(timePoint,
|
||||
new ScalableSpeed(awsPair.getA().getApparentWindSpeed()), awsPair.getA().getTimePoint(),
|
||||
new ScalableSpeed(awsPair.getB().getApparentWindSpeed()), awsPair.getB().getTimePoint());
|
||||
}
|
||||
}
|
||||
return aws;
|
||||
}
|
||||
|
||||
private Speed getSOG(TimePoint timePoint, com.sap.sse.common.Util.Pair<SOG, SOG> sogPair) {
|
||||
final Speed sog;
|
||||
if (sogPair.getA() == null) {
|
||||
if (sogPair.getB() == null) {
|
||||
sog = null;
|
||||
} else {
|
||||
sog = sogPair.getB().getSpeedOverGround();
|
||||
}
|
||||
} else {
|
||||
if (sogPair.getB() == null) {
|
||||
sog = sogPair.getA().getSpeedOverGround();
|
||||
} else {
|
||||
sog = timeBasedAgerage(timePoint,
|
||||
new ScalableSpeed(sogPair.getA().getSpeedOverGround()), sogPair.getA().getTimePoint(),
|
||||
new ScalableSpeed(sogPair.getB().getSpeedOverGround()), sogPair.getB().getTimePoint());
|
||||
}
|
||||
}
|
||||
return sog;
|
||||
}
|
||||
|
||||
private Bearing getCOG(TimePoint timePoint, com.sap.sse.common.Util.Pair<COG, COG> cogPair) {
|
||||
final Bearing sog;
|
||||
if (cogPair.getA() == null) {
|
||||
if (cogPair.getB() == null) {
|
||||
sog = null;
|
||||
} else {
|
||||
sog = cogPair.getB().getCourseOverGround();
|
||||
}
|
||||
} else {
|
||||
if (cogPair.getB() == null) {
|
||||
sog = cogPair.getA().getCourseOverGround();
|
||||
} else {
|
||||
sog = timeBasedAgerage(timePoint,
|
||||
new ScalableBearing(cogPair.getA().getCourseOverGround()), cogPair.getA().getTimePoint(),
|
||||
new ScalableBearing(cogPair.getB().getCourseOverGround()), cogPair.getB().getTimePoint());
|
||||
}
|
||||
}
|
||||
return sog;
|
||||
}
|
||||
|
||||
private Position getPosition(TimePoint timePoint, com.sap.sse.common.Util.Pair<GpsLatLong, GpsLatLong> gpsPair) {
|
||||
final Position pos;
|
||||
if (gpsPair.getA() == null) {
|
||||
if (gpsPair.getB() == null) {
|
||||
pos = null;
|
||||
} else {
|
||||
pos = gpsPair.getB().getPosition();
|
||||
}
|
||||
} else {
|
||||
if (gpsPair.getB() == null) {
|
||||
pos = gpsPair.getA().getPosition();
|
||||
} else {
|
||||
pos = timeBasedAgerage(timePoint, new ScalablePosition(gpsPair.getA().getPosition()), gpsPair.getA()
|
||||
.getTimePoint(), new ScalablePosition(gpsPair.getB().getPosition()), gpsPair.getB()
|
||||
.getTimePoint());
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
private Bearing getHDG(TimePoint timePoint, com.sap.sse.common.Util.Pair<HDG, HDG> hdgPair) {
|
||||
final Bearing hdg;
|
||||
if (hdgPair.getA() == null) {
|
||||
if (hdgPair.getB() == null) {
|
||||
hdg = null;
|
||||
} else {
|
||||
hdg = hdgPair.getB().getTrueHeading();
|
||||
}
|
||||
} else {
|
||||
if (hdgPair.getB() == null) {
|
||||
hdg = hdgPair.getA().getTrueHeading();
|
||||
} else {
|
||||
hdg = timeBasedAgerage(timePoint,
|
||||
new ScalableBearing(hdgPair.getA().getTrueHeading()), hdgPair.getA().getTimePoint(),
|
||||
new ScalableBearing(hdgPair.getB().getTrueHeading()), hdgPair.getB().getTimePoint());
|
||||
}
|
||||
}
|
||||
return hdg;
|
||||
}
|
||||
|
||||
private Bearing getHDGM(TimePoint timePoint, com.sap.sse.common.Util.Pair<HDGM, HDGM> hdgmPair) {
|
||||
final Bearing hdgm;
|
||||
if (hdgmPair.getA() == null) {
|
||||
if (hdgmPair.getB() == null) {
|
||||
hdgm = null;
|
||||
} else {
|
||||
hdgm = hdgmPair.getB().getMagnetigHeading();
|
||||
}
|
||||
} else {
|
||||
if (hdgmPair.getB() == null) {
|
||||
hdgm = hdgmPair.getA().getMagnetigHeading();
|
||||
} else {
|
||||
hdgm = timeBasedAgerage(timePoint,
|
||||
new ScalableBearing(hdgmPair.getA().getMagnetigHeading()), hdgmPair.getA().getTimePoint(),
|
||||
new ScalableBearing(hdgmPair.getB().getMagnetigHeading()), hdgmPair.getB().getTimePoint());
|
||||
}
|
||||
}
|
||||
return hdgm;
|
||||
}
|
||||
|
||||
private Bearing getHeading(TimePoint timePoint, com.sap.sse.common.Util.Pair<HDG, HDG> hdgPair, com.sap.sse.common.Util.Pair<HDGM, HDGM> hdgmPair, Position position) throws ClassNotFoundException, IOException, ParseException {
|
||||
private Bearing getHeading(TimePoint timePoint, String deviceSerialNumber, Position position) throws ClassNotFoundException, IOException, ParseException {
|
||||
final Bearing trueHeading;
|
||||
Bearing hdg = getHDG(timePoint, hdgPair);
|
||||
Bearing hdg = getHdgTrack(deviceSerialNumber).getInterpolatedValue(timePoint, h->new ScalableBearing(h.getTrueHeading()));
|
||||
if (hdg != null) {
|
||||
trueHeading = hdg;
|
||||
} else {
|
||||
Bearing hdgm = getHDGM(timePoint, hdgmPair);
|
||||
Bearing hdgm = getHdgmTrack(deviceSerialNumber).getInterpolatedValue(timePoint, h->new ScalableBearing(h.getMagnetigHeading()));
|
||||
if (hdgm != null) {
|
||||
if (declinationService == null) {
|
||||
trueHeading = hdgm;
|
||||
@@ -405,25 +256,6 @@ public class IgtimiWindReceiver implements BulkFixReceiver {
|
||||
return trueHeading;
|
||||
}
|
||||
|
||||
private <V, T> T timeBasedAgerage(TimePoint timePoint, ScalableValue<V, T> value1, TimePoint timePoint1, ScalableValue<V, T> value2, TimePoint timePoint2) {
|
||||
final T acc;
|
||||
if (timePoint1.equals(timePoint2)) {
|
||||
acc = value1.add(value2).divide(2);
|
||||
} else {
|
||||
long timeDiff1 = Math.abs(timePoint1.asMillis() - timePoint.asMillis());
|
||||
long timeDiff2 = Math.abs(timePoint2.asMillis() - timePoint.asMillis());
|
||||
acc = value1.multiply(timeDiff2).add(value2.multiply(timeDiff1)).divide(timeDiff1 + timeDiff2);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
private <T extends Timed> com.sap.sse.common.Util.Pair<T, T> getSurroundingFixes(Track<T> track, TimePoint timePoint) {
|
||||
T left = track.getLastFixAtOrBefore(timePoint);
|
||||
T right = track.getFirstFixAtOrAfter(timePoint);
|
||||
com.sap.sse.common.Util.Pair<T, T> result = new com.sap.sse.common.Util.Pair<>(left, right);
|
||||
return result;
|
||||
}
|
||||
|
||||
private DynamicTrack<AWA> getAwaTrack(String deviceSerialNumber) {
|
||||
return getTrack(deviceSerialNumber, awaTrack);
|
||||
}
|
||||
|
||||
+8
@@ -17,6 +17,8 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
|
||||
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Function;
|
||||
import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
|
||||
/**
|
||||
* Wrapper for a {@link RaceLog} which will ignore all calls trying to add an {@link RaceLogEvent}. All other
|
||||
@@ -250,6 +252,12 @@ public class NoAddingRaceLogWrapper implements RaceLog {
|
||||
public void revokeEvent(AbstractLogEventAuthor author, RaceLogEvent toRevoke) throws NotRevokableException {
|
||||
innerRaceLog.revokeEvent(author, toRevoke);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <InternalType, ValueType> ValueType getInterpolatedValue(TimePoint timePoint,
|
||||
Function<RaceLogEvent, ScalableValue<InternalType, ValueType>> converter) {
|
||||
return innerRaceLog.getInterpolatedValue(timePoint, converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
|
||||
+6
@@ -1,6 +1,10 @@
|
||||
package com.sap.sailing.domain.statistics;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
|
||||
/**
|
||||
* A {@link Statistics} object represents several statistical information.
|
||||
@@ -41,4 +45,6 @@ public interface Statistics {
|
||||
* @return the totally sailed {@link Distance}; never {@code null}
|
||||
*/
|
||||
Distance getDistanceTraveled();
|
||||
|
||||
Triple<Competitor, Speed, TimePoint> getMaxSpeed();
|
||||
}
|
||||
|
||||
+11
-1
@@ -1,7 +1,11 @@
|
||||
package com.sap.sailing.domain.statistics.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.statistics.Statistics;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
|
||||
public class StatisticsImpl implements Statistics {
|
||||
|
||||
@@ -12,6 +16,7 @@ public class StatisticsImpl implements Statistics {
|
||||
private final long numberOfGPSFixes;
|
||||
private final long numberOfWindFixes;
|
||||
private final Distance distanceTraveled;
|
||||
private final Triple<Competitor, Speed, TimePoint> maxSpeed;
|
||||
|
||||
/**
|
||||
* @param distanceTraveled
|
||||
@@ -20,7 +25,7 @@ public class StatisticsImpl implements Statistics {
|
||||
* further {@code null} checks.
|
||||
*/
|
||||
public StatisticsImpl(int numberOfCompetitors, int numberOfRegattas, int numberOfRaces, int numberOfTrackedRaces,
|
||||
long numberOfGPSFixes, long numberOfWindFixes, Distance distanceTraveled) {
|
||||
long numberOfGPSFixes, long numberOfWindFixes, Distance distanceTraveled, Triple<Competitor, Speed, TimePoint> maxSpeed) {
|
||||
super();
|
||||
this.numberOfCompetitors = numberOfCompetitors;
|
||||
this.numberOfRegattas = numberOfRegattas;
|
||||
@@ -29,6 +34,7 @@ public class StatisticsImpl implements Statistics {
|
||||
this.numberOfGPSFixes = numberOfGPSFixes;
|
||||
this.numberOfWindFixes = numberOfWindFixes;
|
||||
this.distanceTraveled = distanceTraveled == null ? Distance.NULL : distanceTraveled;
|
||||
this.maxSpeed = maxSpeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,4 +71,8 @@ public class StatisticsImpl implements Statistics {
|
||||
public Distance getDistanceTraveled() {
|
||||
return distanceTraveled;
|
||||
}
|
||||
|
||||
public Triple<Competitor, Speed, TimePoint> getMaxSpeed() {
|
||||
return maxSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
+24
@@ -4,9 +4,12 @@ import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.Util.Function;
|
||||
import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
|
||||
/**
|
||||
* A track records {@link Timed} items for an object of type <code>ItemType</code>. It allows clients to ask for a value
|
||||
@@ -117,6 +120,27 @@ public interface Track<FixType extends Timed> extends Serializable {
|
||||
*/
|
||||
FixType getLastRawFix();
|
||||
|
||||
/**
|
||||
* Interpolates an aspect of the fixes in this track for a given {@code timePoint}. If {@code timePoint} matches
|
||||
* exactly a fix in this track, that fix is used. If this track is empty, {@code null} is returned. If the
|
||||
* {@code timePoint} is after the last fix of this track, the last fix is used; if before the first fix, the first
|
||||
* fix is used.
|
||||
* <p>
|
||||
*
|
||||
* The fix(es) are converted to {@link ScalableValue}s using the {@code converter} which gives callers a choice
|
||||
* which aspect of the fixes to project and interpolate. If more than one value results because two fixes (one
|
||||
* before, one after) are used, linear interpolation based on the fixes' time points takes place.
|
||||
* <p>
|
||||
*
|
||||
* Example: for a track of {@link GPSFixMoving} fixes the course over ground shall be determined for a given time
|
||||
* point. The call would look like this:
|
||||
* {@code getInterpolatedValue(timePoint, f->new ScalableBearing(f.getSpeed().getBearing()))}
|
||||
*
|
||||
* @return the projected interpolated value, typed by what the {@link ScalableValue#divide(double)} method returns.
|
||||
*/
|
||||
<InternalType, ValueType> ValueType getInterpolatedValue(TimePoint timePoint,
|
||||
Function<FixType, ScalableValue<InternalType, ValueType>> converter);
|
||||
|
||||
/**
|
||||
* Returns an iterator starting at the first fix after <code>startingAt</code> (or "at or after" in case
|
||||
* <code>inclusive</code> is <code>true</code>). The fixes returned by the iterator are the smoothened fixes (see
|
||||
|
||||
+44
@@ -10,6 +10,9 @@ import com.sap.sailing.domain.tracking.Track;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Timed;
|
||||
import com.sap.sse.common.Util.Function;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.scalablevalue.ScalableValue;
|
||||
import com.sap.sse.concurrent.LockUtil;
|
||||
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
||||
import com.sap.sse.util.impl.ArrayListNavigableSet;
|
||||
@@ -251,6 +254,47 @@ public class TrackImpl<FixType extends Timed> implements Track<FixType> {
|
||||
}
|
||||
}
|
||||
|
||||
private Pair<FixType, FixType> getSurroundingFixes(TimePoint timePoint) {
|
||||
FixType left = getLastFixAtOrBefore(timePoint);
|
||||
FixType right = getFirstFixAtOrAfter(timePoint);
|
||||
com.sap.sse.common.Util.Pair<FixType, FixType> result = new com.sap.sse.common.Util.Pair<>(left, right);
|
||||
return result;
|
||||
}
|
||||
|
||||
private <V, T> T timeBasedAverage(TimePoint timePoint, ScalableValue<V, T> value1, TimePoint timePoint1, ScalableValue<V, T> value2, TimePoint timePoint2) {
|
||||
final T acc;
|
||||
if (timePoint1.equals(timePoint2)) {
|
||||
acc = value1.add(value2).divide(2);
|
||||
} else {
|
||||
long timeDiff1 = Math.abs(timePoint1.asMillis() - timePoint.asMillis());
|
||||
long timeDiff2 = Math.abs(timePoint2.asMillis() - timePoint.asMillis());
|
||||
acc = value1.multiply(timeDiff2).add(value2.multiply(timeDiff1)).divide(timeDiff1 + timeDiff2);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <InternalType, ValueType> ValueType getInterpolatedValue(TimePoint timePoint, Function<FixType, ScalableValue<InternalType, ValueType>> converter) {
|
||||
final ValueType result;
|
||||
Pair<FixType, FixType> fixPair = getSurroundingFixes(timePoint);
|
||||
if (fixPair.getA() == null) {
|
||||
if (fixPair.getB() == null) {
|
||||
result = null;
|
||||
} else {
|
||||
result = converter.get(fixPair.getB()).divide(1);
|
||||
}
|
||||
} else {
|
||||
if (fixPair.getB() == null || fixPair.getA() == fixPair.getB()) {
|
||||
result = converter.get(fixPair.getA()).divide(1);
|
||||
} else {
|
||||
result = timeBasedAverage(timePoint,
|
||||
converter.get(fixPair.getA()), fixPair.getA().getTimePoint(),
|
||||
converter.get(fixPair.getB()), fixPair.getB().getTimePoint());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<FixType> getFixesIterator(TimePoint startingAt, boolean inclusive) {
|
||||
assertReadLock();
|
||||
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
package com.sap.sailing.domain.common.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
|
||||
|
||||
public class ScalableBearingTest {
|
||||
@Test
|
||||
public void testTrivialScaling() {
|
||||
Bearing b = new DegreeBearingImpl(123);
|
||||
ScalableBearing sb = new ScalableBearing(b);
|
||||
Bearing reducedScalableBearing = sb.divide(1);
|
||||
assertEquals(b.getDegrees(), reducedScalableBearing.getDegrees(), 0.0001);
|
||||
}
|
||||
}
|
||||
Regular → Executable
+17
-1
@@ -41,12 +41,14 @@ import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.impl.MeterPerSecondSpeedWithDegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableSpeed;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.CompactionNotPossibleException;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.common.tracking.impl.VeryCompactGPSFixMovingImpl;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.impl.DistanceCache;
|
||||
@@ -109,6 +111,20 @@ public class TrackTest {
|
||||
track.addGPSFix(gpsFix5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bearingInterpolationTest() {
|
||||
TimePoint betweenFirstAndSecond = gpsFix1.getTimePoint().plus(gpsFix1.getTimePoint().until(gpsFix2.getTimePoint()).divide(2));
|
||||
Bearing bearingBetweenFirstAndSecond = track.getInterpolatedValue(betweenFirstAndSecond, f->new ScalableBearing(f.getSpeed().getBearing()));
|
||||
assertEquals(bearingBetweenFirstAndSecond.getDegrees(), gpsFix1.getSpeed().getBearing().middle(gpsFix2.getSpeed().getBearing()).getDegrees(), 0.00001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void speedInterpolationTest() {
|
||||
TimePoint betweenFirstAndSecond = gpsFix1.getTimePoint().plus(gpsFix1.getTimePoint().until(gpsFix2.getTimePoint()).divide(2));
|
||||
Speed speedBetweenFirstAndSecond = track.getInterpolatedValue(betweenFirstAndSecond, f->new ScalableSpeed(f.getSpeed()));
|
||||
assertEquals(speedBetweenFirstAndSecond.getKnots(), (gpsFix1.getSpeed().getKnots()+gpsFix2.getSpeed().getKnots())/2, 0.01);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for a incorrect method of estimating Positions
|
||||
*/
|
||||
|
||||
Regular → Executable
@@ -147,4 +147,11 @@
|
||||
version="1.9.4"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="net.sf.marineapi"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.5.0.qualifier"
|
||||
unpack="false"/>
|
||||
|
||||
</feature>
|
||||
|
||||
@@ -388,4 +388,11 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.nmeaconnector"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false"/>
|
||||
|
||||
</feature>
|
||||
|
||||
-2
@@ -2,7 +2,6 @@ package com.sap.sailing.gwt.autoplay.client.places.screens.afterliveraceloop.boa
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.user.client.ui.AcceptsOneWidget;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
@@ -103,7 +102,6 @@ public class RaceEndWithBoatsPresenterImpl extends AutoPlayPresenterConfigured<A
|
||||
raceColumn = column;
|
||||
}
|
||||
}
|
||||
GWT.debugger();
|
||||
List<CompetitorDTO> sortedCompetitors = leaderboardPanel.getLeaderboard()
|
||||
.getCompetitorsFromBestToWorst(raceColumn);
|
||||
|
||||
|
||||
+1
@@ -34,6 +34,7 @@ public class BoatClassImageResolver {
|
||||
boatClassIconsMap.put(BoatClassMasterdata._49ER.getDisplayName(), imageResources._49erIcon());
|
||||
boatClassIconsMap.put(BoatClassMasterdata._5O5.getDisplayName(), imageResources._505mIcon());
|
||||
boatClassIconsMap.put(BoatClassMasterdata._5_5MR.getDisplayName(), imageResources._5_5MRIcon());
|
||||
boatClassIconsMap.put(BoatClassMasterdata._8MR.getDisplayName(), imageResources._8MRIcon());
|
||||
boatClassIconsMap.put(BoatClassMasterdata.A_CAT.getDisplayName(), imageResources.A_CatIcon());
|
||||
boatClassIconsMap.put(BoatClassMasterdata.ALBIN_EXPRESS.getDisplayName(), imageResources.AlbinExpressIcon());
|
||||
boatClassIconsMap.put(BoatClassMasterdata.ALBIN_BALLAD.getDisplayName(), imageResources.AlbinBalladIcon());
|
||||
|
||||
+3
@@ -40,6 +40,9 @@ public interface BoatClassImageResources extends ClientBundle {
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/5.5mR.png")
|
||||
ImageResource _5_5MRIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/8MR.png")
|
||||
ImageResource _8MRIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/A_CAT.png")
|
||||
ImageResource A_CatIcon();
|
||||
|
||||
|
||||
+11
-5
@@ -60,14 +60,14 @@ public class GetEventOverviewStageAction implements SailingAction<ResultWithTTL<
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<EventOverviewStageDTO> execute(SailingDispatchContext context) {
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
Event event = context.getRacingEventService().getEvent(eventId);
|
||||
EventState state = HomeServiceUtil.calculateEventState(event);
|
||||
final TimePoint now = MillisecondsTimePoint.now();
|
||||
final Event event = context.getRacingEventService().getEvent(eventId);
|
||||
final EventState state = HomeServiceUtil.calculateEventState(event);
|
||||
long ttl = Duration.ONE_MINUTE.times(5).asMillis();
|
||||
if(state == EventState.RUNNING) {
|
||||
ttl = Duration.ONE_MINUTE.times(2).asMillis();
|
||||
}
|
||||
if(state == EventState.UPCOMING || state == EventState.PLANNED) {
|
||||
if (isUpcomingOrPlanned(event, state)) {
|
||||
ttl = Math.min(ttl, now.until(event.getStartDate()).asMillis());
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public class GetEventOverviewStageAction implements SailingAction<ResultWithTTL<
|
||||
}
|
||||
|
||||
// Show countdown for planned or upcoming events
|
||||
if(state == EventState.UPCOMING || state == EventState.PLANNED) {
|
||||
if (isUpcomingOrPlanned(event, state)) {
|
||||
return new EventOverviewTickerStageDTO(event.getStartDate().asDate(), event.getName(), imageUrl);
|
||||
}
|
||||
return new EventOverviewTickerStageDTO(null, null, imageUrl);
|
||||
@@ -153,6 +153,12 @@ public class GetEventOverviewStageAction implements SailingAction<ResultWithTTL<
|
||||
// return new EventOverviewTickerStageDTO(null, null, stageImageUrl);
|
||||
}
|
||||
|
||||
@GwtIncompatible
|
||||
private boolean isUpcomingOrPlanned(Event event, EventState state) {
|
||||
final TimePoint startDate = event.getStartDate();
|
||||
return startDate != null && (state == EventState.UPCOMING || state == EventState.PLANNED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cacheInstanceKey(StringBuilder key) {
|
||||
key.append(eventId).append("_").append(useTeaserImage);
|
||||
|
||||
+11
-10
@@ -4,6 +4,7 @@ import com.google.gwt.core.shared.GwtIncompatible;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
import com.sap.sse.gwt.dispatch.shared.commands.DTO;
|
||||
@@ -15,8 +16,8 @@ public class EventStatisticsDTO implements DTO {
|
||||
private int trackedRacesCount;
|
||||
private long numberOfGPSFixes;
|
||||
private long numberOfWindFixes;
|
||||
private String competitorInfo;
|
||||
private Double competitorSpeedInKnots;
|
||||
private SimpleCompetitorDTO fastestCompetitor;
|
||||
private Double fastestCompetitorSpeedInKnots;
|
||||
private Distance totalDistanceTraveled;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@@ -35,8 +36,8 @@ public class EventStatisticsDTO implements DTO {
|
||||
this.numberOfGPSFixes = numberOfGPSFixes;
|
||||
this.numberOfWindFixes = numberOfWindFixes;
|
||||
if (maxSpeed != null) {
|
||||
this.competitorInfo = maxSpeed.getA().getName();
|
||||
this.competitorSpeedInKnots = maxSpeed.getB().getKnots();
|
||||
this.fastestCompetitor = new SimpleCompetitorDTO(maxSpeed.getA());
|
||||
this.fastestCompetitorSpeedInKnots = maxSpeed.getB().getKnots();
|
||||
}
|
||||
this.totalDistanceTraveled = totalDistanceTraveled;
|
||||
}
|
||||
@@ -80,13 +81,13 @@ public class EventStatisticsDTO implements DTO {
|
||||
public long getNumberOfWindFixes() {
|
||||
return numberOfWindFixes;
|
||||
}
|
||||
|
||||
public String getCompetitorInfo() {
|
||||
return competitorInfo;
|
||||
|
||||
public SimpleCompetitorDTO getFastestCompetitor() {
|
||||
return fastestCompetitor;
|
||||
}
|
||||
|
||||
public Double getCompetitorSpeed() {
|
||||
return competitorSpeedInKnots;
|
||||
|
||||
public Double getFastestCompetitorSpeedInKnots() {
|
||||
return fastestCompetitorSpeedInKnots;
|
||||
}
|
||||
|
||||
public Distance getTotalDistanceTraveled() {
|
||||
|
||||
+21
@@ -5,8 +5,13 @@ import java.util.List;
|
||||
|
||||
import com.google.gwt.core.shared.GwtIncompatible;
|
||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.statistics.Statistics;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
|
||||
public class EventListYearDTO implements IsSerializable {
|
||||
private int year;
|
||||
@@ -18,6 +23,9 @@ public class EventListYearDTO implements IsSerializable {
|
||||
private long numberOfGPSFixes;
|
||||
private long numberOfWindFixes;
|
||||
private Distance distanceTraveled;
|
||||
private SimpleCompetitorDTO fastestCompetitor;
|
||||
private Double fastestCompetitorSpeedInKnots;
|
||||
|
||||
private ArrayList<EventListEventDTO> events = new ArrayList<>();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@@ -57,6 +65,11 @@ public class EventListYearDTO implements IsSerializable {
|
||||
numberOfGPSFixes = statistics.getNumberOfGPSFixes();
|
||||
numberOfWindFixes = statistics.getNumberOfWindFixes();
|
||||
distanceTraveled = statistics.getDistanceTraveled();
|
||||
final Triple<Competitor, Speed, TimePoint> maxSpeed = statistics.getMaxSpeed();
|
||||
if (maxSpeed != null) {
|
||||
fastestCompetitor = new SimpleCompetitorDTO(maxSpeed.getA());
|
||||
fastestCompetitorSpeedInKnots = maxSpeed.getB().getKnots();
|
||||
}
|
||||
}
|
||||
|
||||
public int getEventCount() {
|
||||
@@ -90,4 +103,12 @@ public class EventListYearDTO implements IsSerializable {
|
||||
public Distance getDistanceTraveled() {
|
||||
return distanceTraveled;
|
||||
}
|
||||
|
||||
public SimpleCompetitorDTO getFastestCompetitor() {
|
||||
return fastestCompetitor;
|
||||
}
|
||||
|
||||
public Double getFastestCompetitorSpeedInKnots() {
|
||||
return fastestCompetitorSpeedInKnots;
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -156,4 +156,5 @@
|
||||
font-size: 0.933333333333333rem;
|
||||
padding: 0.714285714285714em 1.071428571428571em;
|
||||
color: #666;
|
||||
min-height: 2.533333333333333rem;
|
||||
}
|
||||
|
||||
+5
@@ -69,4 +69,9 @@ img.statisticsbox_item_icon {
|
||||
padding: 0.2em;
|
||||
border: 1px solid #dedede;
|
||||
border-radius: 0.333333333333333em;
|
||||
display: inline-block;
|
||||
max-width: 35%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
+3
-1
@@ -23,7 +23,9 @@ class StatisticsBoxItem extends UIObject {
|
||||
setElement(uiBinder.createAndBindUi(this));
|
||||
iconUi.setSrc(iconUrl);
|
||||
nameUi.setInnerText(name);
|
||||
valueUi.setInnerText(payload == null ? "n/a" : String.valueOf(payload));
|
||||
final String text = payload == null ? "n/a" : String.valueOf(payload);
|
||||
valueUi.setInnerText(text);
|
||||
valueUi.setTitle(text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
@@ -56,4 +56,9 @@ img.statisticsbox_content_item_icon {
|
||||
background: #ebebeb;
|
||||
border: 1px solid #dedede;
|
||||
border-radius: 0.384615384615385em;
|
||||
display: inline-block;
|
||||
max-width: 35%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
+3
-1
@@ -23,7 +23,9 @@ class StatisticsBoxItem extends Widget {
|
||||
setElement(uiBinder.createAndBindUi(this));
|
||||
iconUi.setSrc(iconUrl);
|
||||
nameUi.setInnerText(name);
|
||||
valueUi.setInnerText(payload == null ? "n/a" : String.valueOf(payload));
|
||||
final String text = payload == null ? "n/a" : String.valueOf(payload);
|
||||
valueUi.setInnerText(text);
|
||||
valueUi.setTitle(text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-9
@@ -143,18 +143,20 @@ public final class EventActionUtil {
|
||||
* @return The calculated {@link Duration time to live}
|
||||
*/
|
||||
public static Duration calculateTtlForNonLiveEvent(Event event, EventState eventState) {
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
if(eventState == EventState.UPCOMING || eventState == EventState.PLANNED) {
|
||||
Duration tillStart = now.until(event.getStartDate());
|
||||
double hoursTillStart = tillStart.asHours();
|
||||
long ttl = Duration.ONE_HOUR.asMillis();
|
||||
if(hoursTillStart < 36) {
|
||||
ttl = Duration.ONE_MINUTE.times(30).asMillis();
|
||||
final TimePoint startDate = event.getStartDate();
|
||||
if (startDate != null) {
|
||||
final Duration tillStart = MillisecondsTimePoint.now().until(startDate);
|
||||
final double hoursTillStart = tillStart.asHours();
|
||||
if (hoursTillStart < 36) {
|
||||
ttl = Duration.ONE_MINUTE.times(30).asMillis();
|
||||
}
|
||||
if (hoursTillStart < 3) {
|
||||
ttl = Duration.ONE_MINUTE.times(15).asMillis();
|
||||
}
|
||||
ttl = Math.min(ttl, tillStart.asMillis());
|
||||
}
|
||||
if(hoursTillStart < 3) {
|
||||
ttl = Duration.ONE_MINUTE.times(15).asMillis();
|
||||
}
|
||||
ttl = Math.min(ttl, tillStart.asMillis());
|
||||
return new MillisecondsDurationImpl(ttl);
|
||||
}
|
||||
if(eventState == EventState.FINISHED) {
|
||||
|
||||
+13
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.gwt.home.shared.partials.statistics;
|
||||
|
||||
import com.google.gwt.i18n.client.NumberFormat;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
public abstract class AbstractStatisticsBoxPresenter {
|
||||
@@ -12,6 +13,18 @@ public abstract class AbstractStatisticsBoxPresenter {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
public void addCompetitorItem(String iconUrl, String name, SimpleCompetitorDTO competitor) {
|
||||
if (competitor != null) {
|
||||
addItem(iconUrl, name, competitor.getSailID() != null ? competitor.getSailID() : competitor.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public void addKnotsItem(String iconUrl, String name, Double speedInKnots) {
|
||||
if (speedInKnots != null) {
|
||||
addItem(iconUrl, name, StringMessages.INSTANCE.knotsValue(speedInKnots));
|
||||
}
|
||||
}
|
||||
|
||||
public void addItemWithCompactFormat(String iconUrl, String name, Double payload) {
|
||||
if (payload != null && payload != 0) {
|
||||
addItem(iconUrl, name, compactNumber(payload));
|
||||
|
||||
+10
-3
@@ -1,6 +1,13 @@
|
||||
package com.sap.sailing.gwt.home.shared.partials.statistics;
|
||||
|
||||
import static com.sap.sailing.gwt.home.shared.partials.statistics.StatisticsBoxConstants.*;
|
||||
import static com.sap.sailing.gwt.home.shared.partials.statistics.StatisticsBoxConstants.ICON_COMPATITORS_COUNT;
|
||||
import static com.sap.sailing.gwt.home.shared.partials.statistics.StatisticsBoxConstants.ICON_FASTEST_SAILOR;
|
||||
import static com.sap.sailing.gwt.home.shared.partials.statistics.StatisticsBoxConstants.ICON_RACES_COUNT;
|
||||
import static com.sap.sailing.gwt.home.shared.partials.statistics.StatisticsBoxConstants.ICON_RAW_GPS_FIX;
|
||||
import static com.sap.sailing.gwt.home.shared.partials.statistics.StatisticsBoxConstants.ICON_REGATTAS_FOUGHT;
|
||||
import static com.sap.sailing.gwt.home.shared.partials.statistics.StatisticsBoxConstants.ICON_SUM_MILES;
|
||||
import static com.sap.sailing.gwt.home.shared.partials.statistics.StatisticsBoxConstants.ICON_TRACKED_COUNT;
|
||||
import static com.sap.sailing.gwt.home.shared.partials.statistics.StatisticsBoxConstants.ICON_WIND_FIX;
|
||||
|
||||
import com.sap.sailing.gwt.home.communication.event.statistics.EventStatisticsDTO;
|
||||
import com.sap.sailing.gwt.home.shared.refresh.RefreshableWidget;
|
||||
@@ -29,7 +36,7 @@ public class EventStatisticsBoxPresenter extends AbstractStatisticsBoxPresenter
|
||||
addItemWithCompactFormat(ICON_RAW_GPS_FIX, MSG.numberOfGPSFixes(), statistics.getNumberOfGPSFixes());
|
||||
addItemWithCompactFormat(ICON_WIND_FIX, MSG.numberWindFixes(), statistics.getNumberOfWindFixes());
|
||||
addItemWithCompactFormat(ICON_SUM_MILES, MSG.sailedMiles(), statistics.getTotalDistanceTraveled() == null ? null : statistics.getTotalDistanceTraveled().getSeaMiles());
|
||||
addItemWithCompactFormat(ICON_FASTEST_SAILOR, MSG.fastestSailor() + ": "
|
||||
+ statistics.getCompetitorInfo(), statistics.getCompetitorSpeed());
|
||||
addCompetitorItem(ICON_FASTEST_SAILOR, MSG.fastestSailor(), statistics.getFastestCompetitor());
|
||||
addKnotsItem(ICON_FASTEST_SAILOR, MSG.highestSpeed(), statistics.getFastestCompetitorSpeedInKnots());
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -22,5 +22,7 @@ public class YearStatisticsBoxPresenter extends AbstractStatisticsBoxPresenter {
|
||||
addItemWithCompactFormat(ICON_RAW_GPS_FIX, MSG.numberOfGPSFixes(), statistics.getNumberOfGPSFixes());
|
||||
addItemWithCompactFormat(ICON_WIND_FIX, MSG.numberWindFixes(), statistics.getNumberOfWindFixes());
|
||||
addItemWithCompactFormat(ICON_SUM_MILES, MSG.sailedMiles(), statistics.getDistanceTraveled().getNauticalMiles());
|
||||
addCompetitorItem(ICON_FASTEST_SAILOR, MSG.fastestSailor(), statistics.getFastestCompetitor());
|
||||
addKnotsItem(ICON_FASTEST_SAILOR, MSG.highestSpeed(), statistics.getFastestCompetitorSpeedInKnots());
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -15,10 +15,10 @@ public class EventDatesFormatterUtil {
|
||||
private final static DefaultEventDatesFormatter FORMATTER = GWT.create(DefaultEventDatesFormatter.class);
|
||||
|
||||
public static String formatDateRangeWithYear(Date from, Date to) {
|
||||
return FORMATTER.formatDateRangeWithYear(from, to);
|
||||
return (from == null || to == null) ? "" : FORMATTER.formatDateRangeWithYear(from, to);
|
||||
}
|
||||
|
||||
public static String formatDateRangeWithoutYear(Date from, Date to) {
|
||||
return FORMATTER.formatDateRangeWithoutYear(from, to);
|
||||
return (from == null || to == null) ? "" : FORMATTER.formatDateRangeWithoutYear(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
+62
-46
@@ -170,9 +170,11 @@ public class RegattaRaceStatesComponent extends AbstractCompositeComponent<Regat
|
||||
@SuppressWarnings("unchecked")
|
||||
private void updateTable(List<RegattaOverviewEntryDTO> newEntries) {
|
||||
allEntries = newEntries;
|
||||
String lastCourseAreaName = null;
|
||||
String lastRegattaName = null;
|
||||
String lastCourseName = null;
|
||||
String firstCourseAreaName = null;
|
||||
String firstRegattaName = null;
|
||||
String firstCourseName = null;
|
||||
RaceInfoDTO firstCourseRegattaOverviewEntry = null;
|
||||
RegattaOverviewEntryDTO firstRegattaNameEntry = null;
|
||||
String lastBoatClass = null;
|
||||
boolean canRemoveCourseArea = true;
|
||||
boolean canRemoveCourse = true;
|
||||
@@ -180,68 +182,82 @@ public class RegattaRaceStatesComponent extends AbstractCompositeComponent<Regat
|
||||
boolean canRemoveBoatClass = true;
|
||||
boolean canRemoveLastUpdate = true;
|
||||
boolean canRemoveProtestTime = true;
|
||||
boolean isAppending = false;
|
||||
RegattaOverviewEntryDTO firstEntry = null;
|
||||
for (RegattaOverviewEntryDTO entryDTO : allEntries) {
|
||||
if (firstEntry == null) {
|
||||
firstEntry = entryDTO;
|
||||
}
|
||||
if (lastRegattaName == null) {
|
||||
lastRegattaName = entryDTO.regattaDisplayName;
|
||||
} else if (canRemoveRegatta && !lastRegattaName.equals(entryDTO.regattaDisplayName)) {
|
||||
canRemoveRegatta = false;
|
||||
}
|
||||
if (canRemoveLastUpdate && timePassedInSeconds(entryDTO.raceInfo.lastUpdateTime) <= HIDE_COL_TIME_THRESHOLD) {
|
||||
|
||||
boolean first = true;
|
||||
for (RegattaOverviewEntryDTO loopEntryDTO : allEntries) {
|
||||
final RaceInfoDTO loopRaceInfo = loopEntryDTO.raceInfo;
|
||||
|
||||
if (canRemoveLastUpdate && timePassedInSeconds(loopRaceInfo.lastUpdateTime) <= HIDE_COL_TIME_THRESHOLD) {
|
||||
canRemoveLastUpdate = false;
|
||||
}
|
||||
if (canRemoveProtestTime && entryDTO.raceInfo.protestFinishTime != null
|
||||
&& timePassedInSeconds(entryDTO.raceInfo.protestFinishTime) <= HIDE_COL_TIME_THRESHOLD) {
|
||||
if (canRemoveProtestTime && loopRaceInfo.protestFinishTime != null
|
||||
&& timePassedInSeconds(loopRaceInfo.protestFinishTime) <= HIDE_COL_TIME_THRESHOLD) {
|
||||
canRemoveProtestTime = false;
|
||||
}
|
||||
if (lastCourseAreaName == null) {
|
||||
lastCourseAreaName = entryDTO.courseAreaName;
|
||||
} else if (canRemoveCourseArea && !lastCourseAreaName.equals(entryDTO.courseAreaName)) {
|
||||
canRemoveCourseArea = false;
|
||||
}
|
||||
if (lastCourseName == null) {
|
||||
lastCourseName = entryDTO.raceInfo.lastCourseName;
|
||||
} else if (canRemoveCourse && !lastCourseName.equals(entryDTO.raceInfo.lastCourseName)) {
|
||||
canRemoveCourse = false;
|
||||
}
|
||||
|
||||
if (lastBoatClass == null) {
|
||||
lastBoatClass = entryDTO.boatClassName;
|
||||
} else if (canRemoveBoatClass && !lastBoatClass.equals(entryDTO.boatClassName)) {
|
||||
canRemoveBoatClass = false;
|
||||
if (first) {
|
||||
firstRegattaName = loopEntryDTO.regattaDisplayName;
|
||||
firstRegattaNameEntry = loopEntryDTO;
|
||||
|
||||
firstCourseAreaName = loopEntryDTO.courseAreaName;
|
||||
|
||||
firstCourseName = loopRaceInfo.lastCourseName;
|
||||
firstCourseRegattaOverviewEntry = loopRaceInfo;
|
||||
|
||||
lastBoatClass = loopEntryDTO.boatClassName;
|
||||
} else {
|
||||
if (canRemoveRegatta && !Util.equalsWithNull(firstRegattaName, loopEntryDTO.regattaDisplayName)) {
|
||||
canRemoveRegatta = false;
|
||||
}
|
||||
|
||||
if (canRemoveCourseArea && !Util.equalsWithNull(firstCourseAreaName, loopEntryDTO.courseAreaName)) {
|
||||
canRemoveCourseArea = false;
|
||||
}
|
||||
|
||||
if (canRemoveCourse && !Util.equalsWithNull(firstCourseName, loopRaceInfo.lastCourseName)
|
||||
&& !Util.equalsWithNull(firstCourseRegattaOverviewEntry.lastCourseDesign,
|
||||
loopRaceInfo.lastCourseDesign)) {
|
||||
canRemoveCourse = false;
|
||||
}
|
||||
|
||||
if (canRemoveBoatClass && !Util.equalsWithNull(lastBoatClass, loopEntryDTO.boatClassName)) {
|
||||
canRemoveBoatClass = false;
|
||||
}
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
final RegattaOverviewEntryDTO entryForRepeatedInfos = firstEntry;
|
||||
// final RegattaOverviewEntryDTO entryForRepeatedInfos = firstEntry;
|
||||
repeatedInfoLabel.clear();
|
||||
isAppending |= collectRepeatedInfos(stringMessages.regatta(), lastRegattaName, canRemoveRegatta,
|
||||
|
||||
boolean isAppending = false;
|
||||
RegattaOverviewEntryDTO _firstRegattaNameEntry = firstRegattaNameEntry;
|
||||
isAppending |= collectRepeatedInfos(stringMessages.regatta(), firstRegattaName, canRemoveRegatta,
|
||||
repeatedInfoLabel, isAppending, new Command() {
|
||||
@Override
|
||||
public void execute() {
|
||||
Window.open(createRegattaLink(entryForRepeatedInfos), "_blank", "");
|
||||
Window.open(createRegattaLink(_firstRegattaNameEntry), "_blank", "");
|
||||
}
|
||||
});
|
||||
// private boolean collectRepeatedInfos(String label, String info,
|
||||
// boolean canRemove, FlowPanel panel, boolean append,
|
||||
// final Command linkAction) {
|
||||
isAppending |= collectRepeatedInfos(stringMessages.courseArea(), lastCourseAreaName, canRemoveCourseArea,
|
||||
|
||||
isAppending |= collectRepeatedInfos(stringMessages.courseArea(), firstCourseAreaName, canRemoveCourseArea,
|
||||
repeatedInfoLabel,
|
||||
isAppending, null);
|
||||
isAppending |= collectRepeatedInfos(stringMessages.course(), lastCourseName, canRemoveCourse, repeatedInfoLabel,
|
||||
|
||||
final RaceInfoDTO _lastCourseEntry = firstCourseRegattaOverviewEntry;
|
||||
isAppending |= collectRepeatedInfos(stringMessages.course(), firstCourseName, canRemoveCourse,
|
||||
repeatedInfoLabel,
|
||||
isAppending, new Command() {
|
||||
@Override
|
||||
public void execute() {
|
||||
raceCourseClicked(entryForRepeatedInfos);
|
||||
raceCourseClicked(_lastCourseEntry);
|
||||
}
|
||||
});
|
||||
|
||||
isAppending |= collectRepeatedInfos(stringMessages.boatClass(), lastBoatClass, canRemoveBoatClass,
|
||||
repeatedInfoLabel,
|
||||
isAppending, null);
|
||||
isAppending |= collectRepeatedInfos("", "", canRemoveLastUpdate, repeatedInfoLabel, isAppending, null);
|
||||
isAppending |= collectRepeatedInfos("", "", canRemoveProtestTime, repeatedInfoLabel, isAppending, null);
|
||||
|
||||
LinkedList<ColumnSortInfo> sortInfos = new LinkedList<ColumnSortList.ColumnSortInfo>();
|
||||
if (table != null) {
|
||||
ColumnSortList columnSortList = table.getColumnSortList();
|
||||
@@ -551,7 +567,7 @@ public class RegattaRaceStatesComponent extends AbstractCompositeComponent<Regat
|
||||
raceCourseColumn.setFieldUpdater(new FieldUpdater<RegattaOverviewEntryDTO, SafeHtml>() {
|
||||
@Override
|
||||
public void update(int index, RegattaOverviewEntryDTO object, SafeHtml value) {
|
||||
raceCourseClicked(object);
|
||||
raceCourseClicked(object.raceInfo);
|
||||
}
|
||||
});
|
||||
// raceCourseColumn.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
|
||||
@@ -847,10 +863,10 @@ public class RegattaRaceStatesComponent extends AbstractCompositeComponent<Regat
|
||||
return result;
|
||||
}
|
||||
|
||||
private void raceCourseClicked(RegattaOverviewEntryDTO object) {
|
||||
RaceCourseDTO courseDTO = object.raceInfo.lastCourseDesign;
|
||||
private void raceCourseClicked(RaceInfoDTO raceInfo) {
|
||||
RaceCourseDTO courseDTO = raceInfo.lastCourseDesign;
|
||||
if (courseDTO != null && courseDTO.waypoints.size() > 0) {
|
||||
DialogBox courseViewDialogBox = createCourseViewDialogBox(object.raceInfo);
|
||||
DialogBox courseViewDialogBox = createCourseViewDialogBox(raceInfo);
|
||||
courseViewDialogBox.center();
|
||||
courseViewDialogBox.setGlassEnabled(true);
|
||||
courseViewDialogBox.setAnimationEnabled(true);
|
||||
|
||||
+11
-9
@@ -28,16 +28,18 @@ public class EventListDataCalculator implements EventVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(EventBase event, boolean onRemoteServer, URL baseURL) {
|
||||
EventListEventDTO eventDTO = HomeServiceUtil.convertToEventListDTO(event, baseURL, onRemoteServer, service);
|
||||
if (HomeServiceUtil.calculateEventState(event) != EventState.UPCOMING && HomeServiceUtil.isFakeSeries(event)) {
|
||||
String seriesName = HomeServiceUtil.getSeriesName(event);
|
||||
EventListEventDTO latestEvent = lastestEventPerSeries.get(seriesName);
|
||||
if (latestEvent == null || latestEvent.getStartDate().before(eventDTO.getStartDate())) {
|
||||
lastestEventPerSeries.put(seriesName, eventDTO);
|
||||
if (event.getStartDate() != null) {
|
||||
EventListEventDTO eventDTO = HomeServiceUtil.convertToEventListDTO(event, baseURL, onRemoteServer, service);
|
||||
if (HomeServiceUtil.calculateEventState(event) != EventState.UPCOMING && HomeServiceUtil.isFakeSeries(event)) {
|
||||
String seriesName = HomeServiceUtil.getSeriesName(event);
|
||||
EventListEventDTO latestEvent = lastestEventPerSeries.get(seriesName);
|
||||
if (latestEvent == null || latestEvent.getStartDate().before(eventDTO.getStartDate())) {
|
||||
lastestEventPerSeries.put(seriesName, eventDTO);
|
||||
}
|
||||
increaseNumberOfEvents(seriesName);
|
||||
} else {
|
||||
addEventToResults(eventDTO);
|
||||
}
|
||||
increaseNumberOfEvents(seriesName);
|
||||
} else {
|
||||
addEventToResults(eventDTO);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-12
@@ -21,19 +21,20 @@ public class EventStageCandidateCalculator implements EventVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(EventBase event, boolean onRemoteServer, URL baseURL) {
|
||||
EventHolder holder = new EventHolder(event, onRemoteServer, baseURL);
|
||||
if (now.after(event.getStartDate()) && now.before(event.getEndDate())) {
|
||||
featuredEvents.add(new Pair<StageEventType, EventHolder>(StageEventType.RUNNING, holder));
|
||||
} else if (event.getStartDate().after(now) &&
|
||||
event.getStartDate().before(now.plus(Duration.ONE_WEEK.times(4)))) {
|
||||
// This ensures that no events appear on the stage that do not have their leaderboards configured
|
||||
// as the event page only shows a placeholder message in this stage
|
||||
if(HomeServiceUtil.hasRegattaData(event)) {
|
||||
featuredEvents.add(new Pair<StageEventType, EventHolder>(StageEventType.UPCOMING_SOON, holder));
|
||||
final TimePoint startDate = event.getStartDate(), endDate = event.getEndDate();
|
||||
if (startDate != null) {
|
||||
final EventHolder holder = new EventHolder(event, onRemoteServer, baseURL);
|
||||
if (now.after(startDate) && (endDate == null || now.before(endDate))) {
|
||||
featuredEvents.add(new Pair<StageEventType, EventHolder>(StageEventType.RUNNING, holder));
|
||||
} else if (startDate.after(now) && startDate.before(now.plus(Duration.ONE_WEEK.times(4)))) {
|
||||
// This ensures that no events appear on the stage that do not have their leaderboards configured
|
||||
// as the event page only shows a placeholder message in this stage
|
||||
if (HomeServiceUtil.hasRegattaData(event)) {
|
||||
featuredEvents.add(new Pair<StageEventType, EventHolder>(StageEventType.UPCOMING_SOON, holder));
|
||||
}
|
||||
} else if (endDate != null && endDate.before(now) && endDate.after(now.minus(Duration.ONE_YEAR))) {
|
||||
featuredEvents.add(new Pair<StageEventType, EventHolder>(StageEventType.POPULAR, holder));
|
||||
}
|
||||
} else if (event.getEndDate().before(now) &&
|
||||
event.getEndDate().after(now.minus(Duration.ONE_YEAR))) {
|
||||
featuredEvents.add(new Pair<StageEventType, EventHolder>(StageEventType.POPULAR, holder));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-5
@@ -97,11 +97,16 @@ public final class HomeServiceUtil {
|
||||
}
|
||||
|
||||
public static EventState calculateEventState(EventBase event) {
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
if (now.before(event.getStartDate())) {
|
||||
final TimePoint startDate = event.getStartDate();
|
||||
if (startDate == null) {
|
||||
return EventState.PLANNED;
|
||||
}
|
||||
final TimePoint now = MillisecondsTimePoint.now();
|
||||
if (now.before(startDate)) {
|
||||
return event.isPublic() ? EventState.UPCOMING : EventState.PLANNED;
|
||||
}
|
||||
if (now.after(event.getEndDate())) {
|
||||
final TimePoint endDate = event.getEndDate();
|
||||
if (endDate != null && now.after(endDate)) {
|
||||
return EventState.FINISHED;
|
||||
}
|
||||
return EventState.RUNNING;
|
||||
@@ -354,8 +359,8 @@ public final class HomeServiceUtil {
|
||||
|
||||
public static void mapToMetadataDTO(EventBase event, EventMetadataDTO dto, RacingEventService service) {
|
||||
mapToReferenceDTO(event, dto, service);
|
||||
dto.setStartDate(event.getStartDate().asDate());
|
||||
dto.setEndDate(event.getEndDate().asDate());
|
||||
dto.setStartDate(event.getStartDate() == null ? null : event.getStartDate().asDate());
|
||||
dto.setEndDate(event.getEndDate() == null ? null : event.getEndDate().asDate());
|
||||
dto.setState(HomeServiceUtil.calculateEventState(event));
|
||||
dto.setVenue(event.getVenue().getName());
|
||||
if(HomeServiceUtil.isFakeSeries(event)) {
|
||||
|
||||
+3
-2
@@ -24,8 +24,9 @@ public class RecentEventsCalculator implements EventVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(EventBase event, boolean onRemoteServer, URL baseURL) {
|
||||
EventHolder holder = new EventHolder(event, onRemoteServer, baseURL);
|
||||
if (event.getEndDate().before(now) && event.getEndDate().after(now.minus(Duration.ONE_YEAR))) {
|
||||
final EventHolder holder = new EventHolder(event, onRemoteServer, baseURL);
|
||||
final TimePoint endDate = event.getEndDate();
|
||||
if (endDate != null && endDate.before(now) && endDate.after(now.minus(Duration.ONE_YEAR))) {
|
||||
recentEventsOfLast12Month.add(holder);
|
||||
}
|
||||
}
|
||||
|
||||
+42
-20
@@ -82,12 +82,13 @@ import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
|
||||
*/
|
||||
public class WindPanel extends FormPanel implements RegattasDisplayer, WindShower {
|
||||
|
||||
private static final String EXPEDITON_IMPORT_PARAMETER_RACES = "races";
|
||||
private static final String WIND_IMPORT_PARAMETER_RACES = "races";
|
||||
|
||||
private static final String EXPEDITON_IMPORT_PARAMETER_BOAT_ID = "boatId";
|
||||
|
||||
private static final String URL_SAILINGSERVER_EXPEDITION_IMPORT = "/../../sailingserver/expedition-import";
|
||||
private static final String URL_SAILINGSERVER_GRIB_IMPORT = "/../../sailingserver/grib-wind-import";
|
||||
private static final String URL_SAILINGSERVER_NMEA_IMPORT = "/../../sailingserver/nmea-wind-import";
|
||||
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final ErrorReporter errorReporter;
|
||||
@@ -260,8 +261,8 @@ public class WindPanel extends FormPanel implements RegattasDisplayer, WindShowe
|
||||
|
||||
mainPanel.add(createExpeditionWindImportPanel());
|
||||
mainPanel.add(createGribWindImportPanel());
|
||||
mainPanel.add(createNmeaWindImportPanel());
|
||||
mainPanel.add(createIgtimiWindImportPanel(mainPanel));
|
||||
|
||||
}
|
||||
|
||||
private CaptionPanel createIgtimiWindImportPanel(VerticalPanel mainPanel) {
|
||||
@@ -345,7 +346,7 @@ public class WindPanel extends FormPanel implements RegattasDisplayer, WindShowe
|
||||
}
|
||||
/**
|
||||
* Creates a file upload form that works with {@code AbstractWindImportServlet} on the server side. In particular,
|
||||
* the race selection is managed in a hidden field named {@link #EXPEDITON_IMPORT_PARAMETER_RACES}, and the
|
||||
* the race selection is managed in a hidden field named {@link #WIND_IMPORT_PARAMETER_RACES}, and the
|
||||
* {@code upload} element is the MIME multipart file upload form element. The form uses {@code POST} as its method.
|
||||
*
|
||||
* The submit button is initially disabled. Callers can implement their own logic based, e.g., on event handlers they
|
||||
@@ -377,7 +378,7 @@ public class WindPanel extends FormPanel implements RegattasDisplayer, WindShowe
|
||||
if (multi) {
|
||||
fileUpload.getElement().setAttribute("multiple", "multiple");
|
||||
}
|
||||
final Hidden hiddenRacesField = new Hidden(EXPEDITON_IMPORT_PARAMETER_RACES);
|
||||
final Hidden hiddenRacesField = new Hidden(WIND_IMPORT_PARAMETER_RACES);
|
||||
formContentPanel.add(hiddenRacesField);
|
||||
formContentPanel.add(fileUpload);
|
||||
formContentPanel.add(submitButton);
|
||||
@@ -413,21 +414,24 @@ public class WindPanel extends FormPanel implements RegattasDisplayer, WindShowe
|
||||
public void onSubmitComplete(SubmitCompleteEvent event) {
|
||||
importResultPanel.clear();
|
||||
String windImportResultJson = event.getResults();
|
||||
|
||||
WindImportResult windImportResult = WindImportResult.fromJson(windImportResultJson);
|
||||
JsArray<RaceEntry> raceEntries = windImportResult.getRaceEntries();
|
||||
Label resultHeader = new Label(stringMessages.windImport_ResultHeader(String.valueOf(windImportResult.getFirst()),
|
||||
String.valueOf(windImportResult.getLast()), raceEntries.length()));
|
||||
importResultPanel.add(resultHeader);
|
||||
if (windImportResult.getError() != null) {
|
||||
Label errorText = new Label(stringMessages.windImport_ResultError(windImportResult.getError()));
|
||||
importResultPanel.add(errorText);
|
||||
}
|
||||
for (int i = 0; i < raceEntries.length(); i++) {
|
||||
RaceEntry raceEntry = raceEntries.get(i);
|
||||
Label entryText = new Label(stringMessages.windImport_ResultEntry(raceEntry.getRaceName(), raceEntry.getRegattaName(),
|
||||
raceEntry.getCount(), String.valueOf(raceEntry.getFirst()), String.valueOf(raceEntry.getLast())));
|
||||
importResultPanel.add(entryText);
|
||||
try {
|
||||
WindImportResult windImportResult = WindImportResult.fromJson(windImportResultJson);
|
||||
JsArray<RaceEntry> raceEntries = windImportResult.getRaceEntries();
|
||||
Label resultHeader = new Label(stringMessages.windImport_ResultHeader(String.valueOf(windImportResult.getFirst()),
|
||||
String.valueOf(windImportResult.getLast()), raceEntries.length()));
|
||||
importResultPanel.add(resultHeader);
|
||||
if (windImportResult.getError() != null) {
|
||||
Label errorText = new Label(stringMessages.windImport_ResultError(windImportResult.getError()));
|
||||
importResultPanel.add(errorText);
|
||||
}
|
||||
for (int i = 0; i < raceEntries.length(); i++) {
|
||||
RaceEntry raceEntry = raceEntries.get(i);
|
||||
Label entryText = new Label(stringMessages.windImport_ResultEntry(raceEntry.getRaceName(), raceEntry.getRegattaName(),
|
||||
raceEntry.getCount(), String.valueOf(raceEntry.getFirst()), String.valueOf(raceEntry.getLast())));
|
||||
importResultPanel.add(entryText);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errorReporter.reportError(stringMessages.windImport_ResultError(e.getMessage()));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -485,6 +489,25 @@ public class WindPanel extends FormPanel implements RegattasDisplayer, WindShowe
|
||||
return windImportRootPanel;
|
||||
}
|
||||
|
||||
private CaptionPanel createNmeaWindImportPanel() {
|
||||
final WindImportFileUploadForm formAndFileUploadAndSubmitButton = createWindImportFileUploadForm(URL_SAILINGSERVER_NMEA_IMPORT, /* multi */ true);
|
||||
CaptionPanel windImportRootPanel = new CaptionPanel(stringMessages.nmeaWindImport_Title());
|
||||
VerticalPanel windImportContentPanel = new VerticalPanel();
|
||||
windImportRootPanel.add(windImportContentPanel);
|
||||
final FormPanel form = formAndFileUploadAndSubmitButton.getFormPanel();
|
||||
windImportContentPanel.add(form);
|
||||
VerticalPanel formContentPanel = formAndFileUploadAndSubmitButton.getFormContentPanel();
|
||||
HorizontalPanel inputPanel = new HorizontalPanel();
|
||||
formContentPanel.add(inputPanel);
|
||||
final Panel importResultPanel = new VerticalPanel();
|
||||
windImportContentPanel.add(importResultPanel);
|
||||
formAndFileUploadAndSubmitButton.getSubmitButton().setEnabled(true);
|
||||
final FileUpload fileUpload = formAndFileUploadAndSubmitButton.getFileUpload();
|
||||
inputPanel.setSpacing(5);
|
||||
inputPanel.setCellVerticalAlignment(fileUpload, HasVerticalAlignment.ALIGN_MIDDLE);
|
||||
return windImportRootPanel;
|
||||
}
|
||||
|
||||
private CaptionPanel createGribWindImportPanel() {
|
||||
/*
|
||||
* To style the "browse" button of the file upload widget
|
||||
@@ -508,7 +531,6 @@ public class WindPanel extends FormPanel implements RegattasDisplayer, WindShowe
|
||||
return windImportRootPanel;
|
||||
}
|
||||
|
||||
|
||||
private void showWindSettingDialog(RaceDTO race, CoursePositionsDTO course) {
|
||||
AddWindFixDialog windSettingDialog = new AddWindFixDialog(race, course, stringMessages, new DialogCallback<WindDTO>() {
|
||||
@Override
|
||||
|
||||
+2
@@ -1429,6 +1429,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
|
||||
String collapseX(String text);
|
||||
String numberOfGPSFixes();
|
||||
String fastestSailor();
|
||||
String highestSpeed();
|
||||
String numberWindFixes();
|
||||
String sailedMiles();
|
||||
String millionValue(double value);
|
||||
@@ -1800,6 +1801,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
|
||||
String eventRegattaHeaderLegendAudioNo();
|
||||
String set();
|
||||
String gribWindImport_Title();
|
||||
String nmeaWindImport_Title();
|
||||
String angleInDegree();
|
||||
String angleInRadian();
|
||||
String centralAngleInRadian();
|
||||
|
||||
+2
@@ -902,6 +902,7 @@ windImport_ResultHeader=Imported wind from: {0} to: {1}. {2} races affected.
|
||||
windImport_ResultEntry=Race: {0} ({1}) - {2} fixes from: {3} to: {4}
|
||||
windImport_ResultError=Error: {0}
|
||||
gribWindImport_Title=Import wind from GRIB files
|
||||
nmeaWindImport_Title=Import wind from NMEA files
|
||||
showWindSpeedSeriesTooltip=Toggles the visibility of the wind speed for all data sources
|
||||
showWindDirectionSeriesTooltip=Toggles the visibility of the wind direction for all data sources
|
||||
combinedWindSourceTypeTooltip=Combines all other wind sources to one data set
|
||||
@@ -1396,6 +1397,7 @@ collapseX=Collapse {0}
|
||||
|
||||
numberOfGPSFixes=GPS fixes
|
||||
fastestSailor=Fastest
|
||||
highestSpeed=Highest speed
|
||||
numberWindFixes=Wind fixes
|
||||
sailedMiles=Sailed nautical miles
|
||||
millionValue={0,number,#0.0} mil
|
||||
|
||||
+2
@@ -891,6 +891,7 @@ windImport_ResultHeader=Wind wurde importiert von: {0} bis: {1}. {2} Rennen betr
|
||||
windImport_ResultEntry=Rennen: {0} ({1}) - {2} Messwerte von: {3} bis: {4}
|
||||
windImport_ResultError=Fehler: {0}
|
||||
gribWindImport_Title=Wind aus GRIB-Dateien importieren
|
||||
nmeaWindImport_Title=Wind aus NMEA-Dateien importieren
|
||||
showWindSpeedSeriesTooltip=Setzt die Sichtbarkeit der Windgeschwindigkeit aller Datenquellen
|
||||
showWindDirectionSeriesTooltip=Setzt die Sichtbarkeit der Windrichtung aller Datenquellen
|
||||
combinedWindSourceTypeTooltip=Kombiniert alle Datenquellen zu einem Datensatz
|
||||
@@ -1379,6 +1380,7 @@ showAllX=Alle {0} anzeigen
|
||||
collapseX={0} einklappen
|
||||
numberOfGPSFixes=Positionswerte
|
||||
fastestSailor=Schnellster
|
||||
highestSpeed=Höchstgeschwindigkeit
|
||||
numberWindFixes=Windwerte
|
||||
sailedMiles=Erfasste Seemeilen
|
||||
millionValue={0,number,#0.0} Mio
|
||||
|
||||
+1
-1
@@ -135,7 +135,7 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
|
||||
|
||||
final MetaLeaderboardViewer leaderboardViewer = new MetaLeaderboardViewer(null, context,
|
||||
rootComponentLifeCycle, defaultSettings, sailingService, new AsyncActionsExecutor(),
|
||||
timer, null, null, leaderboardGroupName, leaderboardName,
|
||||
timer, null, leaderboardGroupName, leaderboardName,
|
||||
LeaderboardEntryPoint.this, getStringMessages(),
|
||||
getActualChartDetailType(defaultSettings));
|
||||
createUi(leaderboardViewer, defaultSettings, timer, leaderboardContextDefinition);
|
||||
|
||||
+2
-1
@@ -2303,9 +2303,10 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
|
||||
public void onSuccess(LeaderboardDTO result) {
|
||||
LS potentiallyChangedSettings = overrideDefaultsForNamesOfRaceColumns(currentSettings, result);
|
||||
try {
|
||||
final boolean wasEmptyRaceColumnSelection = Util.isEmpty(raceColumnSelection.getSelectedRaceColumns());
|
||||
updateLeaderboard(result);
|
||||
// reapply, as columns might have changed
|
||||
if (!potentiallyChangedSettings.equals(currentSettings)) {
|
||||
if (wasEmptyRaceColumnSelection || !potentiallyChangedSettings.equals(currentSettings)) {
|
||||
updateSettings(potentiallyChangedSettings);
|
||||
}
|
||||
} finally {
|
||||
|
||||
+9
-13
@@ -4,7 +4,6 @@ import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardPanelLifecycle;
|
||||
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardPerspectiveOwnSettings;
|
||||
import com.sap.sailing.gwt.settings.client.leaderboard.MetaLeaderboardPerspectiveLifecycle;
|
||||
@@ -38,12 +37,12 @@ public class MetaLeaderboardViewer extends AbstractLeaderboardViewer<MetaLeaderb
|
||||
MetaLeaderboardPerspectiveLifecycle lifecycle,
|
||||
PerspectiveCompositeSettings<LeaderboardPerspectiveOwnSettings> settings,
|
||||
SailingServiceAsync sailingService, AsyncActionsExecutor asyncActionsExecutor,
|
||||
Timer timer, String preselectedLeaderboardName, RegattaAndRaceIdentifier preselectedRace,
|
||||
Timer timer, String preselectedLeaderboardName,
|
||||
String leaderboardGroupName, String metaLeaderboardName, ErrorReporter errorReporter,
|
||||
StringMessages stringMessages, DetailType chartDetailType) {
|
||||
this(parent, componentContext, lifecycle, settings, new CompetitorSelectionModel(/* hasMultiSelection */true),
|
||||
sailingService, asyncActionsExecutor, timer,
|
||||
preselectedLeaderboardName, preselectedRace, leaderboardGroupName, metaLeaderboardName,
|
||||
preselectedLeaderboardName, leaderboardGroupName, metaLeaderboardName,
|
||||
errorReporter, stringMessages, chartDetailType);
|
||||
}
|
||||
|
||||
@@ -53,25 +52,22 @@ public class MetaLeaderboardViewer extends AbstractLeaderboardViewer<MetaLeaderb
|
||||
PerspectiveCompositeSettings<LeaderboardPerspectiveOwnSettings> settings,
|
||||
CompetitorSelectionModel competitorSelectionModel, SailingServiceAsync sailingService,
|
||||
AsyncActionsExecutor asyncActionsExecutor, Timer timer,
|
||||
String preselectedLeaderboardName, RegattaAndRaceIdentifier preselectedRace, String leaderboardGroupName,
|
||||
String preselectedLeaderboardName, String leaderboardGroupName,
|
||||
String metaLeaderboardName, ErrorReporter errorReporter, StringMessages stringMessages,
|
||||
DetailType chartDetailType) {
|
||||
super(parent, componentContext, lifecycle, settings, competitorSelectionModel, asyncActionsExecutor, timer,
|
||||
stringMessages);
|
||||
|
||||
|
||||
/**
|
||||
* Cleanup one java8 suppliers can be used
|
||||
*/
|
||||
init(new SingleRaceLeaderboardPanel(this, componentContext, sailingService, asyncActionsExecutor,
|
||||
settings.findSettingsByComponentId(LeaderboardPanelLifecycle.ID),
|
||||
preselectedRace != null, preselectedRace, competitorSelectionModel, timer,
|
||||
leaderboardGroupName, metaLeaderboardName, errorReporter, stringMessages,
|
||||
init(new MultiRaceLeaderboardPanel(this, componentContext, sailingService, asyncActionsExecutor,
|
||||
settings.findSettingsByComponentId(LeaderboardPanelLifecycle.ID), /* isEmbedded */ false,
|
||||
competitorSelectionModel, timer,
|
||||
leaderboardGroupName, metaLeaderboardName, errorReporter, stringMessages,
|
||||
settings.getPerspectiveOwnSettings().isShowRaceDetails(), /* competitorSearchTextBox */ null,
|
||||
/* showSelectionCheckbox */ true, /* raceTimesInfoProvider */null,
|
||||
settings.getPerspectiveOwnSettings().isAutoExpandLastRaceColumn(), /* adjustTimerDelay */ true,
|
||||
/* autoApplyTopNFilter */ false,
|
||||
/* showCompetitorFilterStatus */ false, /* enableSyncScroller */ false,new ClassicLeaderboardStyle()));
|
||||
/* showCompetitorFilterStatus */ false, /* enableSyncScroller */ false, new ClassicLeaderboardStyle()));
|
||||
|
||||
final LeaderboardPerspectiveOwnSettings perspectiveSettings = settings.getPerspectiveOwnSettings();
|
||||
final boolean showCharts = perspectiveSettings.isShowCharts();
|
||||
|
||||
|
||||
-1
@@ -56,7 +56,6 @@ public class MultiRaceLeaderboardViewer extends AbstractLeaderboardViewer<Leader
|
||||
final StringMessages stringMessages, DetailType chartDetailType) {
|
||||
super(parent, componentContext, lifecycle, settings, competitorSelectionModel, asyncActionsExecutor, timer,
|
||||
stringMessages);
|
||||
// FIXME: Cleanup with java8 using supplier
|
||||
init(new MultiRaceLeaderboardPanel(this, getComponentContext(), sailingService, asyncActionsExecutor,
|
||||
settings.findSettingsByComponentId(LeaderboardPanelLifecycle.ID), false,
|
||||
competitorSelectionModel, timer, leaderboardGroupName, leaderboardName, errorReporter,
|
||||
|
||||
+36
-5
@@ -25,6 +25,11 @@ public class RaceCourseDTO implements IsSerializable {
|
||||
this(waypoints, getMarksFromWaypoints(waypoints));
|
||||
}
|
||||
|
||||
public RaceCourseDTO(List<WaypointDTO> waypoints, List<MarkDTO> allMarks) {
|
||||
this.waypoints = waypoints;
|
||||
this.allMarks = allMarks;
|
||||
}
|
||||
|
||||
private static List<MarkDTO> getMarksFromWaypoints(List<WaypointDTO> waypoints) {
|
||||
final LinkedHashSet<MarkDTO> marks = new LinkedHashSet<>();
|
||||
for (final WaypointDTO waypoint : waypoints) {
|
||||
@@ -39,11 +44,6 @@ public class RaceCourseDTO implements IsSerializable {
|
||||
return result;
|
||||
}
|
||||
|
||||
public RaceCourseDTO(List<WaypointDTO> waypoints, List<MarkDTO> allMarks) {
|
||||
this.waypoints = waypoints;
|
||||
this.allMarks = allMarks;
|
||||
}
|
||||
|
||||
public List<ControlPointDTO> getControlPoints() {
|
||||
List<ControlPointDTO> controlPoints = new ArrayList<ControlPointDTO>();
|
||||
for (WaypointDTO waypoint : waypoints) {
|
||||
@@ -69,4 +69,35 @@ public class RaceCourseDTO implements IsSerializable {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((allMarks == null) ? 0 : allMarks.hashCode());
|
||||
result = prime * result + ((waypoints == null) ? 0 : waypoints.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
RaceCourseDTO other = (RaceCourseDTO) obj;
|
||||
if (allMarks == null) {
|
||||
if (other.allMarks != null)
|
||||
return false;
|
||||
} else if (!allMarks.equals(other.allMarks))
|
||||
return false;
|
||||
if (waypoints == null) {
|
||||
if (other.waypoints != null)
|
||||
return false;
|
||||
} else if (!waypoints.equals(other.waypoints))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="resources"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>com.sap.sailing.nmeaconnector.test</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,12 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
pluginProject.extensions=false
|
||||
resolve.requirebundle=false
|
||||
@@ -0,0 +1,16 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Test
|
||||
Bundle-SymbolicName: com.sap.sailing.nmeaconnector.test
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Fragment-Host: com.sap.sailing.nmeaconnector
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.junit;bundle-version="4.8.2",
|
||||
com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.common,
|
||||
net.sf.marineapi,
|
||||
com.sap.sse.common,
|
||||
routeconverter;bundle-version="2.8.0"
|
||||
Bundle-ClassPath: .
|
||||
@@ -0,0 +1,5 @@
|
||||
source.. = src/,\
|
||||
resources/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sailing.nmeaconnector.test</artifactId>
|
||||
<packaging>eclipse-test-plugin</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,490 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?><gpx version="1.0" creator="GPSLogger - http://gpslogger.mendhak.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/0" xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd"><time>2012-12-19T10:40:46Z</time><bounds /><trk><trkseg><trkpt lat="54.43041895" lon="10.16849843"><ele>56.70000076293945</ele><course>203.1</course><speed>0.75</speed><hdop>1.6970562</hdop><src>gps</src><sat>10</sat><time>2012-12-19T10:40:46Z</time></trkpt>
|
||||
<trkpt lat="54.43041715" lon="10.16849687"><ele>56.400001525878906</ele><course>340.3</course><speed>0.75</speed><hdop>1.6970562</hdop><src>gps</src><sat>10</sat><time>2012-12-19T10:40:49Z</time></trkpt>
|
||||
<trkpt lat="54.43051734" lon="10.16843823"><ele>52.5</ele><course>331.1</course><speed>4.0</speed><hdop>1.0</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:40:52Z</time></trkpt>
|
||||
<trkpt lat="54.43058934" lon="10.16837067"><ele>51.70000076293945</ele><course>330.5</course><speed>4.0</speed><hdop>1.0</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:40:54Z</time></trkpt>
|
||||
<trkpt lat="54.43065468" lon="10.16830576"><ele>50.099998474121094</ele><course>337.3</course><speed>3.75</speed><hdop>0.7211102</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:40:56Z</time></trkpt>
|
||||
<trkpt lat="54.43071658" lon="10.16831836"><ele>49.20000076293945</ele><course>26.7</course><speed>4.5</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:40:58Z</time></trkpt>
|
||||
<trkpt lat="54.43077917" lon="10.16841689"><ele>48.599998474121094</ele><course>54.1</course><speed>4.75</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:00Z</time></trkpt>
|
||||
<trkpt lat="54.43082095" lon="10.16857047"><ele>48.599998474121094</ele><course>66.9</course><speed>5.75</speed><hdop>0.7211102</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:41:02Z</time></trkpt>
|
||||
<trkpt lat="54.43084608" lon="10.16873799"><ele>46.400001525878906</ele><course>70.3</course><speed>5.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:04Z</time></trkpt>
|
||||
<trkpt lat="54.43085174" lon="10.16889115"><ele>44.5</ele><course>81.3</course><speed>5.0</speed><hdop>0.8485281</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:06Z</time></trkpt>
|
||||
<trkpt lat="54.43088122" lon="10.16900612"><ele>43.900001525878906</ele><course>56.6</course><speed>4.0</speed><hdop>0.8485281</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:08Z</time></trkpt>
|
||||
<trkpt lat="54.43093128" lon="10.16904676"><ele>43.70000076293945</ele><course>2.2</course><speed>2.5</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:10Z</time></trkpt>
|
||||
<trkpt lat="54.43096396" lon="10.16902715"><ele>42.29999923706055</ele><course>345.2</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:12Z</time></trkpt>
|
||||
<trkpt lat="54.43096449" lon="10.16901984"><ele>41.79999923706055</ele><course>345.2</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:14Z</time></trkpt>
|
||||
<trkpt lat="54.43096433" lon="10.16902004"><ele>41.79999923706055</ele><course>345.2</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:16Z</time></trkpt>
|
||||
<trkpt lat="54.43097213" lon="10.1690027"><ele>42.400001525878906</ele><course>313.8</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:18Z</time></trkpt>
|
||||
<trkpt lat="54.43097994" lon="10.16895738"><ele>42.79999923706055</ele><course>278.1</course><speed>1.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:20Z</time></trkpt>
|
||||
<trkpt lat="54.43096834" lon="10.16890725"><ele>42.20000076293945</ele><course>231.9</course><speed>2.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:22Z</time></trkpt>
|
||||
<trkpt lat="54.4309299" lon="10.1688647"><ele>42.20000076293945</ele><course>193.2</course><speed>2.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:24Z</time></trkpt>
|
||||
<trkpt lat="54.43088634" lon="10.16886112"><ele>41.70000076293945</ele><course>151.0</course><speed>2.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:26Z</time></trkpt>
|
||||
<trkpt lat="54.430857" lon="10.16890055"><ele>41.79999923706055</ele><course>116.8</course><speed>1.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:28Z</time></trkpt>
|
||||
<trkpt lat="54.43085167" lon="10.16895548"><ele>42.0</ele><course>87.7</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:30Z</time></trkpt>
|
||||
<trkpt lat="54.43085143" lon="10.16898998"><ele>42.099998474121094</ele><course>86.6</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:32Z</time></trkpt>
|
||||
<trkpt lat="54.43085354" lon="10.16899234"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:34Z</time></trkpt>
|
||||
<trkpt lat="54.43085325" lon="10.16899315"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:36Z</time></trkpt>
|
||||
<trkpt lat="54.43085584" lon="10.16899607"><ele>41.79999923706055</ele><course>86.6</course><speed>0.0</speed><hdop>0.8944272</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:38Z</time></trkpt>
|
||||
<trkpt lat="54.43085739" lon="10.16900078"><ele>41.900001525878906</ele><course>86.6</course><speed>0.0</speed><hdop>0.8944272</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:40Z</time></trkpt>
|
||||
<trkpt lat="54.43085794" lon="10.16900229"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.8944272</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:42Z</time></trkpt>
|
||||
<trkpt lat="54.43085825" lon="10.16900311"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.8944272</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:44Z</time></trkpt>
|
||||
<trkpt lat="54.43085823" lon="10.16900318"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:46Z</time></trkpt>
|
||||
<trkpt lat="54.43085822" lon="10.16900323"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:41:48Z</time></trkpt>
|
||||
<trkpt lat="54.43085824" lon="10.16900325"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:41:50Z</time></trkpt>
|
||||
<trkpt lat="54.43085823" lon="10.16900326"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:41:52Z</time></trkpt>
|
||||
<trkpt lat="54.43085823" lon="10.16900326"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:41:54Z</time></trkpt>
|
||||
<trkpt lat="54.43085822" lon="10.16900326"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:41:56Z</time></trkpt>
|
||||
<trkpt lat="54.43085828" lon="10.1690032"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:41:58Z</time></trkpt>
|
||||
<trkpt lat="54.4308585" lon="10.16900302"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:42:00Z</time></trkpt>
|
||||
<trkpt lat="54.4308586" lon="10.16900292"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:42:02Z</time></trkpt>
|
||||
<trkpt lat="54.43085863" lon="10.16900288"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:42:04Z</time></trkpt>
|
||||
<trkpt lat="54.43085857" lon="10.16900291"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:42:06Z</time></trkpt>
|
||||
<trkpt lat="54.43085858" lon="10.16900289"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:08Z</time></trkpt>
|
||||
<trkpt lat="54.43085856" lon="10.16900288"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:42:10Z</time></trkpt>
|
||||
<trkpt lat="54.43085856" lon="10.1690029"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:42:12Z</time></trkpt>
|
||||
<trkpt lat="54.43085857" lon="10.16900289"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:42:14Z</time></trkpt>
|
||||
<trkpt lat="54.43085861" lon="10.16900285"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:42:16Z</time></trkpt>
|
||||
<trkpt lat="54.4308586" lon="10.16900282"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:42:18Z</time></trkpt>
|
||||
<trkpt lat="54.43085863" lon="10.16900278"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:42:20Z</time></trkpt>
|
||||
<trkpt lat="54.43085864" lon="10.16900278"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:42:22Z</time></trkpt>
|
||||
<trkpt lat="54.43085866" lon="10.16900278"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:42:24Z</time></trkpt>
|
||||
<trkpt lat="54.43085866" lon="10.16900279"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:26Z</time></trkpt>
|
||||
<trkpt lat="54.43085864" lon="10.16900276"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:28Z</time></trkpt>
|
||||
<trkpt lat="54.43085861" lon="10.16900272"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:30Z</time></trkpt>
|
||||
<trkpt lat="54.43085859" lon="10.1690027"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:32Z</time></trkpt>
|
||||
<trkpt lat="54.43085856" lon="10.16900269"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:34Z</time></trkpt>
|
||||
<trkpt lat="54.43085837" lon="10.16900276"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>7</sat><time>2012-12-19T10:42:41Z</time></trkpt>
|
||||
<trkpt lat="54.43085837" lon="10.16900276"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:43Z</time></trkpt>
|
||||
<trkpt lat="54.43085836" lon="10.16900276"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:45Z</time></trkpt>
|
||||
<trkpt lat="54.43085832" lon="10.16900281"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:48Z</time></trkpt>
|
||||
<trkpt lat="54.4308583" lon="10.16900284"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:50Z</time></trkpt>
|
||||
<trkpt lat="54.43085831" lon="10.16900285"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:52Z</time></trkpt>
|
||||
<trkpt lat="54.4308583" lon="10.16900283"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:54Z</time></trkpt>
|
||||
<trkpt lat="54.43085831" lon="10.16900278"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:57Z</time></trkpt>
|
||||
<trkpt lat="54.43085831" lon="10.16900277"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:42:59Z</time></trkpt>
|
||||
<trkpt lat="54.43085833" lon="10.1690028"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:01Z</time></trkpt>
|
||||
<trkpt lat="54.43085835" lon="10.1690028"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:43:03Z</time></trkpt>
|
||||
<trkpt lat="54.43085837" lon="10.16900279"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:05Z</time></trkpt>
|
||||
<trkpt lat="54.43085839" lon="10.1690028"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:43:07Z</time></trkpt>
|
||||
<trkpt lat="54.4308584" lon="10.16900281"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:09Z</time></trkpt>
|
||||
<trkpt lat="54.4308584" lon="10.16900283"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:11Z</time></trkpt>
|
||||
<trkpt lat="54.43085835" lon="10.16900285"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:14Z</time></trkpt>
|
||||
<trkpt lat="54.43085832" lon="10.16900284"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:16Z</time></trkpt>
|
||||
<trkpt lat="54.43085829" lon="10.16900281"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:18Z</time></trkpt>
|
||||
<trkpt lat="54.43085828" lon="10.16900278"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:20Z</time></trkpt>
|
||||
<trkpt lat="54.43085825" lon="10.16900276"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:43:22Z</time></trkpt>
|
||||
<trkpt lat="54.43085824" lon="10.16900275"><ele>42.20000076293945</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:43:24Z</time></trkpt>
|
||||
<trkpt lat="54.43085822" lon="10.16900275"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:43:26Z</time></trkpt>
|
||||
<trkpt lat="54.4308582" lon="10.16900274"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:43:28Z</time></trkpt>
|
||||
<trkpt lat="54.43085817" lon="10.16900275"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:43:30Z</time></trkpt>
|
||||
<trkpt lat="54.43085812" lon="10.16900271"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>6</sat><time>2012-12-19T10:43:37Z</time></trkpt>
|
||||
<trkpt lat="54.4308581" lon="10.16900269"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:39Z</time></trkpt>
|
||||
<trkpt lat="54.4308581" lon="10.16900272"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:41Z</time></trkpt>
|
||||
<trkpt lat="54.43085809" lon="10.16900271"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:43Z</time></trkpt>
|
||||
<trkpt lat="54.43085809" lon="10.1690027"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:45Z</time></trkpt>
|
||||
<trkpt lat="54.43085806" lon="10.16900276"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>8</sat><time>2012-12-19T10:43:53Z</time></trkpt>
|
||||
<trkpt lat="54.43085807" lon="10.16900275"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:55Z</time></trkpt>
|
||||
<trkpt lat="54.43085808" lon="10.16900274"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:57Z</time></trkpt>
|
||||
<trkpt lat="54.43085807" lon="10.16900272"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:43:59Z</time></trkpt>
|
||||
<trkpt lat="54.43085807" lon="10.16900267"><ele>42.099998474121094</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:02Z</time></trkpt>
|
||||
<trkpt lat="54.43084639" lon="10.16899943"><ele>42.29999923706055</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>8</sat><time>2012-12-19T10:44:09Z</time></trkpt>
|
||||
<trkpt lat="54.43083804" lon="10.16900454"><ele>42.5</ele><course>86.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:44:11Z</time></trkpt>
|
||||
<trkpt lat="54.43084033" lon="10.16901537"><ele>42.099998474121094</ele><course>45.6</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:44:14Z</time></trkpt>
|
||||
<trkpt lat="54.43087298" lon="10.1690397"><ele>41.79999923706055</ele><course>7.6</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:17Z</time></trkpt>
|
||||
<trkpt lat="54.43090052" lon="10.16904274"><ele>41.70000076293945</ele><course>357.5</course><speed>1.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:19Z</time></trkpt>
|
||||
<trkpt lat="54.43096382" lon="10.16904279"><ele>41.5</ele><course>0.0</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>4</sat><time>2012-12-19T10:44:27Z</time></trkpt>
|
||||
<trkpt lat="54.43095837" lon="10.16904628"><ele>41.5</ele><course>0.0</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:29Z</time></trkpt>
|
||||
<trkpt lat="54.43095725" lon="10.16904903"><ele>41.400001525878906</ele><course>0.0</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:31Z</time></trkpt>
|
||||
<trkpt lat="54.43095709" lon="10.16905039"><ele>41.29999923706055</ele><course>0.0</course><speed>0.0</speed><hdop>1.3416407</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:33Z</time></trkpt>
|
||||
<trkpt lat="54.43095747" lon="10.16904764"><ele>41.400001525878906</ele><course>0.0</course><speed>0.0</speed><hdop>2.529822</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:42Z</time></trkpt>
|
||||
<trkpt lat="54.43095723" lon="10.16904737"><ele>41.400001525878906</ele><course>0.0</course><speed>0.0</speed><hdop>2.529822</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:44Z</time></trkpt>
|
||||
<trkpt lat="54.43095724" lon="10.16904735"><ele>41.400001525878906</ele><course>0.0</course><speed>0.0</speed><hdop>3.2984843</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:46Z</time></trkpt>
|
||||
<trkpt lat="54.43095498" lon="10.16904398"><ele>41.79999923706055</ele><course>0.0</course><speed>0.0</speed><hdop>1.3416407</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:48Z</time></trkpt>
|
||||
<trkpt lat="54.43095496" lon="10.16904392"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.8944272</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:50Z</time></trkpt>
|
||||
<trkpt lat="54.43095495" lon="10.16904388"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:52Z</time></trkpt>
|
||||
<trkpt lat="54.43095493" lon="10.16904384"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:54Z</time></trkpt>
|
||||
<trkpt lat="54.43095492" lon="10.16904379"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:57Z</time></trkpt>
|
||||
<trkpt lat="54.43095493" lon="10.16904378"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:44:59Z</time></trkpt>
|
||||
<trkpt lat="54.43095494" lon="10.16904375"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:01Z</time></trkpt>
|
||||
<trkpt lat="54.43095493" lon="10.16904372"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:03Z</time></trkpt>
|
||||
<trkpt lat="54.43095493" lon="10.16904369"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:05Z</time></trkpt>
|
||||
<trkpt lat="54.43095493" lon="10.16904367"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:07Z</time></trkpt>
|
||||
<trkpt lat="54.43095493" lon="10.16904366"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:09Z</time></trkpt>
|
||||
<trkpt lat="54.43095493" lon="10.16904364"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:11Z</time></trkpt>
|
||||
<trkpt lat="54.43095488" lon="10.16904361"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>6</sat><time>2012-12-19T10:45:18Z</time></trkpt>
|
||||
<trkpt lat="54.43095486" lon="10.16904359"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:45:20Z</time></trkpt>
|
||||
<trkpt lat="54.43095486" lon="10.16904357"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:45:22Z</time></trkpt>
|
||||
<trkpt lat="54.43095487" lon="10.16904355"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:45:24Z</time></trkpt>
|
||||
<trkpt lat="54.43095487" lon="10.16904352"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:26Z</time></trkpt>
|
||||
<trkpt lat="54.43095487" lon="10.16904349"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:28Z</time></trkpt>
|
||||
<trkpt lat="54.43095488" lon="10.16904346"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:30Z</time></trkpt>
|
||||
<trkpt lat="54.43095489" lon="10.16904345"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:32Z</time></trkpt>
|
||||
<trkpt lat="54.43095489" lon="10.16904345"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:34Z</time></trkpt>
|
||||
<trkpt lat="54.43095488" lon="10.16904343"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:36Z</time></trkpt>
|
||||
<trkpt lat="54.43095489" lon="10.16904341"><ele>41.70000076293945</ele><course>0.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:38Z</time></trkpt>
|
||||
<trkpt lat="54.43097629" lon="10.16903671"><ele>41.70000076293945</ele><course>351.4</course><speed>3.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:40Z</time></trkpt>
|
||||
<trkpt lat="54.43110353" lon="10.16900955"><ele>42.0</ele><course>350.9</course><speed>6.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:43Z</time></trkpt>
|
||||
<trkpt lat="54.4312265" lon="10.16897948"><ele>42.5</ele><course>351.1</course><speed>7.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:45Z</time></trkpt>
|
||||
<trkpt lat="54.43136299" lon="10.16894798"><ele>42.79999923706055</ele><course>351.8</course><speed>8.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:47Z</time></trkpt>
|
||||
<trkpt lat="54.43150214" lon="10.16890568"><ele>42.599998474121094</ele><course>352.0</course><speed>7.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:49Z</time></trkpt>
|
||||
<trkpt lat="54.43163351" lon="10.16887174"><ele>42.599998474121094</ele><course>351.9</course><speed>7.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:51Z</time></trkpt>
|
||||
<trkpt lat="54.43176213" lon="10.16884066"><ele>42.70000076293945</ele><course>351.9</course><speed>7.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:53Z</time></trkpt>
|
||||
<trkpt lat="54.43189147" lon="10.16880859"><ele>42.79999923706055</ele><course>352.1</course><speed>7.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:55Z</time></trkpt>
|
||||
<trkpt lat="54.43202266" lon="10.16878099"><ele>42.79999923706055</ele><course>352.2</course><speed>7.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:45:57Z</time></trkpt>
|
||||
<trkpt lat="54.43235573" lon="10.16869785"><ele>42.900001525878906</ele><course>352.1</course><speed>7.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:02Z</time></trkpt>
|
||||
<trkpt lat="54.43256193" lon="10.1686463"><ele>42.599998474121094</ele><course>352.4</course><speed>7.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:05Z</time></trkpt>
|
||||
<trkpt lat="54.43268055" lon="10.16862129"><ele>42.599998474121094</ele><course>351.8</course><speed>5.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:07Z</time></trkpt>
|
||||
<trkpt lat="54.43275984" lon="10.16857723"><ele>42.29999923706055</ele><course>327.3</course><speed>3.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:09Z</time></trkpt>
|
||||
<trkpt lat="54.43280069" lon="10.16851076"><ele>41.79999923706055</ele><course>307.5</course><speed>3.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:11Z</time></trkpt>
|
||||
<trkpt lat="54.43279677" lon="10.16842614"><ele>41.70000076293945</ele><course>253.7</course><speed>2.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:13Z</time></trkpt>
|
||||
<trkpt lat="54.43278766" lon="10.16836186"><ele>41.5</ele><course>244.4</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:15Z</time></trkpt>
|
||||
<trkpt lat="54.43278498" lon="10.16834764"><ele>41.099998474121094</ele><course>244.4</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:17Z</time></trkpt>
|
||||
<trkpt lat="54.43278473" lon="10.16835739"><ele>41.20000076293945</ele><course>84.5</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:20Z</time></trkpt>
|
||||
<trkpt lat="54.43278689" lon="10.16838992"><ele>41.0</ele><course>73.0</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:22Z</time></trkpt>
|
||||
<trkpt lat="54.43279503" lon="10.16840934"><ele>41.099998474121094</ele><course>46.2</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:24Z</time></trkpt>
|
||||
<trkpt lat="54.43280387" lon="10.16842366"><ele>41.0</ele><course>37.8</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:46:26Z</time></trkpt>
|
||||
<trkpt lat="54.43280834" lon="10.16842443"><ele>41.099998474121094</ele><course>37.8</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:46:28Z</time></trkpt>
|
||||
<trkpt lat="54.43280795" lon="10.16842484"><ele>41.20000076293945</ele><course>37.8</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:30Z</time></trkpt>
|
||||
<trkpt lat="54.43279374" lon="10.16845205"><ele>41.099998474121094</ele><course>127.3</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:32Z</time></trkpt>
|
||||
<trkpt lat="54.43279493" lon="10.16854055"><ele>41.099998474121094</ele><course>74.2</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:35Z</time></trkpt>
|
||||
<trkpt lat="54.43277704" lon="10.16859865"><ele>40.900001525878906</ele><course>146.8</course><speed>1.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:38Z</time></trkpt>
|
||||
<trkpt lat="54.43273573" lon="10.16861124"><ele>40.29999923706055</ele><course>183.9</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:41Z</time></trkpt>
|
||||
<trkpt lat="54.43272944" lon="10.16860831"><ele>40.29999923706055</ele><course>183.9</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:43Z</time></trkpt>
|
||||
<trkpt lat="54.43274835" lon="10.16860513"><ele>40.20000076293945</ele><course>355.6</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:46:45Z</time></trkpt>
|
||||
<trkpt lat="54.4327612" lon="10.16860165"><ele>40.29999923706055</ele><course>357.2</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:46:47Z</time></trkpt>
|
||||
<trkpt lat="54.43276081" lon="10.16859911"><ele>40.400001525878906</ele><course>357.2</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:49Z</time></trkpt>
|
||||
<trkpt lat="54.43276066" lon="10.16859796"><ele>40.5</ele><course>357.2</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:51Z</time></trkpt>
|
||||
<trkpt lat="54.43276019" lon="10.16859656"><ele>40.5</ele><course>357.2</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:53Z</time></trkpt>
|
||||
<trkpt lat="54.43276014" lon="10.1685954"><ele>40.5</ele><course>357.2</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:46:55Z</time></trkpt>
|
||||
<trkpt lat="54.43275995" lon="10.16859492"><ele>40.5</ele><course>357.2</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:46:57Z</time></trkpt>
|
||||
<trkpt lat="54.43275989" lon="10.16859467"><ele>40.5</ele><course>357.2</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:46:59Z</time></trkpt>
|
||||
<trkpt lat="54.43275988" lon="10.16859465"><ele>40.5</ele><course>357.2</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:01Z</time></trkpt>
|
||||
<trkpt lat="54.43275983" lon="10.16859466"><ele>40.5</ele><course>357.2</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:03Z</time></trkpt>
|
||||
<trkpt lat="54.43259415" lon="10.16862721"><ele>40.5</ele><course>173.3</course><speed>5.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>7</sat><time>2012-12-19T10:47:10Z</time></trkpt>
|
||||
<trkpt lat="54.43246312" lon="10.16866582"><ele>40.20000076293945</ele><course>172.2</course><speed>7.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:12Z</time></trkpt>
|
||||
<trkpt lat="54.43232389" lon="10.16869694"><ele>40.29999923706055</ele><course>171.6</course><speed>8.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:14Z</time></trkpt>
|
||||
<trkpt lat="54.43217478" lon="10.16873405"><ele>40.29999923706055</ele><course>171.4</course><speed>8.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:16Z</time></trkpt>
|
||||
<trkpt lat="54.4320271" lon="10.1687714"><ele>39.900001525878906</ele><course>171.8</course><speed>8.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:18Z</time></trkpt>
|
||||
<trkpt lat="54.43188236" lon="10.16880774"><ele>40.0</ele><course>172.0</course><speed>8.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:20Z</time></trkpt>
|
||||
<trkpt lat="54.43135175" lon="10.16893504"><ele>40.20000076293945</ele><course>171.5</course><speed>8.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>8</sat><time>2012-12-19T10:47:27Z</time></trkpt>
|
||||
<trkpt lat="54.43120703" lon="10.1689722"><ele>39.900001525878906</ele><course>171.3</course><speed>8.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:47:29Z</time></trkpt>
|
||||
<trkpt lat="54.43107207" lon="10.16901409"><ele>39.70000076293945</ele><course>171.6</course><speed>8.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:31Z</time></trkpt>
|
||||
<trkpt lat="54.430928" lon="10.16904807"><ele>39.900001525878906</ele><course>172.1</course><speed>8.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:33Z</time></trkpt>
|
||||
<trkpt lat="54.43078781" lon="10.16907721"><ele>40.0</ele><course>171.3</course><speed>7.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:35Z</time></trkpt>
|
||||
<trkpt lat="54.43062383" lon="10.16912503"><ele>41.20000076293945</ele><course>170.3</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>6</sat><time>2012-12-19T10:47:43Z</time></trkpt>
|
||||
<trkpt lat="54.43063151" lon="10.16913212"><ele>40.70000076293945</ele><course>170.3</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:45Z</time></trkpt>
|
||||
<trkpt lat="54.43063239" lon="10.16913238"><ele>40.79999923706055</ele><course>170.3</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:47Z</time></trkpt>
|
||||
<trkpt lat="54.4306132" lon="10.16912534"><ele>41.20000076293945</ele><course>200.0</course><speed>2.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:49Z</time></trkpt>
|
||||
<trkpt lat="54.43057387" lon="10.16908"><ele>41.599998474121094</ele><course>216.8</course><speed>3.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:51Z</time></trkpt>
|
||||
<trkpt lat="54.43052683" lon="10.16905874"><ele>41.599998474121094</ele><course>156.2</course><speed>2.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:53Z</time></trkpt>
|
||||
<trkpt lat="54.43050702" lon="10.16916153"><ele>40.900001525878906</ele><course>64.2</course><speed>2.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:56Z</time></trkpt>
|
||||
<trkpt lat="54.43054238" lon="10.16920719"><ele>40.79999923706055</ele><course>4.2</course><speed>2.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:47:58Z</time></trkpt>
|
||||
<trkpt lat="54.43058343" lon="10.16918601"><ele>40.20000076293945</ele><course>327.6</course><speed>2.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:00Z</time></trkpt>
|
||||
<trkpt lat="54.43060387" lon="10.16915942"><ele>40.0</ele><course>337.9</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:02Z</time></trkpt>
|
||||
<trkpt lat="54.43061203" lon="10.16915529"><ele>39.900001525878906</ele><course>337.9</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:04Z</time></trkpt>
|
||||
<trkpt lat="54.43061942" lon="10.16915049"><ele>39.900001525878906</ele><course>337.9</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:06Z</time></trkpt>
|
||||
<trkpt lat="54.43063369" lon="10.16914315"><ele>39.20000076293945</ele><course>352.2</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:08Z</time></trkpt>
|
||||
<trkpt lat="54.43068829" lon="10.16912844"><ele>39.29999923706055</ele><course>347.9</course><speed>5.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:11Z</time></trkpt>
|
||||
<trkpt lat="54.43084109" lon="10.16907817"><ele>39.20000076293945</ele><course>349.7</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:13Z</time></trkpt>
|
||||
<trkpt lat="54.43103454" lon="10.16902536"><ele>39.29999923706055</ele><course>350.8</course><speed>11.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:15Z</time></trkpt>
|
||||
<trkpt lat="54.43123519" lon="10.16897075"><ele>39.20000076293945</ele><course>351.1</course><speed>11.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:17Z</time></trkpt>
|
||||
<trkpt lat="54.43153299" lon="10.16889721"><ele>39.20000076293945</ele><course>351.3</course><speed>11.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:20Z</time></trkpt>
|
||||
<trkpt lat="54.43182139" lon="10.16882499"><ele>39.20000076293945</ele><course>351.7</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:23Z</time></trkpt>
|
||||
<trkpt lat="54.43252182" lon="10.1686609"><ele>39.70000076293945</ele><course>352.3</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>9</sat><time>2012-12-19T10:48:30Z</time></trkpt>
|
||||
<trkpt lat="54.43267304" lon="10.16862423"><ele>39.79999923706055</ele><course>352.3</course><speed>6.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:48:32Z</time></trkpt>
|
||||
<trkpt lat="54.43275593" lon="10.16858829"><ele>39.900001525878906</ele><course>327.5</course><speed>3.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:34Z</time></trkpt>
|
||||
<trkpt lat="54.43279684" lon="10.16850877"><ele>40.0</ele><course>284.6</course><speed>3.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:36Z</time></trkpt>
|
||||
<trkpt lat="54.43278935" lon="10.16841764"><ele>40.70000076293945</ele><course>233.9</course><speed>2.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:38Z</time></trkpt>
|
||||
<trkpt lat="54.43277503" lon="10.16840132"><ele>40.29999923706055</ele><course>225.2</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:40Z</time></trkpt>
|
||||
<trkpt lat="54.432777" lon="10.16841027"><ele>40.400001525878906</ele><course>72.9</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:42Z</time></trkpt>
|
||||
<trkpt lat="54.43278491" lon="10.16843576"><ele>40.400001525878906</ele><course>45.7</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:44Z</time></trkpt>
|
||||
<trkpt lat="54.43279135" lon="10.16844885"><ele>40.400001525878906</ele><course>36.6</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:46Z</time></trkpt>
|
||||
<trkpt lat="54.43279623" lon="10.16844986"><ele>40.79999923706055</ele><course>36.6</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:48Z</time></trkpt>
|
||||
<trkpt lat="54.43278423" lon="10.16846145"><ele>41.099998474121094</ele><course>136.1</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:48:50Z</time></trkpt>
|
||||
<trkpt lat="54.43270545" lon="10.16860144"><ele>39.900001525878906</ele><course>174.5</course><speed>1.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>8</sat><time>2012-12-19T10:48:58Z</time></trkpt>
|
||||
<trkpt lat="54.43272947" lon="10.16859944"><ele>39.79999923706055</ele><course>350.7</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>10</sat><time>2012-12-19T10:49:00Z</time></trkpt>
|
||||
<trkpt lat="54.43275714" lon="10.16860063"><ele>39.900001525878906</ele><course>359.3</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:49:02Z</time></trkpt>
|
||||
<trkpt lat="54.43277324" lon="10.16859357"><ele>40.0</ele><course>356.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>6</sat><time>2012-12-19T10:49:10Z</time></trkpt>
|
||||
<trkpt lat="54.43277326" lon="10.16859184"><ele>40.0</ele><course>356.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:49:12Z</time></trkpt>
|
||||
<trkpt lat="54.432773" lon="10.16859145"><ele>40.099998474121094</ele><course>356.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:49:14Z</time></trkpt>
|
||||
<trkpt lat="54.43277281" lon="10.16859176"><ele>40.0</ele><course>356.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:49:16Z</time></trkpt>
|
||||
<trkpt lat="54.43277231" lon="10.16859228"><ele>40.099998474121094</ele><course>356.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:49:18Z</time></trkpt>
|
||||
<trkpt lat="54.43277225" lon="10.16859246"><ele>40.0</ele><course>356.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:49:20Z</time></trkpt>
|
||||
<trkpt lat="54.43277226" lon="10.16859244"><ele>40.0</ele><course>356.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:49:22Z</time></trkpt>
|
||||
<trkpt lat="54.43277225" lon="10.16859246"><ele>40.0</ele><course>356.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:49:24Z</time></trkpt>
|
||||
<trkpt lat="54.43277225" lon="10.16859251"><ele>40.0</ele><course>356.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>10</sat><time>2012-12-19T10:49:31Z</time></trkpt>
|
||||
<trkpt lat="54.43277224" lon="10.16859252"><ele>40.0</ele><course>356.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:49:34Z</time></trkpt>
|
||||
<trkpt lat="54.4306172" lon="10.1691843"><ele>24.700000762939453</ele><course>168.7</course><speed>11.5</speed><hdop>2.0</hdop><src>gps</src><sat>6</sat><time>2012-12-19T10:50:10Z</time></trkpt>
|
||||
<trkpt lat="54.43052511" lon="10.16927846"><ele>37.20000076293945</ele><course>142.8</course><speed>5.75</speed><hdop>1.3416407</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:50:12Z</time></trkpt>
|
||||
<trkpt lat="54.43052319" lon="10.16926748"><ele>40.0</ele><course>195.3</course><speed>1.118034</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:50:14Z</time></trkpt>
|
||||
<trkpt lat="54.43054108" lon="10.16921228"><ele>41.20000076293945</ele><course>236.2</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:50:16Z</time></trkpt>
|
||||
<trkpt lat="54.43054004" lon="10.16919875"><ele>39.0</ele><course>236.2</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:50:18Z</time></trkpt>
|
||||
<trkpt lat="54.43060163" lon="10.16916831"><ele>42.599998474121094</ele><course>348.1</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>8</sat><time>2012-12-19T10:50:25Z</time></trkpt>
|
||||
<trkpt lat="54.43059537" lon="10.16916402"><ele>41.20000076293945</ele><course>348.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>4</sat><time>2012-12-19T10:50:32Z</time></trkpt>
|
||||
<trkpt lat="54.43059412" lon="10.16915923"><ele>40.70000076293945</ele><course>348.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:50:34Z</time></trkpt>
|
||||
<trkpt lat="54.43058806" lon="10.16914525"><ele>41.0</ele><course>348.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>4</sat><time>2012-12-19T10:50:42Z</time></trkpt>
|
||||
<trkpt lat="54.43058797" lon="10.16914527"><ele>41.0</ele><course>348.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:50:44Z</time></trkpt>
|
||||
<trkpt lat="54.43058935" lon="10.16914576"><ele>41.0</ele><course>348.1</course><speed>0.0</speed><hdop>1.7888544</hdop><src>gps</src><sat>6</sat><time>2012-12-19T10:51:02Z</time></trkpt>
|
||||
<trkpt lat="54.43068619" lon="10.16913652"><ele>41.099998474121094</ele><course>347.4</course><speed>3.75</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:51:04Z</time></trkpt>
|
||||
<trkpt lat="54.43071539" lon="10.16910724"><ele>38.599998474121094</ele><course>348.0</course><speed>5.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:51:06Z</time></trkpt>
|
||||
<trkpt lat="54.43063439" lon="10.16903059"><ele>40.099998474121094</ele><course>176.7</course><speed>1.0</speed><hdop>1.6970562</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:18Z</time></trkpt>
|
||||
<trkpt lat="54.43058142" lon="10.16911856"><ele>40.400001525878906</ele><course>342.9</course><speed>0.25</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:20Z</time></trkpt>
|
||||
<trkpt lat="54.43065995" lon="10.16914006"><ele>40.5</ele><course>348.0</course><speed>4.5</speed><hdop>1.6970562</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:22Z</time></trkpt>
|
||||
<trkpt lat="54.43076071" lon="10.16910091"><ele>40.599998474121094</ele><course>348.6</course><speed>9.25</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:24Z</time></trkpt>
|
||||
<trkpt lat="54.43093204" lon="10.16904044"><ele>41.5</ele><course>349.6</course><speed>10.25</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:26Z</time></trkpt>
|
||||
<trkpt lat="54.43122113" lon="10.1689527"><ele>41.099998474121094</ele><course>351.5</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:29Z</time></trkpt>
|
||||
<trkpt lat="54.43141688" lon="10.16890985"><ele>40.900001525878906</ele><course>351.8</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:31Z</time></trkpt>
|
||||
<trkpt lat="54.43160814" lon="10.16887291"><ele>40.900001525878906</ele><course>352.0</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:33Z</time></trkpt>
|
||||
<trkpt lat="54.43179799" lon="10.16882999"><ele>41.0</ele><course>352.3</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:35Z</time></trkpt>
|
||||
<trkpt lat="54.43199036" lon="10.16878216"><ele>41.099998474121094</ele><course>352.0</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:37Z</time></trkpt>
|
||||
<trkpt lat="54.43227885" lon="10.16871896"><ele>41.400001525878906</ele><course>352.1</course><speed>10.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:40Z</time></trkpt>
|
||||
<trkpt lat="54.43244356" lon="10.16868361"><ele>41.20000076293945</ele><course>352.8</course><speed>7.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:42Z</time></trkpt>
|
||||
<trkpt lat="54.43253996" lon="10.16867204"><ele>41.20000076293945</ele><course>355.0</course><speed>4.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:44Z</time></trkpt>
|
||||
<trkpt lat="54.43259048" lon="10.168666"><ele>41.29999923706055</ele><course>353.2</course><speed>2.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:46Z</time></trkpt>
|
||||
<trkpt lat="54.43270615" lon="10.16862918"><ele>41.400001525878906</ele><course>345.1</course><speed>2.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>6</sat><time>2012-12-19T10:55:53Z</time></trkpt>
|
||||
<trkpt lat="54.43274805" lon="10.16861734"><ele>40.900001525878906</ele><course>349.4</course><speed>2.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:55Z</time></trkpt>
|
||||
<trkpt lat="54.43278369" lon="10.1685677"><ele>40.599998474121094</ele><course>313.3</course><speed>2.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:55:58Z</time></trkpt>
|
||||
<trkpt lat="54.43280992" lon="10.16850865"><ele>40.0</ele><course>306.3</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:01Z</time></trkpt>
|
||||
<trkpt lat="54.43280142" lon="10.16849173"><ele>40.5</ele><course>306.3</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:03Z</time></trkpt>
|
||||
<trkpt lat="54.43279523" lon="10.16849658"><ele>40.900001525878906</ele><course>306.3</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:05Z</time></trkpt>
|
||||
<trkpt lat="54.43279472" lon="10.16849617"><ele>41.099998474121094</ele><course>306.3</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:07Z</time></trkpt>
|
||||
<trkpt lat="54.43279283" lon="10.16849546"><ele>41.0</ele><course>306.3</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:09Z</time></trkpt>
|
||||
<trkpt lat="54.432793" lon="10.16849452"><ele>41.29999923706055</ele><course>306.3</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:12Z</time></trkpt>
|
||||
<trkpt lat="54.43278981" lon="10.16847729"><ele>41.29999923706055</ele><course>306.3</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:14Z</time></trkpt>
|
||||
<trkpt lat="54.43275907" lon="10.16841823"><ele>41.0</ele><course>197.9</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>1</sat><time>2012-12-19T10:56:21Z</time></trkpt>
|
||||
<trkpt lat="54.43275867" lon="10.16841811"><ele>41.0</ele><course>36.4</course><speed>0.75</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:23Z</time></trkpt>
|
||||
<trkpt lat="54.43278175" lon="10.16844743"><ele>41.20000076293945</ele><course>34.3</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:25Z</time></trkpt>
|
||||
<trkpt lat="54.43277477" lon="10.16845457"><ele>41.20000076293945</ele><course>34.3</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:27Z</time></trkpt>
|
||||
<trkpt lat="54.43276857" lon="10.16846928"><ele>41.70000076293945</ele><course>137.5</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:29Z</time></trkpt>
|
||||
<trkpt lat="54.43275738" lon="10.16850234"><ele>41.599998474121094</ele><course>105.2</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:31Z</time></trkpt>
|
||||
<trkpt lat="54.43275559" lon="10.16854259"><ele>41.70000076293945</ele><course>89.8</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:33Z</time></trkpt>
|
||||
<trkpt lat="54.43275148" lon="10.16856383"><ele>40.79999923706055</ele><course>104.0</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:35Z</time></trkpt>
|
||||
<trkpt lat="54.43274495" lon="10.16858048"><ele>40.70000076293945</ele><course>140.0</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:37Z</time></trkpt>
|
||||
<trkpt lat="54.4327189" lon="10.16859558"><ele>40.599998474121094</ele><course>177.5</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:39Z</time></trkpt>
|
||||
<trkpt lat="54.43270725" lon="10.16859652"><ele>40.400001525878906</ele><course>185.5</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:56:41Z</time></trkpt>
|
||||
<trkpt lat="54.43277063" lon="10.16859882"><ele>40.5</ele><course>9.3</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>5</sat><time>2012-12-19T10:56:49Z</time></trkpt>
|
||||
<trkpt lat="54.43277215" lon="10.16860856"><ele>40.099998474121094</ele><course>18.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:56:51Z</time></trkpt>
|
||||
<trkpt lat="54.43276905" lon="10.16860432"><ele>39.900001525878906</ele><course>18.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:56:53Z</time></trkpt>
|
||||
<trkpt lat="54.43277017" lon="10.16860465"><ele>39.900001525878906</ele><course>18.0</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:56:55Z</time></trkpt>
|
||||
<trkpt lat="54.43240684" lon="10.168697"><ele>39.400001525878906</ele><course>171.8</course><speed>9.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>8</sat><time>2012-12-19T10:57:03Z</time></trkpt>
|
||||
<trkpt lat="54.43211051" lon="10.16878066"><ele>39.29999923706055</ele><course>171.6</course><speed>11.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:06Z</time></trkpt>
|
||||
<trkpt lat="54.431909" lon="10.16882937"><ele>39.20000076293945</ele><course>172.1</course><speed>11.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:08Z</time></trkpt>
|
||||
<trkpt lat="54.43171703" lon="10.16887316"><ele>40.099998474121094</ele><course>171.9</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:10Z</time></trkpt>
|
||||
<trkpt lat="54.43152387" lon="10.16891041"><ele>40.599998474121094</ele><course>172.0</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:12Z</time></trkpt>
|
||||
<trkpt lat="54.43133275" lon="10.16895111"><ele>40.400001525878906</ele><course>172.1</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:14Z</time></trkpt>
|
||||
<trkpt lat="54.4311431" lon="10.1689936"><ele>40.70000076293945</ele><course>171.7</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:16Z</time></trkpt>
|
||||
<trkpt lat="54.43095469" lon="10.1690416"><ele>40.5</ele><course>171.7</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:18Z</time></trkpt>
|
||||
<trkpt lat="54.4305972" lon="10.16907812"><ele>40.20000076293945</ele><course>192.8</course><speed>4.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:23Z</time></trkpt>
|
||||
<trkpt lat="54.43053767" lon="10.16907023"><ele>40.20000076293945</ele><course>155.0</course><speed>2.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:25Z</time></trkpt>
|
||||
<trkpt lat="54.43051954" lon="10.16916176"><ele>40.400001525878906</ele><course>65.0</course><speed>2.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:28Z</time></trkpt>
|
||||
<trkpt lat="54.43054701" lon="10.16920438"><ele>40.79999923706055</ele><course>15.1</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:30Z</time></trkpt>
|
||||
<trkpt lat="54.43054778" lon="10.16920633"><ele>41.29999923706055</ele><course>15.1</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:33Z</time></trkpt>
|
||||
<trkpt lat="54.43053699" lon="10.16918965"><ele>41.400001525878906</ele><course>217.1</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:35Z</time></trkpt>
|
||||
<trkpt lat="54.43052616" lon="10.16917976"><ele>41.29999923706055</ele><course>217.1</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:37Z</time></trkpt>
|
||||
<trkpt lat="54.43053032" lon="10.16917992"><ele>41.20000076293945</ele><course>217.1</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:39Z</time></trkpt>
|
||||
<trkpt lat="54.43056778" lon="10.16915999"><ele>41.0</ele><course>340.6</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:42Z</time></trkpt>
|
||||
<trkpt lat="54.43058656" lon="10.16914156"><ele>40.79999923706055</ele><course>339.8</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:44Z</time></trkpt>
|
||||
<trkpt lat="54.43058398" lon="10.16914639"><ele>40.900001525878906</ele><course>339.8</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:46Z</time></trkpt>
|
||||
<trkpt lat="54.43058342" lon="10.16914877"><ele>41.0</ele><course>339.8</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:48Z</time></trkpt>
|
||||
<trkpt lat="54.43057814" lon="10.16916175"><ele>40.599998474121094</ele><course>339.8</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>5</sat><time>2012-12-19T10:57:55Z</time></trkpt>
|
||||
<trkpt lat="54.43057821" lon="10.16916181"><ele>40.599998474121094</ele><course>339.8</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:57:57Z</time></trkpt>
|
||||
<trkpt lat="54.43057824" lon="10.16916197"><ele>40.599998474121094</ele><course>339.8</course><speed>0.0</speed><hdop>0.8485281</hdop><src>gps</src><sat>6</sat><time>2012-12-19T10:58:05Z</time></trkpt>
|
||||
<trkpt lat="54.43057824" lon="10.16916197"><ele>40.599998474121094</ele><course>339.8</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:07Z</time></trkpt>
|
||||
<trkpt lat="54.43057823" lon="10.16916196"><ele>40.599998474121094</ele><course>339.8</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:09Z</time></trkpt>
|
||||
<trkpt lat="54.43057823" lon="10.16916192"><ele>40.599998474121094</ele><course>339.8</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:11Z</time></trkpt>
|
||||
<trkpt lat="54.43057823" lon="10.16916188"><ele>40.599998474121094</ele><course>339.8</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:13Z</time></trkpt>
|
||||
<trkpt lat="54.4305782" lon="10.1691619"><ele>40.599998474121094</ele><course>339.8</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:15Z</time></trkpt>
|
||||
<trkpt lat="54.43057819" lon="10.16916188"><ele>40.599998474121094</ele><course>339.8</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:17Z</time></trkpt>
|
||||
<trkpt lat="54.43057819" lon="10.16916188"><ele>40.599998474121094</ele><course>339.8</course><speed>0.0</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:19Z</time></trkpt>
|
||||
<trkpt lat="54.4305782" lon="10.16916187"><ele>40.599998474121094</ele><course>339.8</course><speed>0.0</speed><hdop>1.3416407</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:21Z</time></trkpt>
|
||||
<trkpt lat="54.4305782" lon="10.16916189"><ele>40.599998474121094</ele><course>339.8</course><speed>0.0</speed><hdop>1.4422204</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:23Z</time></trkpt>
|
||||
<trkpt lat="54.4305782" lon="10.1691619"><ele>40.599998474121094</ele><course>339.8</course><speed>0.25</speed><hdop>1.4422204</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:26Z</time></trkpt>
|
||||
<trkpt lat="54.43065327" lon="10.16913958"><ele>42.20000076293945</ele><course>344.0</course><speed>4.75</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:28Z</time></trkpt>
|
||||
<trkpt lat="54.43076575" lon="10.1690925"><ele>41.099998474121094</ele><course>344.9</course><speed>7.25</speed><hdop>1.0</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:58:30Z</time></trkpt>
|
||||
<trkpt lat="54.43101094" lon="10.16902712"><ele>38.29999923706055</ele><course>351.6</course><speed>9.5</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:33Z</time></trkpt>
|
||||
<trkpt lat="54.43119097" lon="10.16898797"><ele>39.0</ele><course>351.5</course><speed>10.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:35Z</time></trkpt>
|
||||
<trkpt lat="54.43136935" lon="10.16894085"><ele>40.5</ele><course>351.7</course><speed>10.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:37Z</time></trkpt>
|
||||
<trkpt lat="54.43155057" lon="10.16890451"><ele>41.0</ele><course>352.1</course><speed>10.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:39Z</time></trkpt>
|
||||
<trkpt lat="54.43278529" lon="10.16846199"><ele>37.70000076293945</ele><course>333.4</course><speed>5.0</speed><hdop>1.7888544</hdop><src>gps</src><sat>5</sat><time>2012-12-19T10:58:55Z</time></trkpt>
|
||||
<trkpt lat="54.43278302" lon="10.16844972"><ele>41.20000076293945</ele><course>284.6</course><speed>1.5</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:57Z</time></trkpt>
|
||||
<trkpt lat="54.43278727" lon="10.16843158"><ele>40.400001525878906</ele><course>284.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:58:59Z</time></trkpt>
|
||||
<trkpt lat="54.43279092" lon="10.16843429"><ele>39.0</ele><course>85.8</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:01Z</time></trkpt>
|
||||
<trkpt lat="54.43279582" lon="10.16846366"><ele>39.0</ele><course>66.3</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:03Z</time></trkpt>
|
||||
<trkpt lat="54.4328013" lon="10.16847698"><ele>39.20000076293945</ele><course>66.3</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:05Z</time></trkpt>
|
||||
<trkpt lat="54.43280009" lon="10.16847955"><ele>38.599998474121094</ele><course>66.3</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:07Z</time></trkpt>
|
||||
<trkpt lat="54.43279137" lon="10.1684796"><ele>38.70000076293945</ele><course>66.3</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:09Z</time></trkpt>
|
||||
<trkpt lat="54.43277218" lon="10.16849121"><ele>39.0</ele><course>147.7</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:11Z</time></trkpt>
|
||||
<trkpt lat="54.43278905" lon="10.16849708"><ele>38.599998474121094</ele><course>147.7</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>6</sat><time>2012-12-19T10:59:18Z</time></trkpt>
|
||||
<trkpt lat="54.43279361" lon="10.16850682"><ele>38.29999923706055</ele><course>147.7</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:20Z</time></trkpt>
|
||||
<trkpt lat="54.43278201" lon="10.16855043"><ele>37.70000076293945</ele><course>104.1</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:22Z</time></trkpt>
|
||||
<trkpt lat="54.43276411" lon="10.16859568"><ele>37.900001525878906</ele><course>135.6</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:24Z</time></trkpt>
|
||||
<trkpt lat="54.43274075" lon="10.16861847"><ele>37.599998474121094</ele><course>169.9</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:26Z</time></trkpt>
|
||||
<trkpt lat="54.43271886" lon="10.16861587"><ele>38.29999923706055</ele><course>185.2</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:28Z</time></trkpt>
|
||||
<trkpt lat="54.43271343" lon="10.16861855"><ele>38.20000076293945</ele><course>185.2</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:30Z</time></trkpt>
|
||||
<trkpt lat="54.43273357" lon="10.16861491"><ele>38.099998474121094</ele><course>3.1</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:32Z</time></trkpt>
|
||||
<trkpt lat="54.43275637" lon="10.16860787"><ele>38.400001525878906</ele><course>359.7</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:34Z</time></trkpt>
|
||||
<trkpt lat="54.43276803" lon="10.16860498"><ele>38.5</ele><course>359.7</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:36Z</time></trkpt>
|
||||
<trkpt lat="54.43277054" lon="10.16860702"><ele>39.5</ele><course>359.7</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:39Z</time></trkpt>
|
||||
<trkpt lat="54.43277017" lon="10.16860993"><ele>39.79999923706055</ele><course>359.7</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:41Z</time></trkpt>
|
||||
<trkpt lat="54.4327693" lon="10.16861122"><ele>40.29999923706055</ele><course>359.7</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:43Z</time></trkpt>
|
||||
<trkpt lat="54.4327689" lon="10.16861318"><ele>40.5</ele><course>359.7</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:45Z</time></trkpt>
|
||||
<trkpt lat="54.43276845" lon="10.16861436"><ele>40.70000076293945</ele><course>359.7</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:47Z</time></trkpt>
|
||||
<trkpt lat="54.43276859" lon="10.16861487"><ele>40.79999923706055</ele><course>359.7</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:49Z</time></trkpt>
|
||||
<trkpt lat="54.43276861" lon="10.16861491"><ele>40.79999923706055</ele><course>359.7</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:51Z</time></trkpt>
|
||||
<trkpt lat="54.43276862" lon="10.16861492"><ele>40.79999923706055</ele><course>359.7</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:53Z</time></trkpt>
|
||||
<trkpt lat="54.43276862" lon="10.16861492"><ele>40.79999923706055</ele><course>359.7</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:55Z</time></trkpt>
|
||||
<trkpt lat="54.43276861" lon="10.16861492"><ele>40.79999923706055</ele><course>359.7</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T10:59:57Z</time></trkpt>
|
||||
<trkpt lat="54.43274964" lon="10.1686157"><ele>40.70000076293945</ele><course>171.0</course><speed>3.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T10:59:59Z</time></trkpt>
|
||||
<trkpt lat="54.4325596" lon="10.16865154"><ele>40.400001525878906</ele><course>173.3</course><speed>9.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:02Z</time></trkpt>
|
||||
<trkpt lat="54.4323853" lon="10.16868722"><ele>40.70000076293945</ele><course>172.9</course><speed>10.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:04Z</time></trkpt>
|
||||
<trkpt lat="54.43220118" lon="10.16872275"><ele>40.599998474121094</ele><course>171.7</course><speed>10.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:06Z</time></trkpt>
|
||||
<trkpt lat="54.432014" lon="10.16877518"><ele>40.400001525878906</ele><course>172.2</course><speed>10.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:08Z</time></trkpt>
|
||||
<trkpt lat="54.43182945" lon="10.16881879"><ele>40.400001525878906</ele><course>172.9</course><speed>10.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:10Z</time></trkpt>
|
||||
<trkpt lat="54.4315441" lon="10.16888412"><ele>39.79999923706055</ele><course>170.8</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:13Z</time></trkpt>
|
||||
<trkpt lat="54.43135388" lon="10.16893583"><ele>40.099998474121094</ele><course>171.0</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:15Z</time></trkpt>
|
||||
<trkpt lat="54.4311616" lon="10.16898167"><ele>40.0</ele><course>172.0</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:17Z</time></trkpt>
|
||||
<trkpt lat="54.43096739" lon="10.1690221"><ele>40.099998474121094</ele><course>172.8</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:19Z</time></trkpt>
|
||||
<trkpt lat="54.43077774" lon="10.16905566"><ele>39.70000076293945</ele><course>175.9</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:21Z</time></trkpt>
|
||||
<trkpt lat="54.43061311" lon="10.16906607"><ele>39.79999923706055</ele><course>180.0</course><speed>6.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:23Z</time></trkpt>
|
||||
<trkpt lat="54.43053702" lon="10.16909519"><ele>40.599998474121094</ele><course>143.2</course><speed>3.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:25Z</time></trkpt>
|
||||
<trkpt lat="54.43053809" lon="10.16916912"><ele>40.0</ele><course>65.4</course><speed>2.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:27Z</time></trkpt>
|
||||
<trkpt lat="54.43056289" lon="10.16921317"><ele>39.900001525878906</ele><course>33.3</course><speed>1.3462912</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:29Z</time></trkpt>
|
||||
<trkpt lat="54.43056196" lon="10.16921754"><ele>40.0</ele><course>33.3</course><speed>0.559017</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:31Z</time></trkpt>
|
||||
<trkpt lat="54.43055681" lon="10.16919264"><ele>40.0</ele><course>242.8</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:33Z</time></trkpt>
|
||||
<trkpt lat="54.43053437" lon="10.1691685"><ele>40.29999923706055</ele><course>215.4</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:35Z</time></trkpt>
|
||||
<trkpt lat="54.4305321" lon="10.16916101"><ele>39.79999923706055</ele><course>215.4</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:37Z</time></trkpt>
|
||||
<trkpt lat="54.43057429" lon="10.1691503"><ele>40.599998474121094</ele><course>345.8</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:41Z</time></trkpt>
|
||||
<trkpt lat="54.43058174" lon="10.16914358"><ele>41.29999923706055</ele><course>345.8</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:00:44Z</time></trkpt>
|
||||
<trkpt lat="54.43057884" lon="10.16914588"><ele>41.900001525878906</ele><course>345.8</course><speed>0.0</speed><hdop>2.0</hdop><src>gps</src><sat>5</sat><time>2012-12-19T11:01:03Z</time></trkpt>
|
||||
<trkpt lat="54.43057811" lon="10.16914808"><ele>42.400001525878906</ele><course>345.8</course><speed>0.0</speed><hdop>1.6970562</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:05Z</time></trkpt>
|
||||
<trkpt lat="54.43057725" lon="10.16915055"><ele>42.900001525878906</ele><course>345.8</course><speed>0.0</speed><hdop>1.4422204</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:07Z</time></trkpt>
|
||||
<trkpt lat="54.43057826" lon="10.16915167"><ele>42.900001525878906</ele><course>345.8</course><speed>0.0</speed><hdop>1.4422204</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:09Z</time></trkpt>
|
||||
<trkpt lat="54.4305795" lon="10.16915316"><ele>43.0</ele><course>345.8</course><speed>0.0</speed><hdop>1.4422204</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:11Z</time></trkpt>
|
||||
<trkpt lat="54.43057962" lon="10.16915314"><ele>42.900001525878906</ele><course>345.8</course><speed>0.0</speed><hdop>1.4422204</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:14Z</time></trkpt>
|
||||
<trkpt lat="54.43057955" lon="10.16915308"><ele>43.0</ele><course>345.8</course><speed>0.0</speed><hdop>1.3416407</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:16Z</time></trkpt>
|
||||
<trkpt lat="54.43057951" lon="10.16915304"><ele>43.0</ele><course>345.8</course><speed>0.0</speed><hdop>1.3416407</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:18Z</time></trkpt>
|
||||
<trkpt lat="54.43057948" lon="10.16915305"><ele>43.0</ele><course>345.8</course><speed>0.0</speed><hdop>0.8485281</hdop><src>gps</src><sat>8</sat><time>2012-12-19T11:01:25Z</time></trkpt>
|
||||
<trkpt lat="54.43057946" lon="10.16915304"><ele>43.0</ele><course>345.8</course><speed>0.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:27Z</time></trkpt>
|
||||
<trkpt lat="54.43057947" lon="10.16915302"><ele>43.0</ele><course>345.8</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:29Z</time></trkpt>
|
||||
<trkpt lat="54.43058981" lon="10.16917751"><ele>61.20000076293945</ele><course>345.8</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:31Z</time></trkpt>
|
||||
<trkpt lat="54.43064048" lon="10.16917911"><ele>59.29999923706055</ele><course>347.1</course><speed>3.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:33Z</time></trkpt>
|
||||
<trkpt lat="54.43133425" lon="10.16896403"><ele>51.79999923706055</ele><course>351.3</course><speed>11.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>8</sat><time>2012-12-19T11:01:41Z</time></trkpt>
|
||||
<trkpt lat="54.43152674" lon="10.16891544"><ele>51.5</ele><course>351.9</course><speed>10.75</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:43Z</time></trkpt>
|
||||
<trkpt lat="54.43172641" lon="10.16885122"><ele>50.20000076293945</ele><course>352.1</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:45Z</time></trkpt>
|
||||
<trkpt lat="54.43191932" lon="10.1688012"><ele>49.29999923706055</ele><course>352.1</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:47Z</time></trkpt>
|
||||
<trkpt lat="54.43220643" lon="10.16874243"><ele>48.20000076293945</ele><course>352.0</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:50Z</time></trkpt>
|
||||
<trkpt lat="54.43248952" lon="10.16867042"><ele>47.70000076293945</ele><course>351.3</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:53Z</time></trkpt>
|
||||
<trkpt lat="54.43261463" lon="10.16865407"><ele>47.0</ele><course>352.6</course><speed>5.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:55Z</time></trkpt>
|
||||
<trkpt lat="54.43267959" lon="10.16863804"><ele>46.900001525878906</ele><course>351.9</course><speed>2.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:57Z</time></trkpt>
|
||||
<trkpt lat="54.43271603" lon="10.16862845"><ele>46.5</ele><course>350.7</course><speed>2.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:01:59Z</time></trkpt>
|
||||
<trkpt lat="54.43274715" lon="10.1686111"><ele>46.20000076293945</ele><course>346.4</course><speed>2.0615528</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:02:01Z</time></trkpt>
|
||||
<trkpt lat="54.43277648" lon="10.16857157"><ele>45.29999923706055</ele><course>320.2</course><speed>2.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:02:03Z</time></trkpt>
|
||||
<trkpt lat="54.43279967" lon="10.16851235"><ele>44.20000076293945</ele><course>301.0</course><speed>2.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:02:05Z</time></trkpt>
|
||||
<trkpt lat="54.43280927" lon="10.16843886"><ele>43.70000076293945</ele><course>257.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>8</sat><time>2012-12-19T11:02:12Z</time></trkpt>
|
||||
<trkpt lat="54.43281042" lon="10.16844258"><ele>43.79999923706055</ele><course>257.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:02:14Z</time></trkpt>
|
||||
<trkpt lat="54.43281189" lon="10.16844306"><ele>43.400001525878906</ele><course>257.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:02:16Z</time></trkpt>
|
||||
<trkpt lat="54.43281353" lon="10.1684401"><ele>42.900001525878906</ele><course>257.6</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:02:18Z</time></trkpt>
|
||||
<trkpt lat="54.43065418" lon="10.1691878"><ele>30.100000381469727</ele><course>351.8</course><speed>6.823672</speed><hdop>2.0</hdop><src>gps</src><sat>11</sat><time>2012-12-19T11:04:47Z</time></trkpt>
|
||||
<trkpt lat="54.43091658" lon="10.16904786"><ele>42.5</ele><course>350.5</course><speed>11.0</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:04:49Z</time></trkpt>
|
||||
<trkpt lat="54.43118157" lon="10.16894269"><ele>54.599998474121094</ele><course>351.0</course><speed>11.0</speed><hdop>3.5777087</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:04:51Z</time></trkpt>
|
||||
<trkpt lat="54.43128582" lon="10.1689261"><ele>39.29999923706055</ele><course>352.1</course><speed>11.25</speed><hdop>1.4422204</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:04:53Z</time></trkpt>
|
||||
<trkpt lat="54.43148227" lon="10.16887666"><ele>38.900001525878906</ele><course>352.1</course><speed>11.0</speed><hdop>0.8485281</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:04:55Z</time></trkpt>
|
||||
<trkpt lat="54.43167487" lon="10.16883291"><ele>39.099998474121094</ele><course>352.5</course><speed>10.5</speed><hdop>0.8485281</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:04:57Z</time></trkpt>
|
||||
<trkpt lat="54.43187644" lon="10.16878558"><ele>39.70000076293945</ele><course>352.1</course><speed>11.0</speed><hdop>0.8485281</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:04:59Z</time></trkpt>
|
||||
<trkpt lat="54.43206744" lon="10.16873821"><ele>39.79999923706055</ele><course>351.7</course><speed>10.75</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:01Z</time></trkpt>
|
||||
<trkpt lat="54.43224878" lon="10.16869757"><ele>40.29999923706055</ele><course>351.9</course><speed>10.75</speed><hdop>1.0</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:03Z</time></trkpt>
|
||||
<trkpt lat="54.43244945" lon="10.16865159"><ele>40.70000076293945</ele><course>352.0</course><speed>10.75</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:05Z</time></trkpt>
|
||||
<trkpt lat="54.43270678" lon="10.16858865"><ele>41.099998474121094</ele><course>349.0</course><speed>9.0</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:08Z</time></trkpt>
|
||||
<trkpt lat="54.43276861" lon="10.1683779"><ele>42.0</ele><course>229.6</course><speed>1.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>5</sat><time>2012-12-19T11:05:16Z</time></trkpt>
|
||||
<trkpt lat="54.43277331" lon="10.16841148"><ele>41.70000076293945</ele><course>226.0</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T11:05:18Z</time></trkpt>
|
||||
<trkpt lat="54.43278154" lon="10.16843509"><ele>41.5</ele><course>54.4</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:20Z</time></trkpt>
|
||||
<trkpt lat="54.43279011" lon="10.16846136"><ele>41.70000076293945</ele><course>48.6</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T11:05:22Z</time></trkpt>
|
||||
<trkpt lat="54.43278873" lon="10.1685124"><ele>39.79999923706055</ele><course>106.7</course><speed>0.75</speed><hdop>0.7211102</hdop><src>gps</src><sat>6</sat><time>2012-12-19T11:05:31Z</time></trkpt>
|
||||
<trkpt lat="54.43276554" lon="10.16856626"><ele>39.0</ele><course>133.2</course><speed>1.5</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:33Z</time></trkpt>
|
||||
<trkpt lat="54.4327323" lon="10.16857875"><ele>39.20000076293945</ele><course>186.6</course><speed>1.5</speed><hdop>0.7211102</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:35Z</time></trkpt>
|
||||
<trkpt lat="54.43271732" lon="10.16858878"><ele>40.099998474121094</ele><course>186.6</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:37Z</time></trkpt>
|
||||
<trkpt lat="54.43272232" lon="10.16858727"><ele>40.20000076293945</ele><course>347.7</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:39Z</time></trkpt>
|
||||
<trkpt lat="54.43274513" lon="10.16859435"><ele>40.29999923706055</ele><course>5.3</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:41Z</time></trkpt>
|
||||
<trkpt lat="54.43275521" lon="10.16859123"><ele>40.900001525878906</ele><course>3.5</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:43Z</time></trkpt>
|
||||
<trkpt lat="54.43276063" lon="10.16858591"><ele>40.29999923706055</ele><course>3.5</course><speed>0.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:45Z</time></trkpt>
|
||||
<trkpt lat="54.43276232" lon="10.16858767"><ele>40.20000076293945</ele><course>3.5</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:47Z</time></trkpt>
|
||||
<trkpt lat="54.43276336" lon="10.16858918"><ele>40.0</ele><course>3.5</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:49Z</time></trkpt>
|
||||
<trkpt lat="54.43276266" lon="10.16859"><ele>39.70000076293945</ele><course>3.5</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:51Z</time></trkpt>
|
||||
<trkpt lat="54.43276198" lon="10.16858955"><ele>39.900001525878906</ele><course>3.5</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:53Z</time></trkpt>
|
||||
<trkpt lat="54.43276171" lon="10.16859016"><ele>40.0</ele><course>3.5</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:55Z</time></trkpt>
|
||||
<trkpt lat="54.43276159" lon="10.16859004"><ele>40.0</ele><course>3.5</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:05:57Z</time></trkpt>
|
||||
<trkpt lat="54.43254266" lon="10.16864678"><ele>39.70000076293945</ele><course>172.2</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:03Z</time></trkpt>
|
||||
<trkpt lat="54.43234557" lon="10.16869936"><ele>39.5</ele><course>171.8</course><speed>11.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:05Z</time></trkpt>
|
||||
<trkpt lat="54.43214547" lon="10.16874793"><ele>39.20000076293945</ele><course>171.7</course><speed>11.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:07Z</time></trkpt>
|
||||
<trkpt lat="54.43194885" lon="10.1687933"><ele>39.0</ele><course>172.0</course><speed>11.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:09Z</time></trkpt>
|
||||
<trkpt lat="54.43175468" lon="10.16883969"><ele>38.900001525878906</ele><course>171.6</course><speed>11.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:11Z</time></trkpt>
|
||||
<trkpt lat="54.43104911" lon="10.1689969"><ele>40.0</ele><course>173.2</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>9</sat><time>2012-12-19T11:06:18Z</time></trkpt>
|
||||
<trkpt lat="54.43085977" lon="10.16904165"><ele>39.599998474121094</ele><course>174.5</course><speed>10.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:20Z</time></trkpt>
|
||||
<trkpt lat="54.43061221" lon="10.16907294"><ele>39.599998474121094</ele><course>177.9</course><speed>6.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:23Z</time></trkpt>
|
||||
<trkpt lat="54.43053229" lon="10.16901271"><ele>40.20000076293945</ele><course>249.8</course><speed>2.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:26Z</time></trkpt>
|
||||
<trkpt lat="54.43054174" lon="10.16895685"><ele>40.5</ele><course>303.5</course><speed>1.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:28Z</time></trkpt>
|
||||
<trkpt lat="54.43056338" lon="10.16892448"><ele>40.400001525878906</ele><course>339.8</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:30Z</time></trkpt>
|
||||
<trkpt lat="54.43057773" lon="10.16891857"><ele>40.20000076293945</ele><course>350.9</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:32Z</time></trkpt>
|
||||
<trkpt lat="54.43058108" lon="10.16892524"><ele>40.400001525878906</ele><course>350.9</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:34Z</time></trkpt>
|
||||
<trkpt lat="54.43058096" lon="10.1689278"><ele>40.29999923706055</ele><course>350.9</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:36Z</time></trkpt>
|
||||
<trkpt lat="54.43058073" lon="10.16892979"><ele>40.29999923706055</ele><course>350.9</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:38Z</time></trkpt>
|
||||
<trkpt lat="54.43057965" lon="10.16893046"><ele>40.400001525878906</ele><course>350.9</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:40Z</time></trkpt>
|
||||
<trkpt lat="54.43057595" lon="10.16893252"><ele>41.0</ele><course>350.9</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:42Z</time></trkpt>
|
||||
<trkpt lat="54.43057528" lon="10.16893326"><ele>41.099998474121094</ele><course>350.9</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:44Z</time></trkpt>
|
||||
<trkpt lat="54.43057516" lon="10.16893343"><ele>41.099998474121094</ele><course>350.9</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:46Z</time></trkpt>
|
||||
<trkpt lat="54.43057517" lon="10.16893341"><ele>41.099998474121094</ele><course>350.9</course><speed>0.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:48Z</time></trkpt>
|
||||
<trkpt lat="54.43060046" lon="10.16895587"><ele>41.5</ele><course>35.1</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>11</sat><time>2012-12-19T11:06:51Z</time></trkpt>
|
||||
<trkpt lat="54.43061676" lon="10.16898573"><ele>41.400001525878906</ele><course>54.3</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:53Z</time></trkpt>
|
||||
<trkpt lat="54.43062859" lon="10.16901584"><ele>41.5</ele><course>61.1</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:55Z</time></trkpt>
|
||||
<trkpt lat="54.43063596" lon="10.16903848"><ele>41.20000076293945</ele><course>68.9</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:57Z</time></trkpt>
|
||||
<trkpt lat="54.43063844" lon="10.16907118"><ele>41.599998474121094</ele><course>71.9</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:06:59Z</time></trkpt>
|
||||
<trkpt lat="54.43064561" lon="10.16910394"><ele>41.900001525878906</ele><course>74.3</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:01Z</time></trkpt>
|
||||
<trkpt lat="54.4306482" lon="10.16911858"><ele>41.70000076293945</ele><course>74.3</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:03Z</time></trkpt>
|
||||
<trkpt lat="54.43064933" lon="10.16911628"><ele>41.599998474121094</ele><course>74.3</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:05Z</time></trkpt>
|
||||
<trkpt lat="54.43065079" lon="10.16911431"><ele>41.29999923706055</ele><course>74.3</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:07Z</time></trkpt>
|
||||
<trkpt lat="54.43065102" lon="10.1691115"><ele>41.099998474121094</ele><course>74.3</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:09Z</time></trkpt>
|
||||
<trkpt lat="54.43065147" lon="10.16910908"><ele>41.099998474121094</ele><course>74.3</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:11Z</time></trkpt>
|
||||
<trkpt lat="54.43065446" lon="10.16911726"><ele>41.20000076293945</ele><course>74.3</course><speed>0.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:13Z</time></trkpt>
|
||||
<trkpt lat="54.43067991" lon="10.16913114"><ele>41.400001525878906</ele><course>3.5</course><speed>2.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:15Z</time></trkpt>
|
||||
<trkpt lat="54.43071181" lon="10.16911823"><ele>41.29999923706055</ele><course>336.0</course><speed>1.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:17Z</time></trkpt>
|
||||
<trkpt lat="54.43073026" lon="10.16906781"><ele>42.0</ele><course>298.6</course><speed>2.0615528</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:19Z</time></trkpt>
|
||||
<trkpt lat="54.4307148" lon="10.16902511"><ele>41.70000076293945</ele><course>229.3</course><speed>1.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:21Z</time></trkpt>
|
||||
<trkpt lat="54.4306923" lon="10.16898712"><ele>41.70000076293945</ele><course>219.0</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:23Z</time></trkpt>
|
||||
<trkpt lat="54.4306707" lon="10.16895125"><ele>41.70000076293945</ele><course>230.3</course><speed>1.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:26Z</time></trkpt>
|
||||
<trkpt lat="54.43066591" lon="10.16893753"><ele>42.0</ele><course>230.3</course><speed>0.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:28Z</time></trkpt>
|
||||
<trkpt lat="54.43066558" lon="10.16893666"><ele>42.0</ele><course>222.9</course><speed>1.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:30Z</time></trkpt>
|
||||
<trkpt lat="54.4306212" lon="10.16890469"><ele>42.70000076293945</ele><course>177.3</course><speed>3.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:32Z</time></trkpt>
|
||||
<trkpt lat="54.43055872" lon="10.16896914"><ele>42.599998474121094</ele><course>128.7</course><speed>4.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:34Z</time></trkpt>
|
||||
<trkpt lat="54.43050817" lon="10.16914235"><ele>42.099998474121094</ele><course>108.4</course><speed>4.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:37Z</time></trkpt>
|
||||
<trkpt lat="54.43048602" lon="10.16926825"><ele>41.70000076293945</ele><course>104.4</course><speed>4.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:39Z</time></trkpt>
|
||||
<trkpt lat="54.4304711" lon="10.16939046"><ele>41.599998474121094</ele><course>102.2</course><speed>3.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:41Z</time></trkpt>
|
||||
<trkpt lat="54.4304639" lon="10.16950136"><ele>41.400001525878906</ele><course>92.1</course><speed>3.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:43Z</time></trkpt>
|
||||
<trkpt lat="54.43047806" lon="10.16959772"><ele>41.29999923706055</ele><course>64.4</course><speed>3.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:45Z</time></trkpt>
|
||||
<trkpt lat="54.43052418" lon="10.16961685"><ele>41.099998474121094</ele><course>354.2</course><speed>2.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:47Z</time></trkpt>
|
||||
<trkpt lat="54.43051058" lon="10.16939816"><ele>41.099998474121094</ele><course>207.7</course><speed>2.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>6</sat><time>2012-12-19T11:07:55Z</time></trkpt>
|
||||
<trkpt lat="54.43050815" lon="10.16952128"><ele>40.79999923706055</ele><course>84.9</course><speed>3.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:57Z</time></trkpt>
|
||||
<trkpt lat="54.43051757" lon="10.16961082"><ele>40.70000076293945</ele><course>55.9</course><speed>2.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:07:59Z</time></trkpt>
|
||||
<trkpt lat="54.43055012" lon="10.16964109"><ele>40.400001525878906</ele><course>5.4</course><speed>2.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:08:01Z</time></trkpt>
|
||||
<trkpt lat="54.43058612" lon="10.16962381"><ele>40.70000076293945</ele><course>329.4</course><speed>2.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:08:03Z</time></trkpt>
|
||||
<trkpt lat="54.4306113" lon="10.16957624"><ele>40.79999923706055</ele><course>303.1</course><speed>2.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:08:05Z</time></trkpt>
|
||||
<trkpt lat="54.43060325" lon="10.1695141"><ele>40.900001525878906</ele><course>235.6</course><speed>2.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:08:07Z</time></trkpt>
|
||||
<trkpt lat="54.43056712" lon="10.16948906"><ele>41.29999923706055</ele><course>185.0</course><speed>2.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:08:09Z</time></trkpt>
|
||||
<trkpt lat="54.43052946" lon="10.16951748"><ele>41.099998474121094</ele><course>129.6</course><speed>2.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:08:11Z</time></trkpt>
|
||||
<trkpt lat="54.43053857" lon="10.16962929"><ele>40.79999923706055</ele><course>24.9</course><speed>2.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:08:15Z</time></trkpt>
|
||||
<trkpt lat="54.43056676" lon="10.16964339"><ele>41.0</ele><course>2.0</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:08:17Z</time></trkpt>
|
||||
<trkpt lat="54.43057082" lon="10.16940228"><ele>40.70000076293945</ele><course>171.4</course><speed>2.0615528</speed><hdop>2.0</hdop><src>gps</src><sat>7</sat><time>2012-12-19T11:10:42Z</time></trkpt>
|
||||
<trkpt lat="54.43054445" lon="10.16948303"><ele>33.099998474121094</ele><course>104.2</course><speed>1.3462912</speed><hdop>1.4422204</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:10:44Z</time></trkpt>
|
||||
<trkpt lat="54.4304964" lon="10.16953782"><ele>38.70000076293945</ele><course>100.0</course><speed>1.5811388</speed><hdop>2.6832814</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:10:46Z</time></trkpt>
|
||||
<trkpt lat="54.43048754" lon="10.16958998"><ele>42.5</ele><course>91.8</course><speed>1.5811388</speed><hdop>1.1313708</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:10:48Z</time></trkpt>
|
||||
<trkpt lat="54.43046409" lon="10.16965521"><ele>41.79999923706055</ele><course>127.4</course><speed>3.0</speed><hdop>0.8485281</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:10:50Z</time></trkpt>
|
||||
<trkpt lat="54.43043131" lon="10.16972244"><ele>41.79999923706055</ele><course>141.6</course><speed>3.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:10:52Z</time></trkpt>
|
||||
<trkpt lat="54.43039158" lon="10.16977536"><ele>40.79999923706055</ele><course>151.7</course><speed>3.2882366</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:10:54Z</time></trkpt>
|
||||
<trkpt lat="54.43021246" lon="10.16987227"><ele>38.599998474121094</ele><course>169.0</course><speed>3.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>7</sat><time>2012-12-19T11:11:02Z</time></trkpt>
|
||||
<trkpt lat="54.43016291" lon="10.16989913"><ele>38.29999923706055</ele><course>164.8</course><speed>3.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:11:04Z</time></trkpt>
|
||||
<trkpt lat="54.43011186" lon="10.16992503"><ele>38.79999923706055</ele><course>168.0</course><speed>3.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:11:06Z</time></trkpt>
|
||||
<trkpt lat="54.43005522" lon="10.16993589"><ele>39.599998474121094</ele><course>182.2</course><speed>2.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:11:08Z</time></trkpt>
|
||||
<trkpt lat="54.43000737" lon="10.1699276"><ele>40.79999923706055</ele><course>197.2</course><speed>2.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:11:10Z</time></trkpt>
|
||||
<trkpt lat="54.42997965" lon="10.16989719"><ele>41.099998474121094</ele><course>217.2</course><speed>1.5</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:11:12Z</time></trkpt>
|
||||
<trkpt lat="54.42995738" lon="10.16986028"><ele>41.5</ele><course>231.0</course><speed>1.75</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:11:14Z</time></trkpt>
|
||||
<trkpt lat="54.42994569" lon="10.16976584"><ele>41.70000076293945</ele><course>269.0</course><speed>3.25</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:11:16Z</time></trkpt>
|
||||
<trkpt lat="54.42996078" lon="10.16965723"><ele>41.5</ele><course>296.5</course><speed>4.0</speed><hdop>0.5656854</hdop><src>gps</src><sat>12</sat><time>2012-12-19T11:11:18Z</time></trkpt>
|
||||
</trkseg></trk></gpx>
|
||||
+3109
File diff suppressed because it is too large
Load Diff
+126464
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
+2063
File diff suppressed because it is too large
Load Diff
Executable
+108
@@ -0,0 +1,108 @@
|
||||
package com.sap.sailing.nmeaconnector.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.Timeout;
|
||||
|
||||
import com.sap.sailing.nmeaconnector.BATSentence;
|
||||
import com.sap.sailing.nmeaconnector.BATSentence.WindVaneBatteryStatus;
|
||||
import com.sap.sailing.nmeaconnector.NmeaFactory;
|
||||
import com.sap.sailing.nmeaconnector.impl.BATParser;
|
||||
|
||||
import net.sf.marineapi.nmea.event.AbstractSentenceListener;
|
||||
import net.sf.marineapi.nmea.io.SentenceReader;
|
||||
import net.sf.marineapi.nmea.sentence.TalkerId;
|
||||
|
||||
public class BATTest {
|
||||
|
||||
@Rule public Timeout AbstractTracTracLiveTestTimeout = new Timeout(10 * 1000);
|
||||
|
||||
public static final String EXAMPLE = "$WIBAT,1,5";
|
||||
BATSentence empty;
|
||||
BATSentence bat;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
empty = new BATParser(TalkerId.WI);
|
||||
bat = new BATParser(EXAMPLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBATParser() {
|
||||
assertEquals(TalkerId.WI, empty.getTalkerId());
|
||||
assertEquals("BAT", empty.getSentenceId());
|
||||
assertEquals(2, empty.getFieldCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindingBATParserThroughFactory() throws UnsupportedEncodingException, InterruptedException {
|
||||
NmeaFactory.INSTANCE.getUtil().registerAdditionalParsers();
|
||||
final BATSentence[] sentences = new BATSentence[1];
|
||||
SentenceReader reader = new SentenceReader(new ByteArrayInputStream(EXAMPLE.getBytes("UTF-8")));
|
||||
final Object monitor = new Object();
|
||||
final boolean[] paused = new boolean[1];
|
||||
reader.addSentenceListener(new AbstractSentenceListener<BATSentence>() {
|
||||
@Override
|
||||
public void sentenceRead(BATSentence sentence) {
|
||||
sentences[0] = sentence;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readingPaused() {
|
||||
super.readingPaused();
|
||||
setPausedAndTriggerWaiters();
|
||||
}
|
||||
|
||||
private void setPausedAndTriggerWaiters() {
|
||||
synchronized (monitor) {
|
||||
paused[0] = true;
|
||||
monitor.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When reading stops without having been paused before, e.g., because the stream was
|
||||
* exhausted and closed, we will also set the {@code paused[0]} value to true and notify
|
||||
* waiters.
|
||||
*/
|
||||
@Override
|
||||
public void readingStopped() {
|
||||
super.readingStopped();
|
||||
setPausedAndTriggerWaiters();
|
||||
}
|
||||
});
|
||||
reader.setPauseTimeout(100);
|
||||
reader.start();
|
||||
synchronized (monitor) {
|
||||
while (!paused[0]) {
|
||||
monitor.wait(1000);
|
||||
}
|
||||
}
|
||||
assertNotNull(sentences[0]);
|
||||
assertEquals(WindVaneBatteryStatus.GOOD, sentences[0].getWindVaneBatteryStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBATParserString() {
|
||||
assertEquals(TalkerId.WI, bat.getTalkerId());
|
||||
assertEquals("BAT", bat.getSentenceId());
|
||||
assertEquals(2, bat.getFieldCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBaseUnitBatteryLevel() {
|
||||
assertEquals(5, bat.getBaseUnitBatteryLevel());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindVaneBatteryStatus() {
|
||||
assertEquals(WindVaneBatteryStatus.GOOD, bat.getWindVaneBatteryStatus());
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package com.sap.sailing.nmeaconnector.test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.nmeaconnector.NmeaFactory;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
import net.sf.marineapi.nmea.event.AbstractSentenceListener;
|
||||
import net.sf.marineapi.nmea.event.SentenceListener;
|
||||
import net.sf.marineapi.nmea.io.SentenceReader;
|
||||
import net.sf.marineapi.nmea.parser.DataNotAvailableException;
|
||||
import net.sf.marineapi.nmea.sentence.PositionSentence;
|
||||
import net.sf.marineapi.nmea.sentence.Sentence;
|
||||
import net.sf.marineapi.nmea.sentence.TimeSentence;
|
||||
import net.sf.marineapi.nmea.util.Position;
|
||||
import net.sf.marineapi.nmea.util.Time;
|
||||
|
||||
public class GeneralizedSentenceListenerTest {
|
||||
private SentenceReader sentenceReader;
|
||||
private SentenceReaderSupport readerSupport;
|
||||
|
||||
@Before
|
||||
public void setUp() throws FileNotFoundException {
|
||||
sentenceReader = new SentenceReader(new FileInputStream("resources/LogSS.txt"));
|
||||
readerSupport = new SentenceReaderSupport(sentenceReader);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterPositionListener() throws InterruptedException {
|
||||
final List<Position> positions = new ArrayList<>();
|
||||
SentenceListener positionListener = new AbstractSentenceListener<PositionSentence>() {
|
||||
@Override
|
||||
public void sentenceRead(PositionSentence sentence) {
|
||||
try {
|
||||
final Position position = sentence.getPosition();
|
||||
positions.add(position);
|
||||
} catch (DataNotAvailableException e) {
|
||||
// this can happen and simply means we don't have a position; so we
|
||||
// can safely ignore this exception
|
||||
}
|
||||
}
|
||||
};
|
||||
sentenceReader.addSentenceListener(positionListener);
|
||||
readerSupport.startReading();
|
||||
readerSupport.waitUntilAllMessagesHaveBeenRead();
|
||||
assertFalse(positions.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterTimeListener() throws InterruptedException {
|
||||
final List<Time> times = new ArrayList<>();
|
||||
SentenceListener timeListener = new AbstractSentenceListener<TimeSentence>() {
|
||||
@Override
|
||||
public void sentenceRead(TimeSentence sentence) {
|
||||
try {
|
||||
final Time time = sentence.getTime();
|
||||
times.add(time);
|
||||
} catch (DataNotAvailableException e) {
|
||||
// this can happen and simply means we don't have a position; so we
|
||||
// can safely ignore this exception
|
||||
}
|
||||
}
|
||||
};
|
||||
sentenceReader.addSentenceListener(timeListener);
|
||||
readerSupport.startReading();
|
||||
readerSupport.waitUntilAllMessagesHaveBeenRead();
|
||||
assertFalse(times.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleNmeaWindReceiverScenario() throws FileNotFoundException, InterruptedException {
|
||||
final Iterable<Wind> wind = NmeaFactory.INSTANCE.readWind(new FileInputStream("resources/LogSS.txt"));
|
||||
assertFalse(Util.isEmpty(wind));
|
||||
}
|
||||
|
||||
private static class MyGenericSentenceListener<A, B extends Sentence> extends AbstractSentenceListener<B> {
|
||||
private B lastSentence;
|
||||
|
||||
@Override
|
||||
public void sentenceRead(B sentence) {
|
||||
lastSentence = sentence;
|
||||
}
|
||||
|
||||
public B getLastSentence() {
|
||||
return lastSentence;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyOtherGenericSentenceListener<A> extends MyGenericSentenceListener<A, TimeSentence> {}
|
||||
|
||||
private static class MyConcreteSentenceListener extends MyOtherGenericSentenceListener<String> {}
|
||||
|
||||
private static class MyConcreteSentenceListenerSubclass extends MyConcreteSentenceListener {}
|
||||
|
||||
@Test
|
||||
public void testComplicatedGenericSentenceListenerSubclass() throws InterruptedException {
|
||||
MyConcreteSentenceListenerSubclass listener = new MyConcreteSentenceListenerSubclass();
|
||||
sentenceReader.addSentenceListener(listener);
|
||||
readerSupport.startReading();
|
||||
readerSupport.waitUntilAllMessagesHaveBeenRead();
|
||||
assertNotNull(listener.getLastSentence());
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.sap.sailing.nmeaconnector.test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sf.marineapi.nmea.event.AbstractSentenceListener;
|
||||
|
||||
/**
|
||||
* Asserting that Class.getInterfaces() does not consider transitively implemented
|
||||
* interfaces. Based on this observation it seems advisable to use
|
||||
* {@link Class#isAssignableFrom(Class)} instead of a contains check with the
|
||||
* directly implemented interfaces when using the {@link AbstractSentenceListener}
|
||||
* pattern. See commit 746440cae18dd55bf46df8207a03da70466f9e02.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class GetInterfacesTest {
|
||||
private interface I2 {}
|
||||
private interface I1 extends I2 {}
|
||||
private static class A implements I1 {}
|
||||
|
||||
@Test
|
||||
public void testTransitiveInterface() {
|
||||
assertFalse(Arrays.asList(A.class.getInterfaces()).contains(I2.class));
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.sap.sailing.nmeaconnector.test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.nmeaconnector.NmeaFactory;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class NMEAWindImportTest {
|
||||
Iterable<Wind> windFixes;
|
||||
|
||||
@Before
|
||||
public void setUp() throws FileNotFoundException, InterruptedException {
|
||||
NmeaFactory.INSTANCE.getUtil().registerAdditionalParsers();
|
||||
windFixes = NmeaFactory.INSTANCE.readWind(new FileInputStream("resources/ExcerptFromLogJB010815.txt"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThatSomeWindWasFound() {
|
||||
assertNotNull(windFixes);
|
||||
assertTrue(!Util.isEmpty(windFixes));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
NmeaFactory.INSTANCE.getUtil().unregisterAdditionalParsers();
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.sap.sailing.nmeaconnector.test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.nmeaconnector.NmeaFactory;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class NmeaFromZipImportTest {
|
||||
private ZipInputStream zipInputStream;
|
||||
|
||||
@Before
|
||||
public void setUp() throws FileNotFoundException {
|
||||
NmeaFactory.INSTANCE.getUtil().registerAdditionalParsers();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadOneZipEntry() throws IOException, InterruptedException {
|
||||
zipInputStream = new ZipInputStream(new FileInputStream("resources/LogSS.txt.zip"));
|
||||
ZipEntry entry;
|
||||
while ((entry=zipInputStream.getNextEntry()) != null) {
|
||||
if (entry.getName().toLowerCase().endsWith(".txt")) {
|
||||
Iterable<Wind> windFixes = NmeaFactory.INSTANCE.readWind(zipInputStream);
|
||||
assertTrue(!Util.isEmpty(windFixes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("This test only makes sense if the large file resources/Log210417.zip is present locally")
|
||||
@Test
|
||||
public void testOtherZipFile() throws IOException, InterruptedException {
|
||||
zipInputStream = new ZipInputStream(new FileInputStream("resources/Log210417.zip"));
|
||||
ZipEntry entry;
|
||||
while ((entry=zipInputStream.getNextEntry()) != null) {
|
||||
if (entry.getName().toLowerCase().endsWith(".txt")) {
|
||||
Iterable<Wind> windFixes = NmeaFactory.INSTANCE.readWind(zipInputStream);
|
||||
assertTrue(!Util.isEmpty(windFixes));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package com.sap.sailing.nmeaconnector.test;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import com.sap.sailing.nmeaconnector.NmeaFactory;
|
||||
|
||||
import net.sf.marineapi.nmea.event.AbstractSentenceListener;
|
||||
import net.sf.marineapi.nmea.event.SentenceListener;
|
||||
import net.sf.marineapi.nmea.io.SentenceReader;
|
||||
import net.sf.marineapi.nmea.sentence.Sentence;
|
||||
|
||||
/**
|
||||
* Abstract test support class that adds a listener to a {@link SentenceReader} passed to the constructor. This listener
|
||||
* will react to the reading being {@link SentenceListener#readingPaused() paused and unblocks all calls to
|
||||
* {@link #waitUntilAllMessagesHaveBeenRead()}.
|
||||
* <p>
|
||||
*
|
||||
* Subclasses can start the reading process by calling {@link #startReading()} which is shorthand for calling
|
||||
* {@link SentenceReader#start()} on the {@link SentenceReader} passed to the constructor.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class SentenceReaderSupport {
|
||||
private final SentenceReader reader;
|
||||
private final CountDownLatch finishedLatch;
|
||||
|
||||
protected SentenceReaderSupport(SentenceReader reader) {
|
||||
finishedLatch = new CountDownLatch(1);
|
||||
this.reader = reader;
|
||||
NmeaFactory.INSTANCE.getUtil().registerAdditionalParsers();
|
||||
reader.addSentenceListener(new AbstractSentenceListener<Sentence>() {
|
||||
@Override
|
||||
public void readingPaused() {
|
||||
finishedLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readingStopped() {
|
||||
finishedLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sentenceRead(Sentence sentence) {
|
||||
}
|
||||
});
|
||||
reader.setPauseTimeout(100);
|
||||
}
|
||||
|
||||
protected void startReading() {
|
||||
reader.start();
|
||||
}
|
||||
|
||||
protected void waitUntilAllMessagesHaveBeenRead() throws InterruptedException {
|
||||
finishedLatch.await();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>com.sap.sailing.nmeaconnector</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=UTF-8
|
||||
@@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
line.separator=\r\n
|
||||
@@ -0,0 +1,12 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
||||
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
pluginProject.extensions=false
|
||||
resolve.requirebundle=false
|
||||
@@ -0,0 +1,17 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Nmeaconnector
|
||||
Bundle-SymbolicName: com.sap.sailing.nmeaconnector
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Bundle-ClassPath: .
|
||||
Export-Package: com.sap.sailing.nmeaconnector
|
||||
Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sailing.domain.common,
|
||||
com.sap.sse.common,
|
||||
net.sf.marineapi,
|
||||
com.sap.sailing.declination
|
||||
Import-Package: org.osgi.framework
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-Activator: com.sap.sailing.nmeaconnector.impl.Activator
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sailing.nmeaconnector</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* MWVSentence.java
|
||||
* Copyright (C) 2011 Kimmo Tuukkanen
|
||||
*
|
||||
* This file is part of Java Marine API.
|
||||
* <http://sourceforge.net/projects/marineapi/>
|
||||
*
|
||||
* Java Marine API is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Java Marine API is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Java Marine API. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.sap.sailing.nmeaconnector;
|
||||
|
||||
import net.sf.marineapi.nmea.sentence.Sentence;
|
||||
|
||||
/**
|
||||
* This sentence is obsolete over most of its former coverage area.
|
||||
* The US/Canadian/Russian Loran-C network was shut down in 2010; it is still as of 2015 in limited use in Europe.
|
||||
* Loran-C operations in Norway will cease from 1st Jan 2016. [NORWAY]
|
||||
* The format of the sentence is:<pre>
|
||||
* 1 2 3 4 5 6
|
||||
* | | | | | |
|
||||
* $--AAM,A,A,x.x,N,c--c*hh<CR><LF>
|
||||
* Field Number:
|
||||
* Status, BOOLEAN, A = Arrival circle entered, V = not passed
|
||||
* Status, BOOLEAN, A = perpendicular passed at waypoint, V = not passed
|
||||
* Arrival circle radius
|
||||
* Units of radius, nautical miles
|
||||
* Waypoint ID
|
||||
* Checksum
|
||||
* Example: GPAAM,A,A,0.10,N,WPTNME*43
|
||||
* WPTNME is the waypoint name.
|
||||
* </pre>
|
||||
*/
|
||||
public interface AAMSentence extends Sentence {
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* MWVSentence.java
|
||||
* Copyright (C) 2011 Kimmo Tuukkanen
|
||||
*
|
||||
* This file is part of Java Marine API.
|
||||
* <http://sourceforge.net/projects/marineapi/>
|
||||
*
|
||||
* Java Marine API is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Java Marine API is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Java Marine API. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.sap.sailing.nmeaconnector;
|
||||
|
||||
import net.sf.marineapi.nmea.sentence.Sentence;
|
||||
|
||||
/**
|
||||
* BAT sentence. Used for the proprietary NMEA extension of the SailTimer WindVane's battery indicator message.
|
||||
* The format of the sentence is:<pre>
|
||||
*
|
||||
* $WIBAT,a,b*hh
|
||||
*
|
||||
* 1) Wind Vane Battery (‘0’= Low, ‘1’= Good)
|
||||
* 2) Base Unit battery level (‘0’ = Low, ‘9’ = Good)
|
||||
* 3) Checksum
|
||||
* </pre>
|
||||
*/
|
||||
public interface BATSentence extends Sentence {
|
||||
public static enum WindVaneBatteryStatus {
|
||||
LOW(0), GOOD(1);
|
||||
|
||||
private final int value;
|
||||
|
||||
private WindVaneBatteryStatus(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
WindVaneBatteryStatus getWindVaneBatteryStatus();
|
||||
|
||||
void setWindVaneBatteryStatus(WindVaneBatteryStatus status);
|
||||
|
||||
/**
|
||||
* Battery status is reported as value ranve 0..9 where 0 means "Low" and 9 means "Good."
|
||||
*/
|
||||
int getBaseUnitBatteryLevel();
|
||||
|
||||
void setBaseUnitBatteryLevel(int level);
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* MWVSentence.java
|
||||
* Copyright (C) 2011 Kimmo Tuukkanen
|
||||
*
|
||||
* This file is part of Java Marine API.
|
||||
* <http://sourceforge.net/projects/marineapi/>
|
||||
*
|
||||
* Java Marine API is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Java Marine API is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Java Marine API. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.sap.sailing.nmeaconnector;
|
||||
|
||||
import net.sf.marineapi.nmea.sentence.Sentence;
|
||||
|
||||
/**
|
||||
* BWC sentence. Bearing and Distance to Waypoint – Latitude, N/S, Longitude, E/W, UTC, Status.
|
||||
* The format of the sentence is:<pre>
|
||||
*
|
||||
* 1 2 3 4 5 6 7 8 9 10 11 12 13
|
||||
* | | | | | | | | | | | | |
|
||||
* $--BWC,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x.x,T,x.x,M,x.x,N,c--c*hh
|
||||
* 1) Time (UTC)
|
||||
* 2) Waypoint Latitude
|
||||
* 3) N = North, S = South
|
||||
* 4) Waypoint Longitude
|
||||
* 5) E = East, W = West
|
||||
* 6) Bearing, True
|
||||
* 7) T = True
|
||||
* 8) Bearing, Magnetic
|
||||
* 9) M = Magnetic
|
||||
* 10) Nautical Miles
|
||||
* 11) N = Nautical Miles
|
||||
* 12) Waypoint ID
|
||||
* 13) Checksum
|
||||
* </pre>
|
||||
*/
|
||||
public interface BWCSentence extends Sentence {
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* MWVSentence.java
|
||||
* Copyright (C) 2011 Kimmo Tuukkanen
|
||||
*
|
||||
* This file is part of Java Marine API.
|
||||
* <http://sourceforge.net/projects/marineapi/>
|
||||
*
|
||||
* Java Marine API is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Java Marine API is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Java Marine API. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.sap.sailing.nmeaconnector;
|
||||
|
||||
import net.sf.marineapi.nmea.sentence.Sentence;
|
||||
|
||||
/**
|
||||
* BWR sentence. Bearing and Distance to Waypoint – Rhumb Line Latitude, N/S, Longitude, E/W, UTC, Status.
|
||||
* The format of the sentence is:<pre>
|
||||
*
|
||||
* 1 2 3 4 5 6 7 8 9 10 11 12 13
|
||||
* | | | | | | | | | | | | |
|
||||
* $--BWR,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x.x,T,x.x,M,x.x,N,c--c*hh
|
||||
* 1) Time (UTC)
|
||||
* 2) Waypoint Latitude
|
||||
* 3) N = North, S = South
|
||||
* 4) Waypoint Longitude
|
||||
* 5) E = East, W = West
|
||||
* 6) Bearing, True
|
||||
* 7) T = True
|
||||
* 8) Bearing, Magnetic
|
||||
* 9) M = Magnetic
|
||||
* 10) Nautical Miles
|
||||
* 11) N = Nautical Miles
|
||||
* 12) Waypoint ID
|
||||
* 13) Checksum
|
||||
* </pre>
|
||||
*/
|
||||
public interface BWRSentence extends Sentence {
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* MWVSentence.java
|
||||
* Copyright (C) 2011 Kimmo Tuukkanen
|
||||
*
|
||||
* This file is part of Java Marine API.
|
||||
* <http://sourceforge.net/projects/marineapi/>
|
||||
*
|
||||
* Java Marine API is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Java Marine API is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Java Marine API. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.sap.sailing.nmeaconnector;
|
||||
|
||||
import net.sf.marineapi.nmea.sentence.Sentence;
|
||||
|
||||
/**
|
||||
* This sentence is obsolete over most of its former coverage area.
|
||||
* The US/Canadian/Russian Loran-C network was shut down in 2010; it is still as of 2015 in limited use in Europe.
|
||||
* Loran-C operations in Norway will cease from 1st Jan 2016. [NORWAY]
|
||||
* The format of the sentence is:<pre>
|
||||
* 12 14
|
||||
* 1 2 3 4 5 6 7 8 9 10 11| 13|
|
||||
* | | | | | | | | | | | | | |
|
||||
* $--GLC,xxxx,x.x,a,x.x,a,x.x,a.x,x,a,x.x,a,x.x,a*hh<CR><LF>
|
||||
* Field Number:
|
||||
* GRI Microseconds/10
|
||||
* Master TOA Microseconds
|
||||
* Master TOA Signal Status
|
||||
* Time Difference 1 Microseconds
|
||||
* Time Difference 1 Signal Status
|
||||
* Time Difference 2 Microseconds
|
||||
* Time Difference 2 Signal Status
|
||||
* Time Difference 3 Microseconds
|
||||
* Time Difference 3 Signal Status
|
||||
* Time Difference 4 Microseconds
|
||||
* Time Difference 4 Signal Status
|
||||
* Time Difference 5 Microseconds
|
||||
* Time Difference 5 Signal Status
|
||||
* Checksum
|
||||
* </pre>
|
||||
*/
|
||||
public interface GLCSentence extends Sentence {
|
||||
}
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
package com.sap.sailing.nmeaconnector;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.tracking.WindListener;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
import net.sf.marineapi.nmea.event.SentenceListener;
|
||||
import net.sf.marineapi.nmea.io.SentenceReader;
|
||||
import net.sf.marineapi.nmea.sentence.DateSentence;
|
||||
import net.sf.marineapi.nmea.sentence.MWVSentence;
|
||||
import net.sf.marineapi.nmea.sentence.SentenceId;
|
||||
import net.sf.marineapi.nmea.sentence.TimeSentence;
|
||||
|
||||
/**
|
||||
* A stateful receiver that consumes sentences from an NMEA {@link SentenceReader}
|
||||
* for which it acts as a {@link SentenceListener} for sentences providing information
|
||||
* about wind measurements, date/time reference, location of measurements and data
|
||||
* that may be required to convert apparent wind speeds and angles into true wind
|
||||
* speeds and directions. Clients can {@link #addWindListener(WindListener) register}
|
||||
* as a {@link WindListener} and receive {@link WindListener#windDataReceived} callbacks
|
||||
* whenever a {@link Wind} fix was assembled out of the various NMEA sentences.<p>
|
||||
*
|
||||
* The NMEA 0183 protocol specifies that a {@link SentenceId#MWV} sentence may provide
|
||||
* "true" (relative to true north) or "relative" (relative to bow) wind angles. However,
|
||||
* it is not entirely clear in all cases if those angles have the magnetic declination
|
||||
* already corrected. Only with {@link SentenceId#MWD} sentences does this become clear,
|
||||
* and a value for the magnetic declination could be inferred. For now, we will assume
|
||||
* that {@link SentenceId#MWV} values really provide angles based on true north if
|
||||
* {@link MWVSentence#isTrue()} is {@code true}.<p>
|
||||
*
|
||||
* This receiver assumes that the sentences do not necessarily have to be entirely
|
||||
* time-synchronous. But different sentence types can provide "hints" as to the timing.
|
||||
* GPS fixes (@link SentenceId#GGA} and other position fixes {@link SentenceId#GLL} have
|
||||
* time of day but no date information. Other messages such as {@link SentenceId#RMC} and
|
||||
* {@link SentenceId#ZDA} contain date and optionally time zone information. When analyzing
|
||||
* the entire sequence, under certain assumptions such as fixes with time information being
|
||||
* less than 24h apart from each other and with at least one {@link DateSentence} per day
|
||||
* it is possible to combine {@link TimeSentence}s with the last date information into
|
||||
* a full {@link TimePoint}.<p>
|
||||
*
|
||||
* In order to also work in streaming mode and to provide {@link Wind} fixes as soon as
|
||||
* all data relevant for a wind fix has been received, this receiver won't wait for the
|
||||
* next timing information to interpolate, but instead the last timing data received
|
||||
* before the wind measurement will be used for the {@link Wind} fix.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface NMEAWindReceiver {
|
||||
void addWindListener(WindListener listener);
|
||||
|
||||
void removeWindListener(WindListener listener);
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.sap.sailing.nmeaconnector;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.nmeaconnector.impl.NmeaFactoryImpl;
|
||||
|
||||
import net.sf.marineapi.nmea.sentence.MWVSentence;
|
||||
import net.sf.marineapi.nmea.sentence.ZDASentence;
|
||||
|
||||
public interface NmeaFactory {
|
||||
static NmeaFactory INSTANCE = new NmeaFactoryImpl();
|
||||
|
||||
NmeaUtil getUtil();
|
||||
|
||||
/**
|
||||
* Reads from a series of NMEA 0183 sentences and looks for timing information in the form of {@link ZDASentence}s
|
||||
* as well as for weather records ({@link MWVSentence} sentences). If multiple {@code MWV} sentences are found between
|
||||
* two time stamps, linear interpolation is used to assign time points to each wind reading. The information is
|
||||
* furthermore combined with position and motion data. If the wind readings are apparent readings, the speed of
|
||||
* the wind sensor is taken into account to transform into a true reading. NMEA specifies that a "true" reading
|
||||
* is relative to "true north" which we can only believe; it means that the instrument needs to have an understanding
|
||||
* of the magnetic declination at the time and position of the measurement.
|
||||
*
|
||||
* @param inputStream
|
||||
* will be consumed up to its end but will not be closed; the caller remains responsible for closing the
|
||||
* input stream.
|
||||
* @return a sequence of {@link Wind} objects as extracted from the NMEA 0183 sentences found in the contents of the
|
||||
* {@code reader}; never {@code null}, but possibly empty
|
||||
*/
|
||||
Iterable<Wind> readWind(InputStream inputStream) throws InterruptedException;
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.sap.sailing.nmeaconnector;
|
||||
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
import net.sf.marineapi.nmea.parser.SentenceFactory;
|
||||
import net.sf.marineapi.nmea.sentence.MWVSentence;
|
||||
import net.sf.marineapi.nmea.util.Units;
|
||||
|
||||
public interface NmeaUtil {
|
||||
Wind getWind(TimePoint timePoint, Position position, MWVSentence mwvSentence);
|
||||
|
||||
Speed getSpeed(double magnitude, Units unit);
|
||||
|
||||
SpeedWithBearing getSpeedWithBearing(double speedMagnitude, Units speedUnit, double bearingInDegrees);
|
||||
|
||||
/**
|
||||
* Replaces all occurrences of <code>sequenceToFind</code> by <code>replaceWith</code>, as {@link String#replace(CharSequence, CharSequence)},
|
||||
* but assuming that <code>nmeaSentence</code> has a trailing NMEA checksum, adjusts the checksum accordingly. This will turn a valid
|
||||
* checksum into a valid checksum again, and an invalid checksum into an invalid checksum.
|
||||
*/
|
||||
String replace(String nmeaSentence, String sequenceToFind, String replaceWith);
|
||||
|
||||
/**
|
||||
* Call this to register proprietary parsers provided by this bundle with the
|
||||
* {@link SentenceFactory} {@link SentenceFactory#getInstance() default instance}.
|
||||
*/
|
||||
void registerAdditionalParsers();
|
||||
|
||||
/**
|
||||
* Call this to unregister proprietary parsers provided by this bundle from the
|
||||
* {@link SentenceFactory} {@link SentenceFactory#getInstance() default instance}.
|
||||
*/
|
||||
void unregisterAdditionalParsers();
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.sap.sailing.nmeaconnector;
|
||||
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sse.common.Timed;
|
||||
|
||||
public interface TimedBearing extends Timed, Bearing {
|
||||
}
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
package com.sap.sailing.nmeaconnector;
|
||||
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sse.common.Timed;
|
||||
|
||||
public interface TimedSpeedWithBearing extends Timed, SpeedWithBearing {
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* GSVParser.java
|
||||
* Copyright (C) 2010 Kimmo Tuukkanen
|
||||
*
|
||||
* This file is part of Java Marine API.
|
||||
* <http://ktuukkan.github.io/marine-api/>
|
||||
*
|
||||
* Java Marine API is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Java Marine API is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Java Marine API. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.sap.sailing.nmeaconnector.impl;
|
||||
|
||||
import com.sap.sailing.nmeaconnector.AAMSentence;
|
||||
|
||||
import net.sf.marineapi.nmea.parser.SentenceParser;
|
||||
import net.sf.marineapi.nmea.sentence.TalkerId;
|
||||
|
||||
/**
|
||||
* GSV sentence parser.
|
||||
*
|
||||
* @author Kimmo Tuukkanen
|
||||
* @author Axel Uhl
|
||||
*/
|
||||
public class AAMParser extends SentenceParser implements AAMSentence {
|
||||
|
||||
// field indices, in case someone plans to use them:
|
||||
// private static final int STATUS_1 = 0;
|
||||
// private static final int STATUS_2 = 1;
|
||||
// private static final int ARRIVAL_CIRCLE_RADIUS = 2;
|
||||
// private static final int UNIT_OF_RADIUS = 3;
|
||||
// private static final int WAYPOINT_ID = 4;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param nmea
|
||||
* GLC Sentence
|
||||
*/
|
||||
public AAMParser(String nmea) {
|
||||
super(nmea, "AAM");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an GSV parser with empty sentence.
|
||||
*
|
||||
* @param talker
|
||||
* TalkerId to set
|
||||
*/
|
||||
public AAMParser(TalkerId talker) {
|
||||
super(talker, "AAM", 5);
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.sap.sailing.nmeaconnector.impl;
|
||||
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
import com.sap.sailing.nmeaconnector.NmeaFactory;
|
||||
|
||||
import net.sf.marineapi.nmea.parser.SentenceFactory;
|
||||
|
||||
/**
|
||||
* Registers and unregisters additional proprietary NMEA sentence parsers with the {@link SentenceFactory}
|
||||
* {@link SentenceFactory#getInstance() default instance}.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class Activator implements BundleActivator {
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception {
|
||||
NmeaFactory.INSTANCE.getUtil().registerAdditionalParsers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
NmeaFactory.INSTANCE.getUtil().unregisterAdditionalParsers();
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* MWVParser.java
|
||||
* Copyright (C) 2011 Kimmo Tuukkanen
|
||||
*
|
||||
* This file is part of Java Marine API.
|
||||
* <http://sourceforge.net/projects/marineapi/>
|
||||
*
|
||||
* Java Marine API is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Java Marine API is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Java Marine API. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.sap.sailing.nmeaconnector.impl;
|
||||
|
||||
import com.sap.sailing.nmeaconnector.BATSentence;
|
||||
|
||||
import net.sf.marineapi.nmea.parser.SentenceParser;
|
||||
import net.sf.marineapi.nmea.sentence.TalkerId;
|
||||
|
||||
/**
|
||||
* BAT sentence parser. Used for the proprietary NMEA extension of the SailTimer WindVane's battery indicator message.
|
||||
* The format of the sentence is:<pre>
|
||||
*
|
||||
* $WIBAT,a,b*hh
|
||||
*
|
||||
* 1) Wind Vane Battery (‘0’= Low, ‘1’= Good)
|
||||
* 2) Base Unit battery level (‘0’ = Low, ‘9’ = Good)
|
||||
* 3) Checksum
|
||||
* </pre>
|
||||
*
|
||||
* @author Axel Uhl
|
||||
*/
|
||||
public class BATParser extends SentenceParser implements BATSentence {
|
||||
private static final int WIND_VANE_BATTERY_STATUS = 0;
|
||||
private static final int BASE_UNIT_BATTERY_LEVEL = 1;
|
||||
|
||||
/**
|
||||
* Creates a new instance of BATParser.
|
||||
*
|
||||
* @param nmea BAT sentence String
|
||||
*/
|
||||
public BATParser(String nmea) {
|
||||
super(nmea, /* Proprietary extension for SailTimer WindVane's battery indicator message */ "BAT");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty instance of BATParser.
|
||||
*
|
||||
* @param talker Talker id to set
|
||||
*/
|
||||
public BATParser(TalkerId talker) {
|
||||
super(talker, /* Proprietary extension for SailTimer WindVane's battery indicator message */ "BAT", 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindVaneBatteryStatus getWindVaneBatteryStatus() {
|
||||
WindVaneBatteryStatus result = null;
|
||||
final int intValue = getIntValue(WIND_VANE_BATTERY_STATUS);
|
||||
for (BATSentence.WindVaneBatteryStatus status : BATSentence.WindVaneBatteryStatus.values()) {
|
||||
if (status.getValue() == intValue) {
|
||||
result = status;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBaseUnitBatteryLevel() {
|
||||
return getIntValue(BASE_UNIT_BATTERY_LEVEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindVaneBatteryStatus(WindVaneBatteryStatus status) {
|
||||
setIntValue(WIND_VANE_BATTERY_STATUS, status.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBaseUnitBatteryLevel(int level) {
|
||||
if (level < 0 || level > 9) {
|
||||
throw new IllegalArgumentException("Level must be in the range 0..9 but was "+level);
|
||||
}
|
||||
setIntValue(BASE_UNIT_BATTERY_LEVEL, level);
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* MWVParser.java
|
||||
* Copyright (C) 2011 Kimmo Tuukkanen
|
||||
*
|
||||
* This file is part of Java Marine API.
|
||||
* <http://sourceforge.net/projects/marineapi/>
|
||||
*
|
||||
* Java Marine API is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Java Marine API is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Java Marine API. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.sap.sailing.nmeaconnector.impl;
|
||||
|
||||
import com.sap.sailing.nmeaconnector.BWCSentence;
|
||||
|
||||
import net.sf.marineapi.nmea.parser.SentenceParser;
|
||||
import net.sf.marineapi.nmea.sentence.TalkerId;
|
||||
|
||||
public class BWCParser extends SentenceParser implements BWCSentence {
|
||||
/**
|
||||
* Creates a new instance of BWCParser.
|
||||
*
|
||||
* @param nmea BWC sentence String
|
||||
*/
|
||||
public BWCParser(String nmea) {
|
||||
super(nmea, "BWC");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty instance of BWCParser.
|
||||
*
|
||||
* @param talker Talker id to set
|
||||
*/
|
||||
public BWCParser(TalkerId talker) {
|
||||
super(talker, "BWC", 12);
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* MWVParser.java
|
||||
* Copyright (C) 2011 Kimmo Tuukkanen
|
||||
*
|
||||
* This file is part of Java Marine API.
|
||||
* <http://sourceforge.net/projects/marineapi/>
|
||||
*
|
||||
* Java Marine API is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Java Marine API is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Java Marine API. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.sap.sailing.nmeaconnector.impl;
|
||||
|
||||
import com.sap.sailing.nmeaconnector.BWCSentence;
|
||||
|
||||
import net.sf.marineapi.nmea.parser.SentenceParser;
|
||||
import net.sf.marineapi.nmea.sentence.TalkerId;
|
||||
|
||||
public class BWRParser extends SentenceParser implements BWCSentence {
|
||||
/**
|
||||
* Creates a new instance of BWRParser.
|
||||
*
|
||||
* @param nmea BWR sentence String
|
||||
*/
|
||||
public BWRParser(String nmea) {
|
||||
super(nmea, "BWR");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty instance of BWRParser.
|
||||
*
|
||||
* @param talker Talker id to set
|
||||
*/
|
||||
public BWRParser(TalkerId talker) {
|
||||
super(talker, "BWR", 12);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.sap.sailing.nmeaconnector.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.nmeaconnector.TimedBearing;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
public class DegreeBearingWithTimepoint extends DegreeBearingImpl implements TimedBearing {
|
||||
private static final long serialVersionUID = 8704478920647067862L;
|
||||
private final TimePoint timePoint;
|
||||
|
||||
public DegreeBearingWithTimepoint(TimePoint timePoint, double bearingDeg) {
|
||||
super(bearingDeg);
|
||||
this.timePoint = timePoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getTimePoint() {
|
||||
return timePoint;
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* GSVParser.java
|
||||
* Copyright (C) 2010 Kimmo Tuukkanen
|
||||
*
|
||||
* This file is part of Java Marine API.
|
||||
* <http://ktuukkan.github.io/marine-api/>
|
||||
*
|
||||
* Java Marine API is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Java Marine API is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Java Marine API. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.sap.sailing.nmeaconnector.impl;
|
||||
|
||||
import com.sap.sailing.nmeaconnector.GLCSentence;
|
||||
|
||||
import net.sf.marineapi.nmea.parser.SentenceParser;
|
||||
import net.sf.marineapi.nmea.sentence.TalkerId;
|
||||
|
||||
/**
|
||||
* GSV sentence parser.
|
||||
*
|
||||
* @author Kimmo Tuukkanen
|
||||
* @author Axel Uhl
|
||||
*/
|
||||
public class GLCParser extends SentenceParser implements GLCSentence {
|
||||
|
||||
// field indices, in case someone plans to use them:
|
||||
// private static final int GRI_MICROSECONDS_BY_10 = 0;
|
||||
// private static final int MASTER_TOA_MICROSECONDS = 1;
|
||||
// private static final int MASTER_TOA_SIGNAL_STATUS = 2;
|
||||
// private static final int TIME_DIFF_1_MICROSECONDS = 3;
|
||||
// private static final int TIME_DIFF_1_SIGNAL_STATUS = 4;
|
||||
// private static final int TIME_DIFF_2_MICROSECONDS = 5;
|
||||
// private static final int TIME_DIFF_2_SIGNAL_STATUS = 6;
|
||||
// private static final int TIME_DIFF_3_MICROSECONDS = 7;
|
||||
// private static final int TIME_DIFF_3_SIGNAL_STATUS = 8;
|
||||
// private static final int TIME_DIFF_4_MICROSECONDS = 9;
|
||||
// private static final int TIME_DIFF_4_SIGNAL_STATUS = 10;
|
||||
// private static final int TIME_DIFF_5_MICROSECONDS = 11;
|
||||
// private static final int TIME_DIFF_5_SIGNAL_STATUS = 12;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param nmea
|
||||
* GLC Sentence
|
||||
*/
|
||||
public GLCParser(String nmea) {
|
||||
super(nmea, "GLC");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an GSV parser with empty sentence.
|
||||
*
|
||||
* @param talker
|
||||
* TalkerId to set
|
||||
*/
|
||||
public GLCParser(TalkerId talker) {
|
||||
super(talker, "GLC", 19);
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.sap.sailing.nmeaconnector.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.tracking.Track;
|
||||
import com.sap.sailing.nmeaconnector.TimedSpeedWithBearing;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/**
|
||||
* Can be used as a wind vector in a {@link Track} because it has a {@link TimePoint}.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class KnotSpeedWithBearingAndTimepoint extends KnotSpeedWithBearingImpl implements TimedSpeedWithBearing {
|
||||
private static final long serialVersionUID = -627441174825774742L;
|
||||
private final TimePoint timePoint;
|
||||
|
||||
public KnotSpeedWithBearingAndTimepoint(TimePoint timePoint, double speedInKnots, Bearing bearing) {
|
||||
super(speedInKnots, bearing);
|
||||
this.timePoint = timePoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getTimePoint() {
|
||||
return timePoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getTimePoint().toString()+": "+super.toString();
|
||||
}
|
||||
}
|
||||
Executable
+407
@@ -0,0 +1,407 @@
|
||||
package com.sap.sailing.nmeaconnector.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.declination.Declination;
|
||||
import com.sap.sailing.declination.DeclinationService;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KilometersPerHourSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterPerSecondSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableBearing;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalablePosition;
|
||||
import com.sap.sailing.domain.common.scalablevalue.impl.ScalableSpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrack;
|
||||
import com.sap.sailing.domain.tracking.WindListener;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackImpl;
|
||||
import com.sap.sailing.nmeaconnector.NMEAWindReceiver;
|
||||
import com.sap.sailing.nmeaconnector.TimedBearing;
|
||||
import com.sap.sailing.nmeaconnector.TimedSpeedWithBearing;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
import net.sf.marineapi.nmea.event.AbstractSentenceListener;
|
||||
import net.sf.marineapi.nmea.io.SentenceReader;
|
||||
import net.sf.marineapi.nmea.parser.DataNotAvailableException;
|
||||
import net.sf.marineapi.nmea.sentence.DateSentence;
|
||||
import net.sf.marineapi.nmea.sentence.HeadingSentence;
|
||||
import net.sf.marineapi.nmea.sentence.MDASentence;
|
||||
import net.sf.marineapi.nmea.sentence.MWDSentence;
|
||||
import net.sf.marineapi.nmea.sentence.MWVSentence;
|
||||
import net.sf.marineapi.nmea.sentence.PositionSentence;
|
||||
import net.sf.marineapi.nmea.sentence.SentenceId;
|
||||
import net.sf.marineapi.nmea.sentence.TimeSentence;
|
||||
import net.sf.marineapi.nmea.sentence.VTGSentence;
|
||||
import net.sf.marineapi.nmea.sentence.VWRSentence;
|
||||
import net.sf.marineapi.nmea.sentence.ZDASentence;
|
||||
import net.sf.marineapi.nmea.util.CompassPoint;
|
||||
import net.sf.marineapi.nmea.util.Date;
|
||||
import net.sf.marineapi.nmea.util.Direction;
|
||||
import net.sf.marineapi.nmea.util.Time;
|
||||
import net.sf.marineapi.nmea.util.Units;
|
||||
|
||||
public class NMEAWindReceiverImpl implements NMEAWindReceiver {
|
||||
private static final Logger logger = Logger.getLogger(NMEAWindReceiverImpl.class.getName());
|
||||
private final ConcurrentHashMap<WindListener, WindListener> listeners;
|
||||
private final DynamicTrack<TimedSpeedWithBearing> trueWind;
|
||||
private final DynamicTrack<TimedSpeedWithBearing> apparentWind;
|
||||
private final DynamicTrack<GPSFix> sensorPositions;
|
||||
private final DynamicTrack<TimedSpeedWithBearing> sensorSpeeds;
|
||||
private final DynamicTrack<TimedBearing> trueHeadings;
|
||||
|
||||
/**
|
||||
* Don't use the {@link GregorianCalendar#getTime() time point} of this calendar unless a {@link DateSentence} and a
|
||||
* {@link TimeSentence} have been received which is indicated by the {@link #dateReceived} and the
|
||||
* {@link #timeReceived} fields, respectively.
|
||||
*/
|
||||
private final GregorianCalendar utcCalendar;
|
||||
|
||||
private final DeclinationService declinationService = DeclinationService.INSTANCE;
|
||||
|
||||
/**
|
||||
* Until a {@link DateSentence} has been received, the {@link #utcCalendar}'s {@link GregorianCalendar#getTime()}
|
||||
* must not be used.
|
||||
*/
|
||||
private boolean dateReceived;
|
||||
|
||||
private boolean timeReceived;
|
||||
|
||||
private class MWVSentenceListener extends AbstractSentenceListener<MWVSentence> {
|
||||
@Override
|
||||
public void sentenceRead(MWVSentence sentence) {
|
||||
final TimePoint timePoint = getLastTimePoint();
|
||||
if (timePoint != null) {
|
||||
try {
|
||||
final Speed speed = createSpeed(sentence.getSpeedUnit(), sentence.getSpeed());
|
||||
final KnotSpeedWithBearingAndTimepoint fix;
|
||||
if (sentence.isTrue()) {
|
||||
final Bearing trueHeading = trueHeadings.getInterpolatedValue(getLastTimePoint(), f->new ScalableBearing(f));
|
||||
if (trueHeading != null) {
|
||||
// need to take heading into account as MWV is still relative to bow, even if "true" is provided;
|
||||
// it is what you would see on the wind display when set to "true wind"
|
||||
fix = new KnotSpeedWithBearingAndTimepoint(timePoint,
|
||||
speed.getKnots(), new DegreeBearingImpl(sentence.getAngle()).reverse().add(trueHeading));
|
||||
trueWind.add(fix);
|
||||
tryToCreateWindFixFromTrueWind(fix);
|
||||
}
|
||||
} else {
|
||||
fix = new KnotSpeedWithBearingAndTimepoint(timePoint,
|
||||
speed.getKnots(), new DegreeBearingImpl(sentence.getAngle()).reverse());
|
||||
apparentWind.add(fix);
|
||||
tryToCreateWindFixFromApparentWind(fix);
|
||||
}
|
||||
// use the newly gained wind data to try to assemble a Wind fix if
|
||||
// other values such as heading and position are known
|
||||
} catch (DataNotAvailableException e) {
|
||||
// can happen... simply ignore this incomplete sentence
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MWDSentenceListener extends AbstractSentenceListener<MWDSentence> {
|
||||
@Override
|
||||
public void sentenceRead(MWDSentence sentence) {
|
||||
// the message provides data about the true wind direction (TWD) and true wind speed (TWS);
|
||||
// here, "true" means "not apparent"; the direction may still be provided in degrees true
|
||||
// or degrees magnetic, and we need to find out which is available
|
||||
final TimePoint timePoint = getLastTimePoint();
|
||||
if (timePoint != null) {
|
||||
final com.sap.sailing.domain.common.Position position = getPosition(timePoint);
|
||||
if (position != null) {
|
||||
final Speed speed;
|
||||
if (!Double.isNaN(sentence.getWindSpeed())) {
|
||||
speed = new MeterPerSecondSpeedImpl(sentence.getWindSpeed());
|
||||
} else if (!Double.isNaN(sentence.getWindSpeedKnots())) {
|
||||
speed = new KnotSpeedImpl(sentence.getWindSpeedKnots());
|
||||
} else {
|
||||
speed = null;
|
||||
}
|
||||
if (speed != null) {
|
||||
final Bearing direction;
|
||||
if (!Double.isNaN(sentence.getTrueWindDirection())) {
|
||||
direction = new DegreeBearingImpl(sentence.getTrueWindDirection());
|
||||
} else {
|
||||
Declination declination;
|
||||
try {
|
||||
declination = declinationService.getDeclination(timePoint, position, /* timeoutForOnlineFetchInMilliseconds */ 1000);
|
||||
if (declination != null) {
|
||||
direction = new DegreeBearingImpl(sentence.getMagneticWindDirection()).add(declination.getBearingCorrectedTo(timePoint));
|
||||
} else {
|
||||
direction = null;
|
||||
}
|
||||
if (direction != null) {
|
||||
final KnotSpeedWithBearingAndTimepoint fix = new KnotSpeedWithBearingAndTimepoint(timePoint,
|
||||
speed.getKnots(), direction);
|
||||
trueWind.add(fix);
|
||||
tryToCreateWindFixFromTrueWind(fix);
|
||||
}
|
||||
} catch (ParseException | IOException e) {
|
||||
logger.log(Level.WARNING, "Couldn't correct magnetic TWD reading by declination; ignoring", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class VTGSentenceListener extends AbstractSentenceListener<VTGSentence> {
|
||||
@Override
|
||||
public void sentenceRead(VTGSentence sentence) {
|
||||
try {
|
||||
sensorSpeeds.add(new KnotSpeedWithBearingAndTimepoint(getLastTimePoint(), sentence.getSpeedKnots(), new DegreeBearingImpl(sentence.getTrueCourse())));
|
||||
} catch (DataNotAvailableException e) {
|
||||
// no sensor speed will be recorded if data is not available
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class VWRSentenceListener extends AbstractSentenceListener<VWRSentence> {
|
||||
@Override
|
||||
public void sentenceRead(VWRSentence sentence) {
|
||||
apparentWind.add(new KnotSpeedWithBearingAndTimepoint(getLastTimePoint(), sentence.getSpeedKnots(),
|
||||
new DegreeBearingImpl(sentence.getWindAngle() * (sentence.getDirectionLeftRight()==Direction.LEFT ? -1 : 1))));
|
||||
}
|
||||
}
|
||||
|
||||
private class MDASentenceListener extends AbstractSentenceListener<MDASentence> {
|
||||
@Override
|
||||
public void sentenceRead(MDASentence sentence) {
|
||||
if (!Double.isNaN(sentence.getTrueWindDirection())) {
|
||||
if (!Double.isNaN(sentence.getWindSpeed())) {
|
||||
trueWind.add(new KnotSpeedWithBearingAndTimepoint(getLastTimePoint(), new MeterPerSecondSpeedImpl(sentence.getWindSpeed()).getKnots(),
|
||||
new DegreeBearingImpl(sentence.getTrueWindDirection())));
|
||||
} else if (!Double.isNaN(sentence.getWindSpeedKnots())) {
|
||||
trueWind.add(new KnotSpeedWithBearingAndTimepoint(getLastTimePoint(), sentence.getWindSpeedKnots(),
|
||||
new DegreeBearingImpl(sentence.getTrueWindDirection())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class HeadingSentenceListener extends AbstractSentenceListener<HeadingSentence> {
|
||||
@Override
|
||||
public void sentenceRead(HeadingSentence sentence) {
|
||||
if (getLastTimePoint() != null) {
|
||||
if (sentence.isTrue()) {
|
||||
try {
|
||||
trueHeadings.add(new DegreeBearingWithTimepoint(getLastTimePoint(), sentence.getHeading()));
|
||||
} catch (DataNotAvailableException e) {
|
||||
// ignore; in this case, no true heading will be recorded
|
||||
}
|
||||
} else {
|
||||
final Position position = getPosition(getLastTimePoint());
|
||||
if (position != null) {
|
||||
try {
|
||||
final Declination declination = declinationService.getDeclination(getLastTimePoint(), position, /* timeoutForOnlineFetchInMilliseconds */ 1000);
|
||||
if (declination != null) {
|
||||
try {
|
||||
trueHeadings.add(new DegreeBearingWithTimepoint(getLastTimePoint(),
|
||||
new DegreeBearingImpl(sentence.getHeading()).add(declination.getBearingCorrectedTo(getLastTimePoint())).getDegrees()));
|
||||
} catch (DataNotAvailableException e) {
|
||||
// no true heading will be created if data is not available
|
||||
}
|
||||
}
|
||||
} catch (IOException | ParseException e) {
|
||||
logger.log(Level.WARNING, "Error trying to obtain magnetic declination while converting magnetic heading to true heading", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DateListener extends AbstractSentenceListener<DateSentence> {
|
||||
@Override
|
||||
public void sentenceRead(DateSentence sentence) {
|
||||
try {
|
||||
final Date date = sentence.getDate();
|
||||
utcCalendar.set(date.getYear(), date.getMonth() - 1, date.getDay());
|
||||
dateReceived = true;
|
||||
} catch (DataNotAvailableException | IllegalArgumentException e) {
|
||||
// can happen; ignore sentence
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TimeListener extends AbstractSentenceListener<TimeSentence> {
|
||||
@Override
|
||||
public void sentenceRead(TimeSentence sentence) {
|
||||
try {
|
||||
final Time time = sentence.getTime();
|
||||
utcCalendar.set(utcCalendar.get(Calendar.YEAR), utcCalendar.get(Calendar.MONTH), utcCalendar.get(Calendar.DAY_OF_MONTH),
|
||||
time.getHour(), time.getMinutes(), (int) time.getSeconds());
|
||||
final int millisInSecond = (int) ((time.getSeconds()-(int) time.getSeconds())*1000);
|
||||
utcCalendar.set(Calendar.MILLISECOND, millisInSecond);
|
||||
timeReceived = true;
|
||||
} catch (DataNotAvailableException e) {
|
||||
// can happen; ignore sentence
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PositionListener extends AbstractSentenceListener<PositionSentence> {
|
||||
@Override
|
||||
public void sentenceRead(PositionSentence sentence) {
|
||||
if (sentence instanceof TimeSentence) { // all PositionSentence implementations currently also implement TimeSentence
|
||||
TimeSentence timeSentence = (TimeSentence) sentence;
|
||||
// now make sure we work with the latest time from this record:
|
||||
new TimeListener().sentenceRead(timeSentence);
|
||||
final TimePoint timePoint = getLastTimePoint();
|
||||
if (timePoint != null) {
|
||||
try {
|
||||
final GPSFix fix = new GPSFixImpl(getPosition(sentence), timePoint);
|
||||
sensorPositions.add(fix);
|
||||
} catch (DataNotAvailableException e) {
|
||||
// no sensor position is recorded in this case
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Position getPosition(PositionSentence sentence) throws DataNotAvailableException {
|
||||
return new DegreePosition(
|
||||
Math.abs(sentence.getPosition().getLatitude())*(sentence.getPosition().getLatitudeHemisphere()==CompassPoint.NORTH?1:-1),
|
||||
Math.abs(sentence.getPosition().getLongitude())*(sentence.getPosition().getLongitudeHemisphere()==CompassPoint.EAST?1:-1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sentenceReader
|
||||
* The reader that this receiver will listen to for those NMEA sentences of interest for the construction
|
||||
* of wind fixes
|
||||
*/
|
||||
public NMEAWindReceiverImpl(SentenceReader sentenceReader) {
|
||||
super();
|
||||
utcCalendar = new GregorianCalendar();
|
||||
utcCalendar.setTimeZone(TimeZone.getTimeZone(ZoneId.of("UTC")));
|
||||
this.listeners = new ConcurrentHashMap<>();
|
||||
this.trueWind = new DynamicTrackImpl<>("trueWind in "+getClass().getName());
|
||||
this.apparentWind = new DynamicTrackImpl<>("apparentWind in "+getClass().getName());
|
||||
this.sensorPositions = new DynamicTrackImpl<>("measurementPositions in "+getClass().getName());
|
||||
this.sensorSpeeds = new DynamicTrackImpl<>("sensorSpeeds in "+getClass().getName());
|
||||
this.trueHeadings = new DynamicTrackImpl<>("trueHeadings in "+getClass().getName());
|
||||
sentenceReader.addSentenceListener(new MWVSentenceListener(), SentenceId.MWV);
|
||||
sentenceReader.addSentenceListener(new MWDSentenceListener(), SentenceId.MWD);
|
||||
sentenceReader.addSentenceListener(new VWRSentenceListener(), SentenceId.VWR);
|
||||
sentenceReader.addSentenceListener(new MDASentenceListener(), SentenceId.MDA);
|
||||
sentenceReader.addSentenceListener(new VTGSentenceListener(), SentenceId.VTG);
|
||||
sentenceReader.addSentenceListener(new HeadingSentenceListener());
|
||||
sentenceReader.addSentenceListener(new DateListener());
|
||||
sentenceReader.addSentenceListener(new TimeListener());
|
||||
sentenceReader.addSentenceListener(new PositionListener());
|
||||
}
|
||||
|
||||
private Speed createSpeed(Units speedUnit, double amount) {
|
||||
final Speed result;
|
||||
switch (speedUnit) {
|
||||
case KMH:
|
||||
result = new KilometersPerHourSpeedImpl(amount);
|
||||
break;
|
||||
case KNOT:
|
||||
result = new KnotSpeedImpl(amount);
|
||||
break;
|
||||
case METER:
|
||||
result = new MeterPerSecondSpeedImpl(amount);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unknown speed unit: "+speedUnit);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called when new true wind evidence has been received for {@code timePoint}. Creates a {@link Wind} fix when
|
||||
* enough data is available, in particular position data. If this is the case, the wind fix generated will be passed
|
||||
* to {@link #notifyListeners(Wind)}.
|
||||
*/
|
||||
private void tryToCreateWindFixFromTrueWind(TimedSpeedWithBearing trueWind) {
|
||||
final com.sap.sailing.domain.common.Position position = getPosition(trueWind.getTimePoint());
|
||||
if (position != null) {
|
||||
final Wind wind = new WindImpl(position, trueWind.getTimePoint(), trueWind);
|
||||
notifyListeners(wind);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called when new apparent wind evidence has been received for {@code timePoint}. Creates a {@link Wind} fix
|
||||
* when enough data is available, such as motion and heading data required to turn the apparent wind fix into a true
|
||||
* wind fix, as well as position data, motion and heading. If this is the case, the wind fix generated will be
|
||||
* passed to {@link #notifyListeners(Wind)}.
|
||||
*/
|
||||
private void tryToCreateWindFixFromApparentWind(TimedSpeedWithBearing apparentWind) {
|
||||
final com.sap.sailing.domain.common.Position position = getPosition(apparentWind.getTimePoint());
|
||||
if (position != null) {
|
||||
final SpeedWithBearing sensorSpeed = sensorSpeeds.getInterpolatedValue(getLastTimePoint(), fix->new ScalableSpeedWithBearing(fix));
|
||||
if (sensorSpeed != null) {
|
||||
final Bearing trueHeading = trueHeadings.getInterpolatedValue(getLastTimePoint(), fix->new ScalableBearing(fix));
|
||||
if (trueHeading != null) {
|
||||
final SpeedWithBearing apparentWindTrue = new KnotSpeedWithBearingImpl(apparentWind.getKnots(), apparentWind.getBearing().add(trueHeading));
|
||||
final SpeedWithBearing trueWind = apparentWindTrue.add(sensorSpeed); // this subtracts the induced wind which is the sensorSpeed reversed
|
||||
final Wind wind = new WindImpl(position, apparentWind.getTimePoint(), trueWind);
|
||||
notifyListeners(wind);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the sequence of messages received from the reader, a "current" time point is approximated whenever a
|
||||
* {@link TimeSentence} or {@link DateSentence} or some time zone information as in a {@link ZDASentence} is
|
||||
* received. Several messages that are of interest for wind fix construction do not carry their own time stamp
|
||||
* information. For those, the time point inferred from the last {@link TimeSentence} is used which is what this
|
||||
* method returns.
|
||||
*
|
||||
* @return the last {@link TimePoint} inferred from the combination of {@link TimeSentence}, {@link DateSentence}
|
||||
* and {@link ZDASentence}, or {@code null} in case not enough information about timing has been received
|
||||
* yet.
|
||||
*/
|
||||
private TimePoint getLastTimePoint() {
|
||||
final TimePoint result;
|
||||
if (dateReceived && timeReceived) {
|
||||
result = new MillisecondsTimePoint(utcCalendar.getTime());
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private com.sap.sailing.domain.common.Position getPosition(TimePoint timePoint) {
|
||||
return sensorPositions.getInterpolatedValue(timePoint, gpsFix->new ScalablePosition(gpsFix.getPosition()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWindListener(WindListener listener) {
|
||||
listeners.put(listener, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeWindListener(WindListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
private void notifyListeners(Wind wind) {
|
||||
for (WindListener listener : listeners.values()) {
|
||||
listener.windDataReceived(wind);
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
package com.sap.sailing.nmeaconnector.impl;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.tracking.WindListener;
|
||||
import com.sap.sailing.nmeaconnector.NMEAWindReceiver;
|
||||
import com.sap.sailing.nmeaconnector.NmeaFactory;
|
||||
import com.sap.sailing.nmeaconnector.NmeaUtil;
|
||||
|
||||
import net.sf.marineapi.nmea.event.AbstractSentenceListener;
|
||||
import net.sf.marineapi.nmea.io.SentenceReader;
|
||||
import net.sf.marineapi.nmea.sentence.Sentence;
|
||||
|
||||
public class NmeaFactoryImpl implements NmeaFactory {
|
||||
|
||||
@Override
|
||||
public NmeaUtil getUtil() {
|
||||
return new NmeaUtilImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Wind> readWind(InputStream inputStream) throws InterruptedException {
|
||||
final CountDownLatch finishedLatch = new CountDownLatch(1);
|
||||
final List<Wind> result = new ArrayList<>();
|
||||
final SentenceReader sentenceReader = new SentenceReader(inputStream);
|
||||
sentenceReader.addSentenceListener(new AbstractSentenceListener<Sentence>() {
|
||||
@Override
|
||||
public void readingStopped() {
|
||||
finishedLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sentenceRead(Sentence sentence) {}
|
||||
});
|
||||
final NMEAWindReceiver receiver = new NMEAWindReceiverImpl(sentenceReader);
|
||||
receiver.addWindListener(new WindListener() {
|
||||
@Override
|
||||
public void windDataReceived(Wind wind) {
|
||||
result.add(wind);
|
||||
}
|
||||
@Override public void windDataRemoved(Wind wind) {}
|
||||
@Override public void windAveragingChanged(long oldMillisecondsOverWhichToAverage, long newMillisecondsOverWhichToAverage) {}
|
||||
});
|
||||
sentenceReader.start();
|
||||
finishedLatch.await();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Executable
+118
@@ -0,0 +1,118 @@
|
||||
package com.sap.sailing.nmeaconnector.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.sap.sailing.domain.base.impl.KilometersPerHourSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Wind;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.KilometersPerHourSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.WindImpl;
|
||||
import com.sap.sailing.nmeaconnector.NmeaUtil;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
import net.sf.marineapi.nmea.parser.SentenceFactory;
|
||||
import net.sf.marineapi.nmea.parser.SentenceParser;
|
||||
import net.sf.marineapi.nmea.sentence.MWVSentence;
|
||||
import net.sf.marineapi.nmea.util.Units;
|
||||
|
||||
public class NmeaUtilImpl implements NmeaUtil {
|
||||
private static Map<String, Class<? extends SentenceParser>> proprietaryParsers;
|
||||
|
||||
static {
|
||||
proprietaryParsers = new HashMap<>();
|
||||
proprietaryParsers.put("BAT", BATParser.class);
|
||||
proprietaryParsers.put("AAM", AAMParser.class);
|
||||
proprietaryParsers.put("GLC", GLCParser.class);
|
||||
proprietaryParsers.put("BWC", BWCParser.class);
|
||||
proprietaryParsers.put("BWR", BWRParser.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAdditionalParsers() {
|
||||
SentenceFactory sentenceFactory = SentenceFactory.getInstance();
|
||||
for (Entry<String, Class<? extends SentenceParser>> e : proprietaryParsers.entrySet()) {
|
||||
if (!sentenceFactory.hasParser(e.getKey())) {
|
||||
sentenceFactory.registerParser(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterAdditionalParsers() {
|
||||
SentenceFactory sentenceFactory = SentenceFactory.getInstance();
|
||||
for (Entry<String, Class<? extends SentenceParser>> e : proprietaryParsers.entrySet()) {
|
||||
if (!sentenceFactory.hasParser(e.getKey())) {
|
||||
sentenceFactory.unregisterParser(e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wind getWind(TimePoint timePoint, Position position, MWVSentence mwvSentence) {
|
||||
return new WindImpl(position, timePoint, new KnotSpeedWithBearingImpl(mwvSentence.getSpeed(),
|
||||
new DegreeBearingImpl(mwvSentence.getAngle())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Speed getSpeed(double magnitude, Units unit) {
|
||||
switch (unit) {
|
||||
case KMH:
|
||||
return new KilometersPerHourSpeedImpl(magnitude);
|
||||
case KNOT:
|
||||
return new KnotSpeedImpl(magnitude);
|
||||
case METER:
|
||||
return new KilometersPerHourSpeedImpl(magnitude * 3.6);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unit "+unit+" not understood for a speed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeedWithBearing getSpeedWithBearing(double speedMagnitude, Units speedUnit, double bearingInDegrees) {
|
||||
Bearing bearing = new DegreeBearingImpl(bearingInDegrees);
|
||||
switch (speedUnit) {
|
||||
case KMH:
|
||||
return new KilometersPerHourSpeedWithBearingImpl(speedMagnitude, bearing);
|
||||
case KNOT:
|
||||
return new KnotSpeedWithBearingImpl(speedMagnitude, bearing);
|
||||
case METER:
|
||||
return new KilometersPerHourSpeedWithBearingImpl(speedMagnitude * 3.6, bearing);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unit "+speedUnit+" not understood for a speed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String replace(String nmeaSentence, String regexToFind, String replaceWith) {
|
||||
while (nmeaSentence.matches(".*" + regexToFind + ".*")) {
|
||||
final String resultWithOldChecksum = nmeaSentence.replaceFirst(regexToFind, replaceWith);
|
||||
if (resultWithOldChecksum.matches(".*\\*[0-9a-fA-F][0-9a-fA-F]$")) {
|
||||
// found checksum
|
||||
int checksum = Integer.valueOf(resultWithOldChecksum.substring(resultWithOldChecksum.length() - 2), 16);
|
||||
for (char oldChar : regexToFind.toCharArray()) {
|
||||
checksum ^= (byte) oldChar;
|
||||
}
|
||||
for (char newChar : replaceWith.toCharArray()) {
|
||||
checksum ^= (byte) newChar;
|
||||
}
|
||||
String newHexChecksum = Integer.toHexString(checksum).toUpperCase();
|
||||
if (newHexChecksum.length() == 1) {
|
||||
newHexChecksum = "0" + newHexChecksum;
|
||||
}
|
||||
nmeaSentence = resultWithOldChecksum.substring(0, resultWithOldChecksum.length() - 2) + newHexChecksum;
|
||||
} else {
|
||||
nmeaSentence = resultWithOldChecksum;
|
||||
}
|
||||
}
|
||||
return nmeaSentence;
|
||||
}
|
||||
|
||||
}
|
||||
+28
-1
@@ -2,15 +2,32 @@ package com.sap.sailing.server.gateway.deserialization.impl;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.SharedDomainFactory;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.statistics.Statistics;
|
||||
import com.sap.sailing.domain.statistics.impl.StatisticsImpl;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.StatisticsJsonSerializer;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
|
||||
public class StatisticsJsonDeserializer implements JsonDeserializer<Statistics> {
|
||||
|
||||
private final CompetitorJsonDeserializer competitorJsonDeserializer;
|
||||
|
||||
public static StatisticsJsonDeserializer create(SharedDomainFactory baseDomainFactory) {
|
||||
return new StatisticsJsonDeserializer(CompetitorJsonDeserializer.create(baseDomainFactory));
|
||||
}
|
||||
|
||||
private StatisticsJsonDeserializer(CompetitorJsonDeserializer competitorJsonDeserializer) {
|
||||
this.competitorJsonDeserializer = competitorJsonDeserializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statistics deserialize(JSONObject object) throws JsonDeserializationException {
|
||||
@@ -21,7 +38,17 @@ public class StatisticsJsonDeserializer implements JsonDeserializer<Statistics>
|
||||
long gpsFixes = getLongValue(object, StatisticsJsonSerializer.FIELD_NUMBER_OF_GPS_FIXES);
|
||||
long windFixes = getLongValue(object, StatisticsJsonSerializer.FIELD_NUMBER_OF_WIND_FIXES);
|
||||
Distance distance = new MeterDistance(getDoubleValue(object, StatisticsJsonSerializer.FIELD_DISTANCE_TRAVELED_IN_METERS));
|
||||
return new StatisticsImpl(competitors, regattas, races, trackedRaces, gpsFixes, windFixes, distance);
|
||||
JSONObject maxSpeedObject = (JSONObject) object.get(StatisticsJsonSerializer.FIELD_MAX_SPEED);
|
||||
final Triple<Competitor, Speed, TimePoint> maxSpeed;
|
||||
if (maxSpeedObject != null) {
|
||||
final Competitor fastestCompetitor = competitorJsonDeserializer.deserialize((JSONObject) maxSpeedObject.get(StatisticsJsonSerializer.FIELD_FASTEST_COMPETITOR));
|
||||
final Speed fastestCompetitorSpeed = new KnotSpeedImpl(getDoubleValue(maxSpeedObject, StatisticsJsonSerializer.FIELD_FASTEST_COMPETITOR_SPEED_IN_KNOTS));
|
||||
final TimePoint timePoint = new MillisecondsTimePoint(getLongValue(maxSpeedObject, StatisticsJsonSerializer.FIELD_TIMEPOINT_MILLIS));
|
||||
maxSpeed = new Triple<Competitor, Speed, TimePoint>(fastestCompetitor, fastestCompetitorSpeed, timePoint);
|
||||
} else {
|
||||
maxSpeed = null;
|
||||
}
|
||||
return new StatisticsImpl(competitors, regattas, races, trackedRaces, gpsFixes, windFixes, distance, maxSpeed);
|
||||
}
|
||||
|
||||
private int getIntValue(JSONObject object, String field) {
|
||||
|
||||
+20
@@ -2,8 +2,12 @@ package com.sap.sailing.server.gateway.serialization.impl;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.statistics.Statistics;
|
||||
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
|
||||
public class StatisticsJsonSerializer implements JsonSerializer<Statistics> {
|
||||
|
||||
@@ -14,6 +18,12 @@ public class StatisticsJsonSerializer implements JsonSerializer<Statistics> {
|
||||
public static final String FIELD_NUMBER_OF_GPS_FIXES = "numberOfGPSFixes";
|
||||
public static final String FIELD_NUMBER_OF_WIND_FIXES = "numberOfWindFixes";
|
||||
public static final String FIELD_DISTANCE_TRAVELED_IN_METERS = "distanceTraveledInMeters";
|
||||
public static final String FIELD_MAX_SPEED = "maxSpeed";
|
||||
public static final String FIELD_FASTEST_COMPETITOR = "fastestCompetitor";
|
||||
public static final String FIELD_FASTEST_COMPETITOR_SPEED_IN_KNOTS = "fastestCompetitorSpeedInKnots";
|
||||
public static final String FIELD_TIMEPOINT_MILLIS = "timepointMillis";
|
||||
|
||||
private final CompetitorJsonSerializer competitorJsonSerializer = CompetitorJsonSerializer.create();
|
||||
|
||||
@Override
|
||||
public JSONObject serialize(Statistics object) {
|
||||
@@ -25,6 +35,16 @@ public class StatisticsJsonSerializer implements JsonSerializer<Statistics> {
|
||||
result.put(FIELD_NUMBER_OF_GPS_FIXES, object.getNumberOfGPSFixes());
|
||||
result.put(FIELD_NUMBER_OF_WIND_FIXES, object.getNumberOfWindFixes());
|
||||
result.put(FIELD_DISTANCE_TRAVELED_IN_METERS, object.getDistanceTraveled().getMeters());
|
||||
final Triple<Competitor, Speed, TimePoint> maxSpeed = object.getMaxSpeed();
|
||||
if (maxSpeed != null) {
|
||||
JSONObject maxSpeedObject = new JSONObject();
|
||||
|
||||
maxSpeedObject.put(FIELD_FASTEST_COMPETITOR, competitorJsonSerializer.serialize(maxSpeed.getA()));
|
||||
maxSpeedObject.put(FIELD_FASTEST_COMPETITOR_SPEED_IN_KNOTS, maxSpeed.getB().getKnots());
|
||||
maxSpeedObject.put(FIELD_TIMEPOINT_MILLIS, maxSpeed.getC().asMillis());
|
||||
|
||||
result.put(FIELD_MAX_SPEED, maxSpeedObject);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.sap.sse.datamining.shared;bundle-version="1.0.0",
|
||||
com.sap.sailing.datamining,
|
||||
com.sap.sailing.server,
|
||||
com.sap.sailing.grib
|
||||
com.sap.sailing.grib,
|
||||
com.sap.sailing.nmeaconnector
|
||||
Bundle-ClassPath: .
|
||||
Web-ContextPath: /sailingserver
|
||||
Export-Package: com.sap.sailing.server.gateway,
|
||||
|
||||
@@ -131,7 +131,16 @@
|
||||
<url-pattern>/grib-wind-import</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet>
|
||||
<servlet-name>NmeaWindImportServlet</servlet-name>
|
||||
<servlet-class>com.sap.sailing.server.gateway.windimport.nmea.NmeaWindImportServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>NmeaWindImportServlet</servlet-name>
|
||||
<url-pattern>/nmea-wind-import</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>ExpeditionWindMeasureStatusGetServlet</servlet-name>
|
||||
<servlet-class>com.sap.sailing.server.gateway.impl.ExpeditionWindMeasureStatusGetServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
+1
-1
@@ -198,7 +198,7 @@ public abstract class AbstractWindImportServlet extends SailingServerHttpServlet
|
||||
response.getWriter().append(windImportResult.json().toJSONString());
|
||||
}
|
||||
|
||||
protected abstract Iterable<Wind> importWind(Map<InputStream, String> streamsWithFilenames) throws IOException;
|
||||
protected abstract Iterable<Wind> importWind(Map<InputStream, String> streamsWithFilenames) throws IOException, InterruptedException;
|
||||
|
||||
protected abstract WindSource getWindSource(UploadRequest uploadRequest);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user