Added current moon/sun positions to the RadarScreen

This commit is contained in:
Arty Bishop committed 2026-04-26 14:32:16 +01:00
1 parent 18f8ab517d
commit b166e896c2
5 files changed
+72 -10

No files matched your search

@@ -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()
)
@@ -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)
}
@@ -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<OrbitalPos> = emptyList(),
val shouldShowSweep: Boolean = false,
val shouldUseCompass: Boolean = false,
val sunPosition: CelestialComputer.SunPosition? = null,
val moonPosition: CelestialComputer.MoonPosition? = null,
val transmitters: List<SatRadio> = emptyList(),
val selectedTransmitterUuid: String? = null,
val selectedFrequency: Long? = null
@@ -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<Float, Float>,
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(
@@ -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)