From b166e896c2614d6551459356d555a0be8fff4e5f Mon Sep 17 00:00:00 2001 From: Arty Bishop Date: Sun, 26 Apr 2026 14:32:16 +0100 Subject: [PATCH] Added current moon/sun positions to the RadarScreen --- .../core/domain/predict/CelestialComputer.kt | 2 +- .../look4sat/feature/radar/RadarScreen.kt | 4 +- .../look4sat/feature/radar/RadarState.kt | 3 + .../look4sat/feature/radar/RadarView.kt | 59 ++++++++++++++++--- .../look4sat/feature/radar/RadarViewModel.kt | 14 ++++- 5 files changed, 72 insertions(+), 10 deletions(-) diff --git a/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/predict/CelestialComputer.kt b/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/predict/CelestialComputer.kt index 62f008b4..5dc4f19c 100644 --- a/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/predict/CelestialComputer.kt +++ b/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/predict/CelestialComputer.kt @@ -114,7 +114,7 @@ object CelestialComputer { distance = 1.0 + ((obsSet[2] - ASTRONOMICAL_UNIT) / ASTRONOMICAL_UNIT), rangeRate = 1000.0 * obsSet[3], latitude = latLon[0].toDegrees(), - longitude = 360.0 - latLon[1].toDegrees(), + longitude = latLon[1].toDegrees().let { if (it > 180.0) it - 360.0 else it }, rightAscension = raDec[0].toDegrees(), declination = raDec[1].toDegrees() ) diff --git a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarScreen.kt b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarScreen.kt index dc016494..79604309 100644 --- a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarScreen.kt +++ b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarScreen.kt @@ -180,7 +180,9 @@ private fun RadarCard(uiState: RadarState, modifier: Modifier = Modifier) { azimElev = uiState.orientationValues, shouldShowSweep = uiState.shouldShowSweep, shouldUseCompass = uiState.shouldUseCompass, - modifier = Modifier.align(Alignment.Center) + modifier = Modifier.align(Alignment.Center), + sunPosition = uiState.sunPosition, + moonPosition = uiState.moonPosition, ) PositionOverlay(position) } diff --git a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarState.kt b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarState.kt index 21dcfa80..22702a18 100644 --- a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarState.kt +++ b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarState.kt @@ -18,6 +18,7 @@ package com.rtbishop.look4sat.feature.radar import com.rtbishop.look4sat.core.domain.model.SatRadio +import com.rtbishop.look4sat.core.domain.predict.CelestialComputer import com.rtbishop.look4sat.core.domain.predict.OrbitalPass import com.rtbishop.look4sat.core.domain.predict.OrbitalPos @@ -32,6 +33,8 @@ data class RadarState( val satTrack: List = emptyList(), val shouldShowSweep: Boolean = false, val shouldUseCompass: Boolean = false, + val sunPosition: CelestialComputer.SunPosition? = null, + val moonPosition: CelestialComputer.MoonPosition? = null, val transmitters: List = emptyList(), val selectedTransmitterUuid: String? = null, val selectedFrequency: Long? = null diff --git a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarView.kt b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarView.kt index a3590beb..74772f18 100644 --- a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarView.kt +++ b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarView.kt @@ -32,6 +32,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Path import androidx.compose.ui.graphics.PathEffect @@ -44,14 +45,19 @@ import androidx.compose.ui.graphics.drawscope.Fill import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.rotate import androidx.compose.ui.graphics.drawscope.translate +import androidx.compose.ui.graphics.drawscope.withTransform +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextMeasurer import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.drawText import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.unit.sp +import com.rtbishop.look4sat.core.domain.predict.CelestialComputer import com.rtbishop.look4sat.core.domain.predict.OrbitalPos import com.rtbishop.look4sat.core.domain.predict.PI_2 import com.rtbishop.look4sat.core.domain.utility.toRadians +import com.rtbishop.look4sat.core.presentation.R import kotlin.math.cos import kotlin.math.sin @@ -66,11 +72,14 @@ fun RadarViewCompose( azimElev: Pair, shouldShowSweep: Boolean, shouldUseCompass: Boolean, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + sunPosition: CelestialComputer.SunPosition? = null, + moonPosition: CelestialComputer.MoonPosition? = null, ) { - val radarColor = MaterialTheme.colorScheme.secondary - val trackColor = MaterialTheme.colorScheme.primary val aimColor = MaterialTheme.colorScheme.error + val primaryColor = MaterialTheme.colorScheme.primary + val radarColor = MaterialTheme.colorScheme.secondary + val sunColor = MaterialTheme.colorScheme.primary val animTransition = rememberInfiniteTransition(label = "animScale") val animScale by animTransition.animateFloat( initialValue = 16f, @@ -79,6 +88,8 @@ fun RadarViewCompose( label = "animScale" ) val measurer = rememberTextMeasurer() + val sunPainter = painterResource(R.drawable.ic_sun) + val moonPainter = painterResource(R.drawable.ic_moon) var sweepDegrees by remember { mutableFloatStateOf(0f) } var cachedRadius by remember { mutableFloatStateOf(0f) } var trackPath by remember { mutableStateOf(Path()) } @@ -92,13 +103,26 @@ fun RadarViewCompose( cachedRadius = radius } rotate(if (shouldUseCompass) -azimElev.first else 0f) { - if (shouldShowSweep) drawSweep(center, sweepDegrees, radius, trackColor) + if (shouldShowSweep) drawSweep(center, sweepDegrees, radius, primaryColor) drawRadar(radius, radarColor) - drawElevationLabels(radius, trackColor, measurer) + drawElevationLabels(radius, primaryColor, measurer) translate(center.x, center.y) { - drawTrack(trackPath, trackEffect, aimColor, trackColor) + drawTrack(trackPath, trackEffect, aimColor, primaryColor) if (item.elevation > 0) { - drawPosition(item, radius, animScale, trackColor) + drawPosition(item, radius, animScale, primaryColor) + } + sunPosition?.let { sun -> + if (sun.elevation > 0) drawBodyIcon(sun.azimuth, sun.elevation, radius, sunColor, sunPainter, 52f) + } + moonPosition?.let { moon -> + if (moon.elevation > 0) drawBodyIcon( + moon.azimuth, + moon.elevation, + radius, + radarColor, + moonPainter, + 52f + ) } if (shouldUseCompass) drawAim(azimElev.first, azimElev.second, radius, aimColor) } @@ -180,6 +204,27 @@ private fun createTrackEffect(trackPath: Path): PathEffect { return PathEffect.stampedPathEffect(shape, trackLength / 2f, trackLength / 4f, StampedPathEffectStyle.Rotate) } +private fun DrawScope.drawBodyIcon( + azimDeg: Double, + elevDeg: Double, + radius: Float, + color: Color, + painter: Painter, + iconSize: Float +) { + val azimRad = azimDeg.toRadians() + val elevRad = elevDeg.toRadians() + val pos = sph2Cart(azimRad, elevRad, radius.toDouble()) + val half = iconSize / 2f + withTransform({ + translate(pos.x - half, pos.y - half) + }) { + with(painter) { + draw(Size(iconSize, iconSize), colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(color)) + } + } +} + private fun sph2Cart(azim: Double, elev: Double, r: Double): Offset { val radius = r * (PI_2 - elev) / PI_2 return Offset( diff --git a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarViewModel.kt b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarViewModel.kt index 6ac250ea..5ab62b77 100644 --- a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarViewModel.kt +++ b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/RadarViewModel.kt @@ -23,6 +23,7 @@ import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import com.rtbishop.look4sat.core.domain.model.SatRadio +import com.rtbishop.look4sat.core.domain.predict.CelestialComputer import com.rtbishop.look4sat.core.domain.predict.OrbitalObject import com.rtbishop.look4sat.core.domain.predict.OrbitalPos import com.rtbishop.look4sat.core.domain.repository.IContainerProvider @@ -101,9 +102,20 @@ class RadarViewModel( while (isActive) { val timeNow = System.currentTimeMillis() val pos = satelliteRepo.getPosition(satPass.orbitalObject, stationPos, timeNow) + val sunPos = CelestialComputer.getSunPosition(stationPos, timeNow) + val moonPos = CelestialComputer.getMoonPosition(stationPos, timeNow) val (time, isAos) = computeTimer(satPass.isDeepSpace, satPass.aosTime, satPass.losTime, timeNow) val isLos = !satPass.isDeepSpace && timeNow > satPass.losTime - _uiState.update { it.copy(currentTime = time, isTimeAos = isAos, isLos = isLos, orbitalPos = pos) } + _uiState.update { + it.copy( + currentTime = time, + isTimeAos = isAos, + isLos = isLos, + orbitalPos = pos, + sunPosition = sunPos, + moonPosition = moonPos + ) + } processRadios(transmitters, satPass.orbitalObject, timeNow) sendPassData(pos) delay(1000)