diff options
Diffstat (limited to 'test-runner/src/main')
4 files changed, 68 insertions, 1 deletions
diff --git a/test-runner/src/main/kotlin/org/terst/nav/ais/CpaAlert.kt b/test-runner/src/main/kotlin/org/terst/nav/ais/CpaAlert.kt new file mode 100644 index 0000000..1d635c0 --- /dev/null +++ b/test-runner/src/main/kotlin/org/terst/nav/ais/CpaAlert.kt @@ -0,0 +1,23 @@ +package org.terst.nav.ais + +enum class CpaSeverity { CAUTION, WARNING, DANGER } + +data class CpaAlert( + val mmsi: Int, + val vesselName: String, + val cpaNm: Double, + val tcpaMin: Double, + val severity: CpaSeverity +) + +object CpaThresholds { + const val DANGER_CPA_NM = 0.5 + const val WARNING_CPA_NM = 1.0 + const val CAUTION_CPA_NM = 2.0 + const val MAX_TCPA_MIN = 30.0 // ignore contacts closing in > 30 min +} + +fun CpaAlert.label(): String { + val name = if (vesselName.isNotBlank()) vesselName else "MMSI $mmsi" + return "%-12s CPA %.1fnm T+%.0fmin".format(name.take(12), cpaNm, tcpaMin) +} diff --git a/test-runner/src/main/kotlin/org/terst/nav/ais/CpaCalculator.kt b/test-runner/src/main/kotlin/org/terst/nav/ais/CpaCalculator.kt index 7e98451..298af59 100644 --- a/test-runner/src/main/kotlin/org/terst/nav/ais/CpaCalculator.kt +++ b/test-runner/src/main/kotlin/org/terst/nav/ais/CpaCalculator.kt @@ -2,7 +2,6 @@ package org.terst.nav.ais import kotlin.math.cos import kotlin.math.sqrt -import kotlin.math.PI object CpaCalculator { fun compute( diff --git a/test-runner/src/main/kotlin/org/terst/nav/track/TrackRepository.kt b/test-runner/src/main/kotlin/org/terst/nav/track/TrackRepository.kt index 7953822..a68e315 100644 --- a/test-runner/src/main/kotlin/org/terst/nav/track/TrackRepository.kt +++ b/test-runner/src/main/kotlin/org/terst/nav/track/TrackRepository.kt @@ -1,5 +1,10 @@ package org.terst.nav.track +import kotlin.math.atan2 +import kotlin.math.cos +import kotlin.math.sin +import kotlin.math.sqrt + class TrackRepository { var isRecording: Boolean = false @@ -23,4 +28,29 @@ class TrackRepository { } fun getPoints(): List<TrackPoint> = points.toList() + + fun computeStats(): TrackStats? { + if (points.size < 2) return null + var distNm = 0.0 + for (i in 1 until points.size) { + distNm += haversineNm(points[i - 1].lat, points[i - 1].lon, points[i].lat, points[i].lon) + } + val durationMs = points.last().timestampMs - points.first().timestampMs + val avgSog = if (durationMs > 0) { + points.map { it.sogKnots }.average() + } else 0.0 + return TrackStats(distNm, durationMs, avgSog) + } + + companion object { + fun haversineNm(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Double { + val r = 3440.065 // Earth radius in nautical miles + val dLat = Math.toRadians(lat2 - lat1) + val dLon = Math.toRadians(lon2 - lon1) + val a = sin(dLat / 2) * sin(dLat / 2) + + cos(Math.toRadians(lat1)) * cos(Math.toRadians(lat2)) * + sin(dLon / 2) * sin(dLon / 2) + return r * 2 * atan2(sqrt(a), sqrt(1 - a)) + } + } } diff --git a/test-runner/src/main/kotlin/org/terst/nav/track/TrackStats.kt b/test-runner/src/main/kotlin/org/terst/nav/track/TrackStats.kt new file mode 100644 index 0000000..39153c6 --- /dev/null +++ b/test-runner/src/main/kotlin/org/terst/nav/track/TrackStats.kt @@ -0,0 +1,15 @@ +package org.terst.nav.track + +data class TrackStats( + val distanceNm: Double, + val durationMs: Long, + val avgSogKnots: Double +) { + val durationFormatted: String get() { + val totalSec = durationMs / 1000 + val h = totalSec / 3600 + val m = (totalSec % 3600) / 60 + val s = totalSec % 60 + return if (h > 0) "%d:%02d:%02d".format(h, m, s) else "%d:%02d".format(m, s) + } +} |
