diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-06-30 18:48:43 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-06-30 18:48:43 +0000 |
| commit | af1232773fd525ecd6f6ad434346673139d0d183 (patch) | |
| tree | 2c07c33d9e3daa59031053cf9af00b4ffadbfabc /android-app | |
| parent | ddfeae7a5f109fc4e993e6697b961ea652360fc2 (diff) | |
feat(fishing): dashed bearing line on map for fishing target
Adds setupFishingLayer() and updateFishingBearing() to MapHandler with
destinationPoint() haversine helper. Draws dashed orange line from boat
toward the computed fishing target bearing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'android-app')
| -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 |
