fix: reuse main page pass list for mutual search

findMutualPasses was computing passes independently with its own
search algorithm, which produced different results from the main
page's getLeoPass. Now it directly reuses satelliteRepo.passes,
which is the same list shown on the main passes page. The only
additional computation is refining the common window for station B
and sampling elevation/azimuth curves.
This commit is contained in:
atsunatsu committed 2026-08-03 02:16:15 +08:00
1 parent 43788ba7a7
commit 86ee3dcbac
1 file changed
+48 -51
@@ -210,63 +210,60 @@ class MutualViewModel(
val endTime = time + hours * 60L * 60L * 1000L val endTime = time + hours * 60L * 60L * 1000L
val sampleInterval = 5_000L // 5 seconds between samples for smooth curves val sampleInterval = 5_000L // 5 seconds between samples for smooth curves
for (sat in satellites) { // Reuse the main page's pass list (calculated by getLeoPass/getGeoPass)
if (sat.data.meanmo < 1e-8) continue // so the mutual pass times match the main page exactly.
var searchStart = time val existingPasses = satelliteRepo.passes.value
// Find ALL mutual passes for this satellite for (pass in existingPasses) {
while (true) { if (pass.losTime <= time || pass.aosTime >= endTime) continue
val t = findNextMutualPass(sat, posA, posB, searchStart, endTime) if (pass.isDeepSpace) continue
if (t == null) break if (pass.orbitalObject.data.meanmo < 1e-8) continue
val (aos, los) = t
// Refine AOS: finer search near the edge (0° horizon, like the main radar) val sat = pass.orbitalObject
val refinedAos = refineEdge(sat, posA, posB, aos, step = 1_000L, goingUp = true) // Refine the common window: AOS = max(A's AOS, B's horizon crossing)
// Refine LOS: finer search near the edge val refinedAos = refineEdge(sat, posA, posB, pass.aosTime, 1_000L, goingUp = true)
val refinedLos = refineEdge(sat, posA, posB, los, step = 1_000L, goingUp = false) val refinedLos = refineEdge(sat, posA, posB, pass.losTime, 1_000L, goingUp = false)
if (refinedLos <= refinedAos) continue
val samples = mutableListOf<Pair<Long, Pair<Double, Double>>>() val samples = mutableListOf<Pair<Long, Pair<Double, Double>>>()
val tracks = mutableListOf<TrackSample>() val tracks = mutableListOf<TrackSample>()
var maxElevA = 0.0 var maxElevA = 0.0
var maxElevB = 0.0 var maxElevB = 0.0
var tSample = refinedAos var tSample = refinedAos
while (tSample <= refinedLos) { while (tSample <= refinedLos) {
val fullA = sat.getFullPosition(posA, tSample) val fullA = sat.getFullPosition(posA, tSample)
val fullB = sat.getFullPosition(posB, tSample) val fullB = sat.getFullPosition(posB, tSample)
val elevA = fullA.elevation * 180.0 / PI val elevA = fullA.elevation * 180.0 / PI
val elevB = fullB.elevation * 180.0 / PI val elevB = fullB.elevation * 180.0 / PI
if (elevA > maxElevA) maxElevA = elevA if (elevA > maxElevA) maxElevA = elevA
if (elevB > maxElevB) maxElevB = elevB if (elevB > maxElevB) maxElevB = elevB
samples.add(tSample to (elevA to elevB)) samples.add(tSample to (elevA to elevB))
tracks.add( tracks.add(
TrackSample( TrackSample(
time = tSample, time = tSample,
azimuthA = fullA.azimuth * 180.0 / PI, azimuthA = fullA.azimuth * 180.0 / PI,
elevationA = elevA, elevationA = elevA,
azimuthB = fullB.azimuth * 180.0 / PI, azimuthB = fullB.azimuth * 180.0 / PI,
elevationB = elevB elevationB = elevB
)
) )
tSample += sampleInterval )
} tSample += sampleInterval
}
// Both stations must reach their own min elevation for a usable mutual pass // Both stations must reach their own min elevation for a usable mutual pass
if (maxElevA > minElevADeg && maxElevB > minElevBDeg) { if (maxElevA > minElevADeg && maxElevB > minElevBDeg) {
results.add( results.add(
MutualPass( MutualPass(
catNum = sat.data.catnum, catNum = pass.catNum,
name = sat.data.name, name = pass.orbitalObject.data.name,
startTime = refinedAos, startTime = refinedAos,
endTime = refinedLos, endTime = refinedLos,
maxElevationA = (maxElevA * 10).roundToInt() / 10.0, maxElevationA = (maxElevA * 10).roundToInt() / 10.0,
maxElevationB = (maxElevB * 10).roundToInt() / 10.0, maxElevationB = (maxElevB * 10).roundToInt() / 10.0,
elevationSamples = samples, elevationSamples = samples,
trackSamples = tracks trackSamples = tracks
)
) )
} )
// Advance past this pass and keep searching
searchStart = refinedLos + 120_000L
} }
} }
return results return results