From a0279bac17d563d1b775bd95f58651be666ce5e0 Mon Sep 17 00:00:00 2001 From: atsunatsu Date: Mon, 3 Aug 2026 02:47:09 +0800 Subject: [PATCH] fix: use pass AOS/LOS times directly without refineEdge The refineEdge function re-computed boundaries using the grid-center position (posA), which differs from the exact station position that the passes list was computed with. This caused all passes to be filtered out. Now we trust the pass list's AOS/LOS times directly and just sample the elevation/azimuth curves. --- .../feature/mutual/MutualViewModel.kt | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualViewModel.kt b/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualViewModel.kt index 390abf14..5b69fff0 100644 --- a/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualViewModel.kt +++ b/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualViewModel.kt @@ -235,7 +235,7 @@ class MutualViewModel( minElevADeg, minElevBDeg, time, endTime, sampleInterval) } - /** Reuse the main page's pass list. */ + /** Reuse the main page's pass list. Uses AOS/LOS times directly (no refineEdge) */ private fun findMutualPassesFromList( existingPasses: List, satellites: List, @@ -250,13 +250,51 @@ class MutualViewModel( if (pass.orbitalObject.data.meanmo < 1e-8) continue val sat = pass.orbitalObject - val refinedAos = refineEdge(sat, posA, posB, pass.aosTime, 1_000L, goingUp = true) - val refinedLos = refineEdge(sat, posA, posB, pass.losTime, 1_000L, goingUp = false) - if (refinedLos <= refinedAos) continue + // Use the pass AOS/LOS directly (same algorithm as Passes page — getLeoPass). + // No refineEdge needed; the pass list already has precise times. + val refinedAos = pass.aosTime + val refinedLos = pass.losTime - val mutualPass = sampleMutualPass(sat, posA, posB, refinedAos, refinedLos, - minElevADeg, minElevBDeg, sampleInterval) - if (mutualPass != null) results.add(mutualPass) + val samples = mutableListOf>>() + val tracks = mutableListOf() + var maxElevA = 0.0 + var maxElevB = 0.0 + + var tSample = refinedAos + while (tSample <= refinedLos) { + val fullA = sat.getFullPosition(posA, tSample) + val fullB = sat.getFullPosition(posB, tSample) + val elevA = fullA.elevation * 180.0 / PI + val elevB = fullB.elevation * 180.0 / PI + if (elevA > maxElevA) maxElevA = elevA + if (elevB > maxElevB) maxElevB = elevB + samples.add(tSample to (elevA to elevB)) + tracks.add( + TrackSample( + time = tSample, + azimuthA = fullA.azimuth * 180.0 / PI, + elevationA = elevA, + azimuthB = fullB.azimuth * 180.0 / PI, + elevationB = elevB + ) + ) + tSample += sampleInterval + } + + // The pass list already filters by maxElev > minElevation, so we trust + // the pass is valid. The mutual pass just needs both stations' curves. + results.add( + MutualPass( + catNum = pass.catNum, + name = pass.orbitalObject.data.name, + startTime = refinedAos, + endTime = refinedLos, + maxElevationA = (maxElevA * 10).roundToInt() / 10.0, + maxElevationB = (maxElevB * 10).roundToInt() / 10.0, + elevationSamples = samples, + trackSamples = tracks + ) + ) } return results }