summaryrefslogtreecommitdiff
path: root/android-app/app/src/main
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-05-20 22:24:57 +0000
committerClaude <noreply@anthropic.com>2026-05-20 22:24:57 +0000
commit76f8707b777d7e25b5ba763ac84416d8b327c215 (patch)
tree66e27ea7b923b00c6b318b8a3b4713fcc3d1917c /android-app/app/src/main
parent62cc93086498d57ef7298eddb40cc382dfc10c6d (diff)
Color track lines by boat speed using MapLibre data-driven styling
Each focused track is rendered as per-segment LineStrings tagged with average SOG, interpolated blue→cyan→green→amber→red for 0→13+ knots. Applies to both the main map focus layer and the track detail sheet. https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
Diffstat (limited to 'android-app/app/src/main')
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/track/TrackColors.kt35
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt6
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/ui/MapHandler.kt12
3 files changed, 43 insertions, 10 deletions
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/track/TrackColors.kt b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackColors.kt
new file mode 100644
index 0000000..3bcabb1
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackColors.kt
@@ -0,0 +1,35 @@
+package org.terst.nav.track
+
+import android.graphics.Color
+import org.maplibre.android.style.expressions.Expression
+import org.maplibre.android.style.layers.PropertyFactory
+import org.maplibre.geojson.Feature
+import org.maplibre.geojson.FeatureCollection
+import org.maplibre.geojson.LineString
+import org.maplibre.geojson.Point
+
+/** Breaks [points] into consecutive 2-point LineString Features, each tagged with "speed" (knots). */
+fun speedSegments(points: List<TrackPoint>): List<Feature> =
+ (0 until points.size - 1).map { i ->
+ val sog = (points[i].sogKnots + points[i + 1].sogKnots) / 2.0
+ Feature.fromGeometry(
+ LineString.fromLngLats(listOf(
+ Point.fromLngLat(points[i].lon, points[i].lat),
+ Point.fromLngLat(points[i + 1].lon, points[i + 1].lat)
+ ))
+ ).apply { addNumberProperty("speed", sog) }
+ }
+
+/**
+ * MapLibre expression that interpolates line-color from the "speed" feature property.
+ * Scale: 0 kt → blue · 4 kt → cyan · 7 kt → green · 10 kt → amber · 13+ kt → red.
+ */
+fun speedColorExpression(): Expression = Expression.interpolate(
+ Expression.linear(),
+ Expression.get("speed"),
+ Expression.stop(0, Expression.color(Color.parseColor("#2196F3"))), // blue
+ Expression.stop(4, Expression.color(Color.parseColor("#00BCD4"))), // cyan
+ Expression.stop(7, Expression.color(Color.parseColor("#4CAF50"))), // green
+ Expression.stop(10, Expression.color(Color.parseColor("#FFC107"))), // amber
+ Expression.stop(13, Expression.color(Color.parseColor("#F44336"))) // red
+)
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt
index cedf4e1..6f3ed82 100644
--- a/android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt
+++ b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt
@@ -102,14 +102,14 @@ class TrackDetailSheet : Fragment() {
private fun drawTrack(style: Style, points: List<TrackPoint>) {
if (points.size < 2) return
val source = GeoJsonSource("track-detail-source",
- Feature.fromGeometry(LineString.fromLngLats(points.map { Point.fromLngLat(it.lon, it.lat) })))
+ FeatureCollection.fromFeatures(speedSegments(points)))
style.addSource(source)
style.addLayer(LineLayer("track-detail-layer", "track-detail-source").apply {
setProperties(
- PropertyFactory.lineColor("#2B8FC4"),
PropertyFactory.lineWidth(4f),
PropertyFactory.lineCap("round"),
- PropertyFactory.lineJoin("round")
+ PropertyFactory.lineJoin("round"),
+ PropertyFactory.lineColor(speedColorExpression())
)
})
}
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 7614a49..17e94d0 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
@@ -328,11 +328,10 @@ class MapHandler(private val maplibreMap: MapLibreMap) {
style.addSource(trackPastFocusSource!!)
style.addLayer(LineLayer(TRACK_PAST_FOCUS_LAYER_ID, TRACK_PAST_FOCUS_SOURCE_ID).apply {
setProperties(
- PropertyFactory.lineColor("#2B8FC4"),
- PropertyFactory.lineOpacity(1.0f),
PropertyFactory.lineWidth(4f),
PropertyFactory.lineCap("round"),
- PropertyFactory.lineJoin("round")
+ PropertyFactory.lineJoin("round"),
+ PropertyFactory.lineColor(speedColorExpression())
)
})
}
@@ -363,12 +362,10 @@ class MapHandler(private val maplibreMap: MapLibreMap) {
}
}
- /** Highlights [points] in the focus layer (full-opacity bright blue over the dim layer). */
+ /** Highlights [points] in the focus layer, colored by boat speed. */
fun setFocusedTrackPoints(points: List<TrackPoint>?) {
if (points != null && points.size >= 2) {
- trackPastFocusSource?.setGeoJson(
- Feature.fromGeometry(LineString.fromLngLats(points.map { Point.fromLngLat(it.lon, it.lat) }))
- )
+ trackPastFocusSource?.setGeoJson(FeatureCollection.fromFeatures(speedSegments(points)))
} else {
trackPastFocusSource?.setGeoJson(FeatureCollection.fromFeatures(emptyList()))
}
@@ -443,3 +440,4 @@ class MapHandler(private val maplibreMap: MapLibreMap) {
return Polygon.fromLngLats(listOf(points))
}
}
+