summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt53
1 files changed, 53 insertions, 0 deletions
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt b/android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt
index 99c8ffc..6d408ed 100644
--- a/android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt
+++ b/android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt
@@ -96,6 +96,11 @@ class MapHandler(private val maplibreMap: MapLibreMap) {
private var fadSource: GeoJsonSource? = null
+ private val FISHING_LINE_SOURCE_ID = "fishing-line-source"
+ private val FISHING_LINE_LAYER_ID = "fishing-line-layer"
+ private var fishingLineSource: GeoJsonSource? = null
+ private var fishingLineStyle: Style? = null
+
private var anchorPointSource: GeoJsonSource? = null
private var anchorCircleSource: GeoJsonSource? = null
private var tidalCurrentSource: GeoJsonSource? = null
@@ -489,6 +494,54 @@ class MapHandler(private val maplibreMap: MapLibreMap) {
tackSource?.setGeoJson(FeatureCollection.fromFeatures(emptyList()))
}
+ /**
+ * Initialises the fishing bearing line layer.
+ * A dashed orange line is drawn from the boat position toward the fishing target bearing.
+ * Call once after style loads.
+ */
+ fun setupFishingLayer(style: Style) {
+ fishingLineStyle = style
+ val src = GeoJsonSource(FISHING_LINE_SOURCE_ID, FeatureCollection.fromFeatures(emptyArray()))
+ fishingLineSource = src
+ style.addSource(src)
+ style.addLayer(LineLayer(FISHING_LINE_LAYER_ID, FISHING_LINE_SOURCE_ID).apply {
+ setProperties(
+ PropertyFactory.lineColor("#FF6D00"),
+ PropertyFactory.lineWidth(2f),
+ PropertyFactory.lineDasharray(arrayOf(4f, 2f)),
+ PropertyFactory.visibility("none")
+ )
+ })
+ }
+
+ /**
+ * Updates the fishing bearing line from [lat]/[lon] toward [bearingDeg] for [lengthNm] nautical miles.
+ */
+ fun updateFishingBearing(lat: Double, lon: Double, bearingDeg: Double, lengthNm: Double = 10.0) {
+ val end = destinationPoint(lat, lon, bearingDeg, lengthNm)
+ val line = Feature.fromGeometry(
+ LineString.fromLngLats(listOf(
+ Point.fromLngLat(lon, lat),
+ Point.fromLngLat(end.second, end.first)
+ ))
+ )
+ fishingLineSource?.setGeoJson(FeatureCollection.fromFeature(line))
+ fishingLineStyle?.getLayer(FISHING_LINE_LAYER_ID)?.setProperties(
+ PropertyFactory.visibility("visible")
+ )
+ }
+
+ private fun destinationPoint(lat: Double, lon: Double, bearingDeg: Double, distanceNm: Double): Pair<Double, Double> {
+ val R = 3440.065
+ val d = distanceNm / R
+ val bear = Math.toRadians(bearingDeg)
+ val lat1r = Math.toRadians(lat)
+ val lon1r = Math.toRadians(lon)
+ val lat2r = kotlin.math.asin(kotlin.math.sin(lat1r) * kotlin.math.cos(d) + kotlin.math.cos(lat1r) * kotlin.math.sin(d) * kotlin.math.cos(bear))
+ val lon2r = lon1r + kotlin.math.atan2(kotlin.math.sin(bear) * kotlin.math.sin(d) * kotlin.math.cos(lat1r), kotlin.math.cos(d) - kotlin.math.sin(lat1r) * kotlin.math.sin(lat2r))
+ return Pair(Math.toDegrees(lat2r), Math.toDegrees(lon2r))
+ }
+
private fun createCirclePolygon(lat: Double, lon: Double, radiusMeters: Double): Polygon {
val points = mutableListOf<Point>()
val degreesBetweenPoints = 8