diff options
| -rw-r--r-- | android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt | 53 |
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 |
