mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
fix: radar track rendering bugs
- Elevation ring labels were inverted (90/60/30 from outer to inner); now 30/60/90 correctly from outer ring to center - Split track paths at the 0/360° azimuth wrap in both MutualRadarView and main RadarView, so passes crossing due north no longer draw a line straight across the plot
This commit is contained in:
1 parent
998c98267b
commit
1a3f1bb34c
2 files changed
+37
-10
No files matched your search
+22
-9
@@ -103,29 +103,35 @@ fun MutualRadarView(
|
||||
// Grid: elevation rings + azimuth spokes + cardinal labels
|
||||
drawRadarGrid(center, radius, gridColor, textColor, measurer)
|
||||
|
||||
// Track paths (only the above-horizon arc)
|
||||
// Track paths (only the above-horizon arc, split at the 0/360° azimuth wrap)
|
||||
val pathA = Path()
|
||||
val pathB = Path()
|
||||
var firstVisibleA = true
|
||||
var firstVisibleB = true
|
||||
var lastAzimA: Double? = null
|
||||
var lastAzimB: Double? = null
|
||||
trackSamples.forEach { sample ->
|
||||
if (sample.elevationA > 0f) {
|
||||
val p = sph2Cart(center, sample.azimuthA, sample.elevationA, radius)
|
||||
if (firstVisibleA) {
|
||||
val wrapA = lastAzimA != null && kotlin.math.abs(azimuthDelta(sample.azimuthA - lastAzimA!!)) > 180.0
|
||||
if (firstVisibleA || wrapA) {
|
||||
pathA.moveTo(p.x, p.y)
|
||||
firstVisibleA = false
|
||||
} else {
|
||||
pathA.lineTo(p.x, p.y)
|
||||
}
|
||||
lastAzimA = sample.azimuthA
|
||||
}
|
||||
if (sample.elevationB > 0f) {
|
||||
val p = sph2Cart(center, sample.azimuthB, sample.elevationB, radius)
|
||||
if (firstVisibleB) {
|
||||
val wrapB = lastAzimB != null && kotlin.math.abs(azimuthDelta(sample.azimuthB - lastAzimB!!)) > 180.0
|
||||
if (firstVisibleB || wrapB) {
|
||||
pathB.moveTo(p.x, p.y)
|
||||
firstVisibleB = false
|
||||
} else {
|
||||
pathB.lineTo(p.x, p.y)
|
||||
}
|
||||
lastAzimB = sample.azimuthB
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,13 +204,12 @@ private fun DrawScope.drawRadarGrid(
|
||||
Offset(center.x - diag, center.y + diag), Offset(center.x + diag, center.y - diag), 1f
|
||||
)
|
||||
|
||||
// Elevation ring labels
|
||||
// Elevation ring labels: 30° on the outer ring, 60° on the middle ring, 90° at center
|
||||
// (outer edge is the 0° horizon). Labels sit just above their ring.
|
||||
val style = TextStyle(color = textColor, fontSize = 11.sp)
|
||||
for (i in 0 until CIRCLES) {
|
||||
val deg = 30 * (CIRCLES - i)
|
||||
val y = (center.y - (radius - step * i)) - 24f
|
||||
drawText(measurer, "$deg°", Offset(center.x + 6f, y), style = style)
|
||||
}
|
||||
drawText(measurer, "30°", Offset(center.x + 6f, (center.y - (radius - step)) - 24f), style = style)
|
||||
drawText(measurer, "60°", Offset(center.x + 6f, (center.y - (radius - 2 * step)) - 24f), style = style)
|
||||
drawText(measurer, "90°", Offset(center.x + 6f, center.y - 18f), style = style)
|
||||
// Cardinal labels
|
||||
drawText(measurer, "N", Offset(center.x - 8f, center.y - radius - 20f), style = style)
|
||||
drawText(measurer, "E", Offset(center.x + radius + 4f, center.y - 10f), style = style)
|
||||
@@ -212,6 +217,14 @@ private fun DrawScope.drawRadarGrid(
|
||||
drawText(measurer, "W", Offset(center.x - radius - 24f, center.y - 10f), style = style)
|
||||
}
|
||||
|
||||
/** Normalize an azimuth delta (degrees) into the [-180, 180] range. */
|
||||
private fun azimuthDelta(deltaDeg: Double): Double {
|
||||
var d = deltaDeg % 360.0
|
||||
if (d > 180.0) d -= 360.0
|
||||
if (d < -180.0) d += 360.0
|
||||
return d
|
||||
}
|
||||
|
||||
/** Convert azimuth (deg, 0=N, clockwise) and elevation (deg) to canvas offset. */
|
||||
private fun sph2Cart(center: Offset, azimDeg: Double, elevDeg: Double, r: Float): Offset {
|
||||
val azimRad = azimDeg * PI / 180.0
|
||||
|
||||
@@ -60,6 +60,8 @@ 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.PI
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
@@ -226,13 +228,25 @@ private fun DrawScope.drawSweep(center: Offset, degrees: Float, radius: Float, b
|
||||
|
||||
private fun createTrackPath(positions: List<OrbitalPos>, radius: Float): Path {
|
||||
val trackPath = Path()
|
||||
var lastAzim: Double? = null
|
||||
positions.forEachIndexed { index, pos ->
|
||||
val offset = sph2Cart(pos.azimuth, pos.elevation, radius.toDouble())
|
||||
if (index == 0) trackPath.moveTo(offset.x, offset.y) else trackPath.lineTo(offset.x, offset.y)
|
||||
// Split the path when azimuth wraps 0°/360° to avoid a line across the plot
|
||||
val wrap = lastAzim != null && abs(azimuthDeltaRad(pos.azimuth - lastAzim!!)) > PI
|
||||
if (index == 0 || wrap) trackPath.moveTo(offset.x, offset.y) else trackPath.lineTo(offset.x, offset.y)
|
||||
lastAzim = pos.azimuth
|
||||
}
|
||||
return trackPath
|
||||
}
|
||||
|
||||
/** Normalize an azimuth delta (radians) into the [-PI, PI] range. */
|
||||
private fun azimuthDeltaRad(deltaRad: Double): Double {
|
||||
var d = deltaRad % (2 * PI)
|
||||
if (d > PI) d -= 2 * PI
|
||||
if (d < -PI) d += 2 * PI
|
||||
return d
|
||||
}
|
||||
|
||||
private fun createTrackEffect(trackPath: Path): PathEffect {
|
||||
val shapeRadius = 24f
|
||||
val angle = 120.0.toRadians()
|
||||
|
||||
Reference in new issue
Block a user