Further changes to Look4Sat Predictor.kt core class

This commit is contained in:
Arty Bishop committed 2021-09-16 10:03:58 +01:00
1 parent bceeb01194
commit a82915c0ca
8 files changed
+314 -496

No files matched your search

@@ -22,6 +22,7 @@ import android.content.SharedPreferences
import android.location.LocationManager
import androidx.room.Room
import com.rtbishop.look4sat.data.*
import com.rtbishop.look4sat.domain.Predictor
import com.rtbishop.look4sat.framework.PreferencesProvider
import com.rtbishop.look4sat.framework.api.RemoteSource
import com.rtbishop.look4sat.framework.api.SatelliteService
@@ -63,8 +64,8 @@ object SatelliteDataModule {
@Provides
@Singleton
fun providePassPredictor(@DefaultDispatcher dispatcher: CoroutineDispatcher): PassPredictor {
return PassPredictor(dispatcher)
fun providePredictor(@DefaultDispatcher dispatcher: CoroutineDispatcher): Predictor {
return Predictor(dispatcher)
}
@Provides
@@ -18,28 +18,22 @@
package com.rtbishop.look4sat.presentation.satMapScreen
import androidx.lifecycle.*
import com.rtbishop.look4sat.domain.Predictor
import com.rtbishop.look4sat.data.PreferencesSource
import com.rtbishop.look4sat.data.SatelliteRepo
import com.rtbishop.look4sat.data.PassPredictor
import com.rtbishop.look4sat.domain.GeoPos
import com.rtbishop.look4sat.domain.Satellite
import com.rtbishop.look4sat.domain.StationPos
import com.rtbishop.look4sat.domain.SatData
import com.rtbishop.look4sat.injection.DefaultDispatcher
import com.rtbishop.look4sat.domain.*
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*
import org.osmdroid.views.MapView
import java.util.*
import javax.inject.Inject
import kotlin.math.pow
import kotlin.math.sqrt
import kotlin.math.max
import kotlin.math.min
@HiltViewModel
class SatMapViewModel @Inject constructor(
private val satelliteRepo: SatelliteRepo,
private val passPredictor: PassPredictor,
private val predictor: Predictor,
private val preferences: PreferencesSource,
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher
) : ViewModel() {
private val stationPos = preferences.loadStationPosition()
@@ -99,100 +93,93 @@ class SatMapViewModel @Inject constructor(
dataUpdateJob?.cancelAndJoin()
dataUpdateJob = launch {
val dateNow = Date()
setSelectedSatTrack(selectedSat, stationPos, dateNow)
getSatTrack(selectedSat, stationPos, dateNow)
while (isActive) {
dateNow.time = System.currentTimeMillis()
setSatPositions(allSatList, stationPos, dateNow)
setSelectedSatFootprint(selectedSat, stationPos, dateNow)
setSelectedSatData(selectedSat, stationPos, dateNow)
getPositions(allSatList, stationPos, dateNow)
getSatFootprint(selectedSat, stationPos, dateNow)
getSatData(selectedSat, stationPos, dateNow)
delay(updateFreq)
}
}
}
}
private suspend fun setSatPositions(list: List<Satellite>, gsp: StationPos, date: Date) {
withContext(defaultDispatcher) {
val satPositions = mutableMapOf<Satellite, GeoPos>()
list.forEach { satellite ->
val satPos = satellite.getPosition(gsp, date.time)
val osmLat = clipLat(Math.toDegrees(satPos.latitude))
val osmLon = clipLon(Math.toDegrees(satPos.longitude))
satPositions[satellite] = GeoPos(osmLat, osmLon)
}
_satPositions.postValue(satPositions)
}
}
private suspend fun setSelectedSatTrack(sat: Satellite, gsp: StationPos, date: Date) {
withContext(defaultDispatcher) {
val satTracks = mutableListOf<List<GeoPos>>()
val currentTrack = mutableListOf<GeoPos>()
var oldLongitude = 0.0
passPredictor.getPositions(sat, gsp, date, 15, 0, 2.4).forEach { satPos ->
val osmLat = clipLat(Math.toDegrees(satPos.latitude))
val osmLon = clipLon(Math.toDegrees(satPos.longitude))
val currentPosition = GeoPos(osmLat, osmLon)
if (oldLongitude < -170.0 && currentPosition.longitude > 170.0) {
// adding left terminal position
currentTrack.add(GeoPos(osmLat, -180.0))
val finishedTrack = mutableListOf<GeoPos>().apply { addAll(currentTrack) }
satTracks.add(finishedTrack)
currentTrack.clear()
} else if (oldLongitude > 170.0 && currentPosition.longitude < -170.0) {
// adding right terminal position
currentTrack.add(GeoPos(osmLat, 180.0))
val finishedTrack = mutableListOf<GeoPos>().apply { addAll(currentTrack) }
satTracks.add(finishedTrack)
currentTrack.clear()
}
oldLongitude = currentPosition.longitude
currentTrack.add(currentPosition)
}
satTracks.add(currentTrack)
_satTrack.postValue(satTracks)
}
}
private suspend fun setSelectedSatFootprint(sat: Satellite, gsp: StationPos, date: Date) {
withContext(defaultDispatcher) {
val satFootprint = sat.getPosition(gsp, date.time).getRangeCircle().map { rangePos ->
val osmLat = clipLat(rangePos.latitude)
val osmLon = clipLon(rangePos.longitude)
GeoPos(osmLat, osmLon)
}
_satFootprint.postValue(satFootprint)
}
}
private suspend fun setSelectedSatData(sat: Satellite, gsp: StationPos, date: Date) {
withContext(defaultDispatcher) {
val satPos = sat.getPosition(gsp, date.time)
private suspend fun getSatTrack(satellite: Satellite, pos: StationPos, date: Date) {
val satTracks = mutableListOf<List<GeoPos>>()
val currentTrack = mutableListOf<GeoPos>()
val endDate = Date(date.time + (satellite.orbitalPeriod * 2.4 * 60000L).toLong())
var oldLongitude = 0.0
predictor.getSatTrack(satellite, pos, date, endDate).forEach { satPos ->
val osmLat = clipLat(Math.toDegrees(satPos.latitude))
val osmLon = clipLon(Math.toDegrees(satPos.longitude))
val osmPos = GeoPos(osmLat, osmLon)
val qthLoc = preferences.positionToQTH(osmPos.latitude, osmPos.longitude) ?: "-- --"
val velocity = getOrbitalVelocity(satPos.altitude)
val satData = SatData(
sat, sat.params.catnum, sat.params.name, satPos.range,
satPos.altitude, velocity, qthLoc, osmPos
)
this@SatMapViewModel._satData.postValue(satData)
val currentPosition = GeoPos(osmLat, osmLon)
if (oldLongitude < -170.0 && currentPosition.longitude > 170.0) {
// adding left terminal position
currentTrack.add(GeoPos(osmLat, -180.0))
val finishedTrack = mutableListOf<GeoPos>().apply { addAll(currentTrack) }
satTracks.add(finishedTrack)
currentTrack.clear()
} else if (oldLongitude > 170.0 && currentPosition.longitude < -170.0) {
// adding right terminal position
currentTrack.add(GeoPos(osmLat, 180.0))
val finishedTrack = mutableListOf<GeoPos>().apply { addAll(currentTrack) }
satTracks.add(finishedTrack)
currentTrack.clear()
}
oldLongitude = currentPosition.longitude
currentTrack.add(currentPosition)
}
satTracks.add(currentTrack)
_satTrack.postValue(satTracks)
}
private suspend fun getPositions(satellites: List<Satellite>, pos: StationPos, date: Date) {
val positions = mutableMapOf<Satellite, GeoPos>()
satellites.forEach { satellite ->
val satPos = predictor.getSatPos(satellite, pos, date)
val osmLat = clipLat(Math.toDegrees(satPos.latitude))
val osmLon = clipLon(Math.toDegrees(satPos.longitude))
positions[satellite] = GeoPos(osmLat, osmLon)
}
_satPositions.postValue(positions)
}
private suspend fun getSatFootprint(satellite: Satellite, pos: StationPos, date: Date) {
val satPos = predictor.getSatPos(satellite, pos, date)
val satFootprint = satPos.getRangeCircle().map { rangePos ->
val osmLat = clipLat(rangePos.latitude)
val osmLon = clipLon(rangePos.longitude)
GeoPos(osmLat, osmLon)
}
_satFootprint.postValue(satFootprint)
}
private suspend fun getSatData(satellite: Satellite, pos: StationPos, date: Date) {
val satPos = predictor.getSatPos(satellite, pos, date)
val osmLat = clipLat(Math.toDegrees(satPos.latitude))
val osmLon = clipLon(Math.toDegrees(satPos.longitude))
val osmPos = GeoPos(osmLat, osmLon)
val qthLoc = QthConverter.positionToQTH(osmPos.latitude, osmPos.longitude) ?: "-- --"
val satData = SatData(
satellite, satellite.params.catnum, satellite.params.name, satPos.range,
satPos.altitude, satPos.getOrbitalVelocity(), qthLoc, osmPos
)
_satData.postValue(satData)
}
private fun clipLat(latitude: Double): Double {
return MapView.getTileSystem().cleanLatitude(latitude)
return clip(latitude, -85.05, 85.05)
}
private fun clipLon(longitude: Double): Double {
return MapView.getTileSystem().cleanLongitude(longitude)
var result = longitude
while (result < -180.0) result += 360.0
while (result > 180.0) result -= 360.0
return clip(result, -180.0, 180.0)
}
private fun getOrbitalVelocity(altitude: Double): Double {
val earthG = 6.674 * 10.0.pow(-11)
val earthM = 5.98 * 10.0.pow(24)
val radius = 6.37 * 10.0.pow(6) + altitude * 10.0.pow(3)
return sqrt(earthG * earthM / radius) / 1000
private fun clip(currentValue: Double, minValue: Double, maxValue: Double): Double {
return min(max(currentValue, minValue), maxValue)
}
}
@@ -18,7 +18,7 @@
package com.rtbishop.look4sat.presentation.satPassInfoScreen
import androidx.lifecycle.*
import com.rtbishop.look4sat.data.PassPredictor
import com.rtbishop.look4sat.domain.Predictor
import com.rtbishop.look4sat.data.PreferencesSource
import com.rtbishop.look4sat.data.SatelliteRepo
import com.rtbishop.look4sat.injection.IoDispatcher
@@ -38,7 +38,7 @@ import javax.inject.Inject
class PassInfoViewModel @Inject constructor(
private val orientationProvider: OrientationProvider,
private val preferences: PreferencesSource,
private val passPredictor: PassPredictor,
private val predictor: Predictor,
private val satelliteRepo: SatelliteRepo,
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
) : ViewModel(), OrientationProvider.OrientationListener {
@@ -50,7 +50,7 @@ class PassInfoViewModel @Inject constructor(
val orientation: LiveData<Triple<Float, Float, Float>> = _orientation
fun getPass(catNum: Int, aosTime: Long) = liveData {
passPredictor.passes.collect { passes ->
predictor.passes.collect { passes ->
val pass = passes.find { it.catNum == catNum && it.aosTime == aosTime }
pass?.let { satPass ->
processTransmitters(satPass)
@@ -23,7 +23,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.rtbishop.look4sat.data.PreferencesSource
import com.rtbishop.look4sat.data.SatelliteRepo
import com.rtbishop.look4sat.data.PassPredictor
import com.rtbishop.look4sat.domain.Predictor
import com.rtbishop.look4sat.domain.SatPass
import com.rtbishop.look4sat.framework.model.Result
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -34,7 +34,7 @@ import javax.inject.Inject
@HiltViewModel
class SatPassViewModel @Inject constructor(
private val satelliteRepo: SatelliteRepo,
private val passPredictor: PassPredictor,
private val predictor: Predictor,
private val preferencesSource: PreferencesSource
) : ViewModel() {
@@ -49,13 +49,13 @@ class SatPassViewModel @Inject constructor(
viewModelScope.launch {
_passes.postValue(Result.InProgress)
val stationPos = preferencesSource.loadStationPosition()
passPredictor.triggerCalculation(satelliteRepo.getSelectedSatellites(), stationPos)
predictor.triggerCalculation(satelliteRepo.getSelectedSatellites(), stationPos)
}
} else {
_isFirstLaunchDone.value = false
}
viewModelScope.launch {
passPredictor.passes.collect { passes ->
predictor.passes.collect { passes ->
passesProcessing?.cancelAndJoin()
passesProcessing = viewModelScope.launch { tickPasses(passes) }
}
@@ -70,7 +70,7 @@ class SatPassViewModel @Inject constructor(
val stationPos = preferencesSource.loadStationPosition()
satelliteRepo.updateEntriesFromWeb(preferencesSource.loadDefaultSources())
satelliteRepo.updateEntriesSelection(defaultCatNums, true)
passPredictor.forceCalculation(satelliteRepo.getSelectedSatellites(), stationPos)
predictor.forceCalculation(satelliteRepo.getSelectedSatellites(), stationPos)
preferencesSource.setSetupDone()
_isFirstLaunchDone.value = true
}
@@ -81,7 +81,7 @@ class SatPassViewModel @Inject constructor(
_passes.postValue(Result.InProgress)
passesProcessing?.cancelAndJoin()
val stationPos = preferencesSource.loadStationPosition()
passPredictor.forceCalculation(satelliteRepo.getSelectedSatellites(), stationPos)
predictor.forceCalculation(satelliteRepo.getSelectedSatellites(), stationPos)
}
}