package au.gov.amsa.navigation; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.util.Map; import java.util.Set; import com.github.davidmoten.rx.slf4j.Logging; import com.google.common.base.Optional; import com.google.common.collect.Sets; import au.gov.amsa.navigation.ShipStaticData.Info; import au.gov.amsa.risky.format.BinaryFixes; import au.gov.amsa.risky.format.BinaryFixesFormat; import rx.functions.Func1; public class CollisionDetectorMain { public static void main(String[] args) throws IOException, InterruptedException { VesselPosition.validate = true; CollisionDetector c = new CollisionDetector(); // String filename = "/media/an/nmea/2013/NMEA_ITU_20130108.gz"; Map<Integer, Info> ships = ShipStaticData.getMapFromResource("/ship-data-2014.txt"); // nmea from file // Streams.nmeaFromGzip(filename) File file = new File("/media/an/daily-fixes/2014/2014-02-01.fix"); File candidates = new File( "/media/an/temp/" + file.getName() + ".collision-candidates.txt"); try (PrintStream out = new PrintStream(candidates)) { out.println("time,mmsi1,lat1, lon1, cog1, m/s, mmsi2, lat2, lon2, cog2, m/s"); BinaryFixes.from(file, true, BinaryFixesFormat.WITH_MMSI) .map(VesselPositions.TO_VESSEL_POSITION) .lift(Logging.<VesselPosition> logger().showCount().every(1000).showMemory() .log()) // only class A .filter(onlyClassA) // speed must b present .filter(p -> p.speedMetresPerSecond().isPresent()) // course must be present .filter(p -> p.cogDegrees().isPresent()) // ignore tugs, pilots, towing .filter(p -> { Mmsi mmsi = (Mmsi) p.id(); Optional<Info> info = Optional.fromNullable(ships.get(mmsi.value())); return (!info.isPresent() || !info.get().shipType.isPresent() || !isTugPilotTowing(info.get().shipType.get())); }) // candidates must both be moving more than N knots .filter(p -> p.speedKnots().get() >= 5) // detect collision candidates .compose(CollisionDetector.detectCollisionCandidates()) // filter // .filter(candidatesMovingWithAtLeastSpeedMetresPerSecond(5 // * 0.5144444)) // log .lift(Logging.<CollisionCandidate> logger().showCount().every(1).showValue() .showMemory().log()) .doOnNext(cc -> out.format("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s", cc.time(), cc.position1().id().uniqueId(), cc.position1().lat(), cc.position1().lon(), cc.position1().cogDegrees(), cc.position1().speedMetresPerSecond().transform(x -> String.valueOf(x)) .or(""), cc.position2().id().uniqueId(), cc.position2().lat(), cc.position2().lon(), cc.position2().cogDegrees(), cc.position2().speedMetresPerSecond().transform(x -> String.valueOf(x)) .or(""))) // count .count() // go .toBlocking().single(); } } private static final Set<Integer> tugPilotTowingShipTypes = Sets.newHashSet(31, 32, 50, 53, 52); private static boolean isTugPilotTowing(int shipType) { return tugPilotTowingShipTypes.contains(shipType); } private static Func1<CollisionCandidate, Boolean> candidatesMovingWithAtLeastSpeedMetresPerSecond( final double minSpeedMetresPerSecond) { return c -> c.position1().speedMetresPerSecond().get() >= minSpeedMetresPerSecond && c.position2().speedMetresPerSecond().get() >= minSpeedMetresPerSecond; } private static Func1<VesselPosition, Boolean> onlyClassA = p -> p.cls() == VesselClass.A; }