1 package au.gov.amsa.navigation;
2
3 import java.util.concurrent.TimeUnit;
4
5 import com.google.common.base.Optional;
6
7 import au.gov.amsa.navigation.VesselPosition.NavigationalStatus;
8 import au.gov.amsa.risky.format.AisClass;
9 import au.gov.amsa.risky.format.Fix;
10 import au.gov.amsa.risky.format.HasFix;
11 import rx.functions.Func1;
12
13 public class VesselPositions {
14
15 private static final double KNOTS_TO_METRES_PER_SECOND = 1852.0 / TimeUnit.HOURS.toSeconds(1);
16
17
18 public static VesselPosition toVesselPosition(Fix fix, Optional<?> data) {
19 return VesselPosition.builder().id(new Mmsi(fix.mmsi())).lat(fix.lat()).lon(fix.lon())
20 .time(fix.time()).cls(fix.aisClass() == AisClass.A ? VesselClass.A : VesselClass.B)
21 .cogDegrees(toDouble(fix.courseOverGroundDegrees()))
22 .headingDegrees(toDouble(fix.headingDegrees()))
23 .speedMetresPerSecond(
24 multiply(fix.speedOverGroundKnots(), KNOTS_TO_METRES_PER_SECOND))
25 .navigationalStatus(fix.navigationalStatus().isPresent()
26 ? NavigationalStatus.values()[fix.navigationalStatus().get().ordinal()]
27 : NavigationalStatus.NOT_DEFINED)
28 .positionAisNmea(Optional.<String> absent())
29 .shipStaticAisNmea(Optional.<String> absent())
30
31 .data(data)
32
33 .build();
34 }
35
36 public static Func1<HasFix, VesselPosition> TO_VESSEL_POSITION = fix -> toVesselPosition(
37 fix.fix(), Optional.absent());
38
39 public static <T extends HasFix> Func1<T, VesselPosition> toVesselPosition(
40 final Func1<T, Optional<?>> dataExtractor) {
41 return fix -> toVesselPosition(fix.fix(), dataExtractor.call(fix));
42 }
43
44 private static Optional<Double> toDouble(Optional<Float> value) {
45 if (!value.isPresent())
46 return Optional.absent();
47 else
48 return Optional.of((double) value.get());
49 }
50
51 private static Optional<Double> multiply(Optional<Float> value, double factor) {
52 if (!value.isPresent())
53 return Optional.absent();
54 else
55 return Optional.of((double) value.get() * factor);
56 }
57
58 }