From 88c7bb6bcaa9e0f4a04395d26a44d08d1d2a21ab Mon Sep 17 00:00:00 2001 From: Arty Bishop Date: Thu, 28 Oct 2021 19:32:21 +0100 Subject: [PATCH] Removed all java dependencies from domain.predict package --- .../presentation/mapScreen/MapViewModel.kt | 8 +- .../passesScreen/PassesViewModel.kt | 10 +- .../radarScreen/RadarViewModel.kt | 8 +- .../look4sat/domain/predict/Predictor.kt | 98 +++++++++---------- .../look4sat/domain/predict/Satellite.kt | 20 ++-- 5 files changed, 67 insertions(+), 77 deletions(-) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/mapScreen/MapViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/mapScreen/MapViewModel.kt index e7cea42b..72d89e7b 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/mapScreen/MapViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/mapScreen/MapViewModel.kt @@ -116,7 +116,7 @@ class MapViewModel @Inject constructor( val currentTrack = mutableListOf() val endDate = Date(date.time + (satellite.orbitalPeriod * 2.4 * 60000L).toLong()) var oldLongitude = 0.0 - predictor.getSatTrack(satellite, pos, date, endDate).forEach { satPos -> + predictor.getSatTrack(satellite, pos, date.time, endDate.time).forEach { satPos -> val osmLat = clipLat(Math.toDegrees(satPos.latitude)) val osmLon = clipLon(Math.toDegrees(satPos.longitude)) val currentPosition = GeoPos(osmLat, osmLon) @@ -143,7 +143,7 @@ class MapViewModel @Inject constructor( private suspend fun getPositions(satellites: List, pos: GeoPos, date: Date) { val positions = mutableMapOf() satellites.forEach { satellite -> - val satPos = predictor.getSatPos(satellite, pos, date) + val satPos = predictor.getSatPos(satellite, pos, date.time) val osmLat = clipLat(Math.toDegrees(satPos.latitude)) val osmLon = clipLon(Math.toDegrees(satPos.longitude)) positions[satellite] = GeoPos(osmLat, osmLon) @@ -152,7 +152,7 @@ class MapViewModel @Inject constructor( } private suspend fun getSatFootprint(satellite: Satellite, pos: GeoPos, date: Date) { - val satPos = predictor.getSatPos(satellite, pos, date) + val satPos = predictor.getSatPos(satellite, pos, date.time) val satFootprint = satPos.getRangeCircle().map { rangePos -> val osmLat = clipLat(rangePos.latitude) val osmLon = clipLon(rangePos.longitude) @@ -162,7 +162,7 @@ class MapViewModel @Inject constructor( } private suspend fun getSatData(satellite: Satellite, pos: GeoPos, date: Date) { - val satPos = predictor.getSatPos(satellite, pos, date) + val satPos = predictor.getSatPos(satellite, pos, date.time) val osmLat = clipLat(Math.toDegrees(satPos.latitude)) val osmLon = clipLon(Math.toDegrees(satPos.longitude)) val osmPos = GeoPos(osmLat, osmLon) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesViewModel.kt index 4078fc15..23990253 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/passesScreen/PassesViewModel.kt @@ -49,12 +49,12 @@ class PassesViewModel @Inject constructor( if (preferences.isSetupDone()) { viewModelScope.launch { _passes.postValue(DataState.Loading) - val dateNow = Date() + val timeNow = System.currentTimeMillis() val satellites = dataRepository.getSelectedSatellites() val stationPos = preferences.loadStationPosition() val hoursAhead = preferences.getHoursAhead() val minElev = preferences.getMinElevation() - predictor.triggerCalculation(satellites, stationPos, dateNow, hoursAhead, minElev) + predictor.triggerCalculation(satellites, stationPos, timeNow, hoursAhead, minElev) } } else { _isFirstLaunchDone.value = false @@ -77,7 +77,7 @@ class PassesViewModel @Inject constructor( val minElev = preferences.getMinElevation() dataRepository.updateDataFromWeb() dataRepository.updateSelection(isSelected = true) - predictor.forceCalculation(satellites, stationPos, Date(), hoursAhead, minElev) + predictor.forceCalculation(satellites, stationPos, Date().time, hoursAhead, minElev) preferences.setSetupDone() _isFirstLaunchDone.value = true } @@ -87,12 +87,12 @@ class PassesViewModel @Inject constructor( viewModelScope.launch { _passes.postValue(DataState.Loading) passesProcessing?.cancelAndJoin() - val dateNow = Date() + val timeNow = System.currentTimeMillis() val satellites = dataRepository.getSelectedSatellites() val stationPos = preferences.loadStationPosition() val hoursAhead = preferences.getHoursAhead() val minElev = preferences.getMinElevation() - predictor.forceCalculation(satellites, stationPos, dateNow, hoursAhead, minElev) + predictor.forceCalculation(satellites, stationPos, timeNow, hoursAhead, minElev) } } diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt index fa6e01b4..6d5032da 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/radarScreen/RadarViewModel.kt @@ -79,12 +79,12 @@ class RadarViewModel @Inject constructor( viewModelScope.launch { var satTrack: List = emptyList() if (!satPass.isDeepSpace) { - val startDate = Date(satPass.aosTime) - val endDate = Date(satPass.losTime) + val startDate = satPass.aosTime + val endDate = satPass.losTime satTrack = predictor.getSatTrack(satPass.satellite, stationPos, startDate, endDate) } while (isActive) { - val satPos = predictor.getSatPos(satPass.satellite, stationPos, Date()) + val satPos = predictor.getSatPos(satPass.satellite, stationPos, Date().time) if (preferences.isRotatorEnabled()) { val server = preferences.getRotatorServer().first val port = preferences.getRotatorServer().second @@ -102,7 +102,7 @@ class RadarViewModel @Inject constructor( viewModelScope.launch { val transmitters = dataRepository.getTransmitters(satPass.catNum) while (isActive) { - val satPos = predictor.getSatPos(satPass.satellite, stationPos, Date()) + val satPos = predictor.getSatPos(satPass.satellite, stationPos, Date().time) val copiedList = transmitters.map { it.copy() } copiedList.forEach { transmitter -> transmitter.downlink?.let { diff --git a/core/src/main/java/com/rtbishop/look4sat/domain/predict/Predictor.kt b/core/src/main/java/com/rtbishop/look4sat/domain/predict/Predictor.kt index a310dc19..582d3a8d 100644 --- a/core/src/main/java/com/rtbishop/look4sat/domain/predict/Predictor.kt +++ b/core/src/main/java/com/rtbishop/look4sat/domain/predict/Predictor.kt @@ -21,7 +21,6 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.withContext -import java.util.* class Predictor(private val predictorDispatcher: CoroutineDispatcher) { @@ -29,26 +28,26 @@ class Predictor(private val predictorDispatcher: CoroutineDispatcher) { private var selectedSatIds = emptyList() val passes: SharedFlow> = _passes - suspend fun getSatPos(sat: Satellite, pos: GeoPos, date: Date): SatPos = - withContext(predictorDispatcher) { - return@withContext sat.getPosition(pos, date.time) - } + suspend fun getSatPos(sat: Satellite, pos: GeoPos, time: Long): SatPos { + return withContext(predictorDispatcher) { sat.getPosition(pos, time) } + } - suspend fun getSatTrack(sat: Satellite, pos: GeoPos, start: Date, end: Date): List = - withContext(predictorDispatcher) { + suspend fun getSatTrack(sat: Satellite, pos: GeoPos, start: Long, end: Long): List { + return withContext(predictorDispatcher) { val positions = mutableListOf() - var currentTime = start.time - while (currentTime < end.time) { + var currentTime = start + while (currentTime < end) { positions.add(sat.getPosition(pos, currentTime)) currentTime += 15000 } - return@withContext positions + positions } + } suspend fun triggerCalculation( satellites: List, pos: GeoPos, - date: Date = Date(), + time: Long, hoursAhead: Int = 8, minElevation: Double = 16.0 ) { @@ -57,7 +56,7 @@ class Predictor(private val predictorDispatcher: CoroutineDispatcher) { } else { val newCatNums = satellites.map { it.params.catnum } if (selectedSatIds != newCatNums) { - forceCalculation(satellites, pos, date, hoursAhead, minElevation) + forceCalculation(satellites, pos, time, hoursAhead, minElevation) } } } @@ -65,7 +64,7 @@ class Predictor(private val predictorDispatcher: CoroutineDispatcher) { suspend fun forceCalculation( satellites: List, pos: GeoPos, - date: Date = Date(), + time: Long, hoursAhead: Int = 8, minElevation: Double = 16.0 ) { @@ -76,31 +75,31 @@ class Predictor(private val predictorDispatcher: CoroutineDispatcher) { val allPasses = mutableListOf() selectedSatIds = satellites.map { it.params.catnum } satellites.forEach { satellite -> - allPasses.addAll(satellite.getPasses(pos, date, hoursAhead)) + allPasses.addAll(satellite.getPasses(pos, time, hoursAhead)) } - _passes.emit(allPasses.filter(date, hoursAhead, minElevation)) + _passes.emit(allPasses.filter(time, hoursAhead, minElevation)) } } } - private fun Satellite.getPasses(pos: GeoPos, date: Date, hours: Int): List { + private fun Satellite.getPasses(pos: GeoPos, time: Long, hours: Int): List { val passes = mutableListOf() - val endDate = Date(date.time + hours * 60L * 60L * 1000L) + val endDate = time + hours * 60L * 60L * 1000L val quarterOrbitMin = (this.orbitalPeriod / 4.0).toInt() - var startDate = date + var startDate = time var shouldRewind = true - var lastAosDate: Date + var lastAosDate: Long var count = 0 if (this.willBeSeen(pos)) { if (this.params.isDeepspace) { - passes.add(getGeoPass(this, pos, date)) + passes.add(getGeoPass(this, pos, time)) } else { do { if (count > 0) shouldRewind = false val pass = getLeoPass(this, pos, startDate, shouldRewind) - lastAosDate = Date(pass.aosTime) + lastAosDate = pass.aosTime passes.add(pass) - startDate = Date(pass.losTime + (quarterOrbitMin * 3) * 60L * 1000L) + startDate = pass.losTime + (quarterOrbitMin * 3) * 60L * 1000L count++ } while (lastAosDate < endDate) } @@ -108,53 +107,50 @@ class Predictor(private val predictorDispatcher: CoroutineDispatcher) { return passes } - private fun List.filter(date: Date, hoursAhead: Int, minElev: Double): List { - val timeFuture = date.time + (hoursAhead * 60L * 60L * 1000L) - return this.filter { it.losTime > date.time } + private fun List.filter(time: Long, hoursAhead: Int, minElev: Double): List { + val timeFuture = time + (hoursAhead * 60L * 60L * 1000L) + return this.filter { it.losTime > time } .filter { it.aosTime < timeFuture } .filter { it.maxElevation > minElev } .sortedBy { it.aosTime } } - private fun getGeoPass(sat: Satellite, pos: GeoPos, date: Date): SatPass { - val satPos = sat.getPosition(pos, date.time) - val aos = Date(date.time - 24 * 60L * 60L * 1000L).time - val los = Date(date.time + 24 * 60L * 60L * 1000L).time - val tca = Date((aos + los) / 2).time + private fun getGeoPass(sat: Satellite, pos: GeoPos, time: Long): SatPass { + val satPos = sat.getPosition(pos, time) + val aos = time - 24 * 60L * 60L * 1000L + val los = time + 24 * 60L * 60L * 1000L + val tca = (aos + los) / 2 val az = Math.toDegrees(satPos.azimuth) val elev = Math.toDegrees(satPos.elevation) val alt = satPos.altitude return SatPass(aos, az, los, az, tca, az, alt, elev, sat) } - private fun getLeoPass(sat: Satellite, pos: GeoPos, date: Date, rewind: Boolean): SatPass { + private fun getLeoPass(sat: Satellite, pos: GeoPos, time: Long, rewind: Boolean): SatPass { val quarterOrbitMin = (sat.orbitalPeriod / 4.0).toInt() - val calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { - clear() - timeInMillis = date.time - } + var calendarTimeMillis = time var elevation: Double var maxElevation = 0.0 var alt = 0.0 var tcaAz = 0.0 // rewind 1/4 of an orbit - if (rewind) calendar.add(Calendar.MINUTE, -quarterOrbitMin) + if (rewind) calendarTimeMillis += -quarterOrbitMin * 60L * 1000L - var satPos = sat.getPosition(pos, calendar.time.time) + var satPos = sat.getPosition(pos, calendarTimeMillis) if (satPos.elevation > 0.0) { // move forward in 30 second intervals until the sat goes below the horizon do { - calendar.add(Calendar.SECOND, 30) - satPos = sat.getPosition(pos, calendar.time.time) + calendarTimeMillis += 30 * 1000L + satPos = sat.getPosition(pos, calendarTimeMillis) } while (satPos.elevation > 0.0) // move forward 3/4 of an orbit - calendar.add(Calendar.MINUTE, quarterOrbitMin * 3) + calendarTimeMillis += quarterOrbitMin * 3 * 60L * 1000L } // find the next time sat comes above the horizon do { - calendar.add(Calendar.SECOND, 60) - satPos = sat.getPosition(pos, calendar.time.time) + calendarTimeMillis += 60L * 1000L + satPos = sat.getPosition(pos, calendarTimeMillis) elevation = satPos.elevation if (elevation > maxElevation) { maxElevation = elevation @@ -164,10 +160,10 @@ class Predictor(private val predictorDispatcher: CoroutineDispatcher) { } while (satPos.elevation < 0.0) // refine to 3 seconds - calendar.add(Calendar.SECOND, -60) + calendarTimeMillis += -60L * 1000L do { - calendar.add(Calendar.SECOND, 3) - satPos = sat.getPosition(pos, calendar.time.time) + calendarTimeMillis += 3L * 1000L + satPos = sat.getPosition(pos, calendarTimeMillis) elevation = satPos.elevation if (elevation > maxElevation) { maxElevation = elevation @@ -181,8 +177,8 @@ class Predictor(private val predictorDispatcher: CoroutineDispatcher) { // find when sat goes below do { - calendar.add(Calendar.SECOND, 30) - satPos = sat.getPosition(pos, calendar.time.time) + calendarTimeMillis += 30L * 1000L + satPos = sat.getPosition(pos, calendarTimeMillis) elevation = satPos.elevation if (elevation > maxElevation) { maxElevation = elevation @@ -192,10 +188,10 @@ class Predictor(private val predictorDispatcher: CoroutineDispatcher) { } while (satPos.elevation > 0.0) // refine to 3 seconds - calendar.add(Calendar.SECOND, -30) + calendarTimeMillis += -30L * 1000L do { - calendar.add(Calendar.SECOND, 3) - satPos = sat.getPosition(pos, calendar.time.time) + calendarTimeMillis += 3L * 1000L + satPos = sat.getPosition(pos, calendarTimeMillis) elevation = satPos.elevation if (elevation > maxElevation) { maxElevation = elevation @@ -206,7 +202,7 @@ class Predictor(private val predictorDispatcher: CoroutineDispatcher) { val los = satPos.time val losAz = Math.toDegrees(satPos.azimuth) - val tca = Date((aos + los) / 2).time + val tca = (aos + los) / 2 val elev = Math.toDegrees(maxElevation) return SatPass(aos, aosAz, los, losAz, tca, tcaAz, alt, elev, sat) } diff --git a/core/src/main/java/com/rtbishop/look4sat/domain/predict/Satellite.kt b/core/src/main/java/com/rtbishop/look4sat/domain/predict/Satellite.kt index 4d11a8b6..8f9e8dc2 100644 --- a/core/src/main/java/com/rtbishop/look4sat/domain/predict/Satellite.kt +++ b/core/src/main/java/com/rtbishop/look4sat/domain/predict/Satellite.kt @@ -17,8 +17,6 @@ */ package com.rtbishop.look4sat.domain.predict -import java.util.* -import java.util.concurrent.atomic.AtomicReference import kotlin.math.* abstract class Satellite(val params: TLE) { @@ -30,6 +28,7 @@ abstract class Satellite(val params: TLE) { private val epsilon = 1.0E-12 private val position = Vector4() private val velocity = Vector4() + private var gsPosTheta = 0.0 private var perigee = 0.0 val orbitalPeriod = 24 * 60 / params.meanmo val earthRadius = 6378.137 @@ -74,10 +73,7 @@ abstract class Satellite(val params: TLE) { // Read the system clock and return the number of days since 31Dec79 00:00:00 UTC (daynum 0) private fun calcCurrentDaynum(now: Long): Double { - val sgp4Epoch = Calendar.getInstance(TimeZone.getTimeZone("UTC:UTC")) - sgp4Epoch.clear() - sgp4Epoch[1979, 11, 31, 0, 0] = 0 - val then = sgp4Epoch.timeInMillis + val then = 315446400000 // time in millis on 31Dec79 00:00:00 UTC (daynum 0) val millis = now - then return millis / 1000.0 / 60.0 / 60.0 / 24.0 } @@ -124,8 +120,7 @@ abstract class Satellite(val params: TLE) { val obsVel = Vector4() val range = Vector4() val rgvel = Vector4() - val gsPosTheta = AtomicReference() - calculateUserPosVel(julianUTC, gsPos, gsPosTheta, obsPos, obsVel) + calculateUserPosVel(julianUTC, gsPos, obsPos, obsVel) range.setXYZ( positionVector.x - obsPos.x, positionVector.y - obsPos.y, @@ -141,8 +136,8 @@ abstract class Satellite(val params: TLE) { magnitude(range) val sinLat = sin(deg2Rad * gsPos.latitude) val cosLat = cos(deg2Rad * gsPos.latitude) - val sinTheta = sin(gsPosTheta.get()) - val cosTheta = cos(gsPosTheta.get()) + val sinTheta = sin(gsPosTheta) + val cosTheta = cos(gsPosTheta) val topS = sinLat * cosTheta * range.x + sinLat * sinTheta * range.y - cosLat * range.z val topE = -sinTheta * range.x + cosTheta * range.y val topZ = cosLat * cosTheta * range.x + cosLat * sinTheta * range.y + sinLat * range.z @@ -159,18 +154,17 @@ abstract class Satellite(val params: TLE) { private fun calculateUserPosVel( time: Double, gsPos: GeoPos, - gsPosTheta: AtomicReference, obsPos: Vector4, obsVel: Vector4 ) { val mFactor = 7.292115E-5 - gsPosTheta.set(mod2PI(thetaGJD(time) + deg2Rad * gsPos.longitude)) + gsPosTheta = mod2PI(thetaGJD(time) + deg2Rad * gsPos.longitude) val c = invert(sqrt(1.0 + flatFactor * (flatFactor - 2) * sqr(sin(deg2Rad * gsPos.latitude)))) val sq = sqr(1.0 - flatFactor) * c val achcp = (earthRadius * c) * cos(deg2Rad * gsPos.latitude) obsPos.setXYZ( - achcp * cos(gsPosTheta.get()), achcp * sin(gsPosTheta.get()), + achcp * cos(gsPosTheta), achcp * sin(gsPosTheta), (earthRadius * sq) * sin(deg2Rad * gsPos.latitude) ) obsVel.setXYZ(-mFactor * obsPos.y, mFactor * obsPos.x, 0.0)