kopia lustrzana https://github.com/rt-bishop/Look4Sat
Replaced original SatPassTime class with my own
rodzic
37c5ebbf2e
commit
33d25d3c25
|
@ -17,7 +17,6 @@
|
||||||
*/
|
*/
|
||||||
package com.rtbishop.look4sat.data.model
|
package com.rtbishop.look4sat.data.model
|
||||||
|
|
||||||
import com.github.amsacode.predict4java.SatPassTime
|
|
||||||
import com.github.amsacode.predict4java.Satellite
|
import com.github.amsacode.predict4java.Satellite
|
||||||
import com.rtbishop.look4sat.utility.PassPredictor
|
import com.rtbishop.look4sat.utility.PassPredictor
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Look4Sat. Amateur radio satellite tracker and pass predictor.
|
||||||
|
* Copyright (C) 2019-2021 Arty Bishop (bishop.arty@gmail.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.rtbishop.look4sat.data.model
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class SatPassTime(
|
||||||
|
private val startTime: Date,
|
||||||
|
private val endTime: Date,
|
||||||
|
val aosAzimuth: Int,
|
||||||
|
val losAzimuth: Int,
|
||||||
|
val maxEl: Double
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun getStartTime(): Date {
|
||||||
|
return Date(startTime.time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getEndTime(): Date {
|
||||||
|
return Date(endTime.time)
|
||||||
|
}
|
||||||
|
}
|
|
@ -72,10 +72,10 @@ class PassesRepo @Inject constructor(
|
||||||
this.time = refDate
|
this.time = refDate
|
||||||
this.add(Calendar.HOUR, hoursAhead)
|
this.add(Calendar.HOUR, hoursAhead)
|
||||||
}.time
|
}.time
|
||||||
passes.removeAll { it.pass.startTime.after(dateFuture) }
|
passes.removeAll { it.pass.getStartTime().after(dateFuture) }
|
||||||
passes.removeAll { it.pass.endTime.before(refDate) }
|
passes.removeAll { it.pass.getEndTime().before(refDate) }
|
||||||
passes.removeAll { it.pass.maxEl < prefsRepo.getMinElevation() }
|
passes.removeAll { it.pass.maxEl < prefsRepo.getMinElevation() }
|
||||||
passes.sortBy { it.pass.startTime }
|
passes.sortBy { it.pass.getStartTime() }
|
||||||
return passes
|
return passes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,9 +46,9 @@ class PassesAdapter(private val shouldUseUTC: Boolean = false) :
|
||||||
val satPass = iterator.next()
|
val satPass = iterator.next()
|
||||||
if (!satPass.satellite.tle.isDeepspace) {
|
if (!satPass.satellite.tle.isDeepspace) {
|
||||||
if (satPass.progress < 100) {
|
if (satPass.progress < 100) {
|
||||||
val timeStart = satPass.pass.startTime.time
|
val timeStart = satPass.pass.getStartTime().time
|
||||||
if (timeNow > timeStart) {
|
if (timeNow > timeStart) {
|
||||||
val timeEnd = satPass.pass.endTime.time
|
val timeEnd = satPass.pass.getEndTime().time
|
||||||
val index = satPassList.indexOf(satPass)
|
val index = satPassList.indexOf(satPass)
|
||||||
val deltaNow = timeNow.minus(timeStart).toFloat()
|
val deltaNow = timeNow.minus(timeStart).toFloat()
|
||||||
val deltaTotal = timeEnd.minus(timeStart).toFloat()
|
val deltaTotal = timeEnd.minus(timeStart).toFloat()
|
||||||
|
@ -115,9 +115,9 @@ class PassesAdapter(private val shouldUseUTC: Boolean = false) :
|
||||||
passLeoAosAz.text = String.format(aosAzFormat, satPass.pass.aosAzimuth)
|
passLeoAosAz.text = String.format(aosAzFormat, satPass.pass.aosAzimuth)
|
||||||
passLeoMaxEl.text = String.format(maxElFormat, satPass.pass.maxEl)
|
passLeoMaxEl.text = String.format(maxElFormat, satPass.pass.maxEl)
|
||||||
passLeoLosAz.text = String.format(losAzFormat, satPass.pass.losAzimuth)
|
passLeoLosAz.text = String.format(losAzFormat, satPass.pass.losAzimuth)
|
||||||
passLeoStart.text = startFormat.format(satPass.pass.startTime)
|
passLeoStart.text = startFormat.format(satPass.pass.getStartTime())
|
||||||
passLeoAlt.text = String.format(altFormat, satPos.altitude)
|
passLeoAlt.text = String.format(altFormat, satPos.altitude)
|
||||||
passLeoEnd.text = endFormat.format(satPass.pass.endTime)
|
passLeoEnd.text = endFormat.format(satPass.pass.getEndTime())
|
||||||
passLeoProgress.progress = satPass.progress
|
passLeoProgress.progress = satPass.progress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,12 +100,12 @@ class PassesFragment : Fragment(R.layout.fragment_passes) {
|
||||||
private fun tickMainTimer(timeNow: Long) {
|
private fun tickMainTimer(timeNow: Long) {
|
||||||
if (passes.isNotEmpty()) {
|
if (passes.isNotEmpty()) {
|
||||||
try {
|
try {
|
||||||
val nextPass = passes.first { it.pass.startTime.time.minus(timeNow) > 0 }
|
val nextPass = passes.first { it.pass.getStartTime().time.minus(timeNow) > 0 }
|
||||||
val millisBeforeStart = nextPass.pass.startTime.time.minus(timeNow)
|
val millisBeforeStart = nextPass.pass.getStartTime().time.minus(timeNow)
|
||||||
binding?.passesTimer?.text = millisBeforeStart.formatForTimer()
|
binding?.passesTimer?.text = millisBeforeStart.formatForTimer()
|
||||||
} catch (e: NoSuchElementException) {
|
} catch (e: NoSuchElementException) {
|
||||||
val lastPass = passes.last()
|
val lastPass = passes.last()
|
||||||
val millisBeforeEnd = lastPass.pass.endTime.time.minus(timeNow)
|
val millisBeforeEnd = lastPass.pass.getEndTime().time.minus(timeNow)
|
||||||
binding?.passesTimer?.text = millisBeforeEnd.formatForTimer()
|
binding?.passesTimer?.text = millisBeforeEnd.formatForTimer()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -30,7 +30,6 @@ import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||||
import com.rtbishop.look4sat.R
|
import com.rtbishop.look4sat.R
|
||||||
import com.rtbishop.look4sat.data.model.Result
|
|
||||||
import com.rtbishop.look4sat.data.model.SatPass
|
import com.rtbishop.look4sat.data.model.SatPass
|
||||||
import com.rtbishop.look4sat.databinding.FragmentPolarBinding
|
import com.rtbishop.look4sat.databinding.FragmentPolarBinding
|
||||||
import com.rtbishop.look4sat.utility.RecyclerDivider
|
import com.rtbishop.look4sat.utility.RecyclerDivider
|
||||||
|
@ -57,7 +56,7 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
||||||
binding = FragmentPolarBinding.bind(view)
|
binding = FragmentPolarBinding.bind(view)
|
||||||
sensorManager = requireContext().getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
sensorManager = requireContext().getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
||||||
magneticDeclination = viewModel.getMagDeclination()
|
magneticDeclination = viewModel.getMagDeclination()
|
||||||
observePasses()
|
observePass()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
@ -92,15 +91,23 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
||||||
polarView?.rotation = -(roundedAzimuth + magneticDeclination)
|
polarView?.rotation = -(roundedAzimuth + magneticDeclination)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observePasses() {
|
private fun observePass() {
|
||||||
viewModel.getPasses().observe(viewLifecycleOwner, { result ->
|
val passId = requireArguments().getInt("index")
|
||||||
if (result is Result.Success) {
|
viewModel.getPass(passId).observe(viewLifecycleOwner, { pass ->
|
||||||
satPass = result.data[requireArguments().getInt("index")]
|
satPass = pass
|
||||||
polarView = PolarView(requireContext()).apply { setPass(satPass) }
|
polarView = PolarView(requireContext()).apply { setPass(pass) }
|
||||||
binding.frame.addView(polarView)
|
binding.frame.addView(polarView)
|
||||||
observeTransmitters()
|
observeTransmitters()
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// viewModel.getPasses().observe(viewLifecycleOwner, { result ->
|
||||||
|
// if (result is Result.Success) {
|
||||||
|
// satPass = result.data[requireArguments().getInt("index")]
|
||||||
|
// polarView = PolarView(requireContext()).apply { setPass(satPass) }
|
||||||
|
// binding.frame.addView(polarView)
|
||||||
|
// observeTransmitters()
|
||||||
|
// }
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeTransmitters() {
|
private fun observeTransmitters() {
|
||||||
|
@ -148,13 +155,13 @@ class PolarFragment : Fragment(R.layout.fragment_polar), SensorEventListener {
|
||||||
binding.altitude.text = String.format(polarAlt, satPos.altitude)
|
binding.altitude.text = String.format(polarAlt, satPos.altitude)
|
||||||
|
|
||||||
if (!satPass.satellite.tle.isDeepspace) {
|
if (!satPass.satellite.tle.isDeepspace) {
|
||||||
if (dateNow.before(satPass.pass.startTime)) {
|
if (dateNow.before(satPass.pass.getStartTime())) {
|
||||||
val millisBeforeStart = satPass.pass.startTime.time.minus(timeNow)
|
val millisBeforeStart = satPass.pass.getStartTime().time.minus(timeNow)
|
||||||
binding.polarTimer.text = millisBeforeStart.formatForTimer()
|
binding.polarTimer.text = millisBeforeStart.formatForTimer()
|
||||||
} else {
|
} else {
|
||||||
val millisBeforeEnd = satPass.pass.endTime.time.minus(timeNow)
|
val millisBeforeEnd = satPass.pass.getEndTime().time.minus(timeNow)
|
||||||
binding.polarTimer.text = millisBeforeEnd.formatForTimer()
|
binding.polarTimer.text = millisBeforeEnd.formatForTimer()
|
||||||
if (dateNow.after(satPass.pass.endTime)) {
|
if (dateNow.after(satPass.pass.getEndTime())) {
|
||||||
binding.polarTimer.text = 0L.formatForTimer()
|
binding.polarTimer.text = 0L.formatForTimer()
|
||||||
findNavController().popBackStack()
|
findNavController().popBackStack()
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,13 +92,13 @@ class PolarView(context: Context) : View(context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun drawPassTrajectory(cvs: Canvas, satPass: SatPass) {
|
private fun drawPassTrajectory(cvs: Canvas, satPass: SatPass) {
|
||||||
val startTime = satPass.pass.startTime
|
val startTime = satPass.pass.getStartTime()
|
||||||
val endTime = satPass.pass.endTime
|
val endTime = satPass.pass.getEndTime()
|
||||||
while (startTime.before(endTime)) {
|
while (startTime.before(endTime)) {
|
||||||
val satPos = satPass.predictor.getSatPos(startTime)
|
val satPos = satPass.predictor.getSatPos(startTime)
|
||||||
val x = sph2CartX(satPos.azimuth, satPos.elevation, radius.toDouble())
|
val x = sph2CartX(satPos.azimuth, satPos.elevation, radius.toDouble())
|
||||||
val y = sph2CartY(satPos.azimuth, satPos.elevation, radius.toDouble())
|
val y = sph2CartY(satPos.azimuth, satPos.elevation, radius.toDouble())
|
||||||
if (startTime.compareTo(satPass.pass.startTime) == 0) {
|
if (startTime.compareTo(satPass.pass.getStartTime()) == 0) {
|
||||||
path.moveTo(x, -y)
|
path.moveTo(x, -y)
|
||||||
} else {
|
} else {
|
||||||
path.lineTo(x, -y)
|
path.lineTo(x, -y)
|
||||||
|
|
|
@ -20,11 +20,14 @@ package com.rtbishop.look4sat.ui.polarScreen
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.asLiveData
|
import androidx.lifecycle.asLiveData
|
||||||
import androidx.lifecycle.liveData
|
import androidx.lifecycle.liveData
|
||||||
|
import com.rtbishop.look4sat.data.model.Result
|
||||||
|
import com.rtbishop.look4sat.data.model.SatPass
|
||||||
import com.rtbishop.look4sat.data.repository.PassesRepo
|
import com.rtbishop.look4sat.data.repository.PassesRepo
|
||||||
import com.rtbishop.look4sat.data.repository.PrefsRepo
|
import com.rtbishop.look4sat.data.repository.PrefsRepo
|
||||||
import com.rtbishop.look4sat.data.repository.SatelliteRepo
|
import com.rtbishop.look4sat.data.repository.SatelliteRepo
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
|
@ -41,6 +44,14 @@ class PolarViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getPass(passId: Int) = liveData {
|
||||||
|
passesRepo.passes.collect { passes ->
|
||||||
|
if (passes is Result.Success) {
|
||||||
|
emit(passes.data[passId])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getPasses() = passesRepo.passes.asLiveData()
|
fun getPasses() = passesRepo.passes.asLiveData()
|
||||||
|
|
||||||
fun shouldUseCompass(): Boolean {
|
fun shouldUseCompass(): Boolean {
|
||||||
|
|
|
@ -18,19 +18,30 @@
|
||||||
package com.rtbishop.look4sat.utility
|
package com.rtbishop.look4sat.utility
|
||||||
|
|
||||||
import com.github.amsacode.predict4java.GroundStationPosition
|
import com.github.amsacode.predict4java.GroundStationPosition
|
||||||
import com.github.amsacode.predict4java.SatPassTime
|
|
||||||
import com.github.amsacode.predict4java.SatPos
|
import com.github.amsacode.predict4java.SatPos
|
||||||
import com.github.amsacode.predict4java.Satellite
|
import com.github.amsacode.predict4java.Satellite
|
||||||
|
import com.rtbishop.look4sat.data.model.SatPassTime
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PassPredictor(private val satellite: Satellite, private val qth: GroundStationPosition) {
|
class PassPredictor(private val satellite: Satellite, private val qth: GroundStationPosition) {
|
||||||
|
|
||||||
private val oneQuarterOrbitMin = (24.0 * 60.0 / satellite.tle.meanmo / 4.0).toInt()
|
private val oneQuarterOrbitMin = (24.0 * 60.0 / satellite.tle.meanmo / 4.0).toInt()
|
||||||
|
private val speedOfLight = 2.99792458E8
|
||||||
|
|
||||||
|
fun getDownlinkFreq(freq: Long, date: Date): Long {
|
||||||
|
val rangeRate = getSatPos(date).rangeRate
|
||||||
|
return (freq.toDouble() * (speedOfLight - rangeRate * 1000.0) / speedOfLight).toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUplinkFreq(freq: Long, date: Date): Long {
|
||||||
|
val rangeRate = getSatPos(date).rangeRate
|
||||||
|
return (freq.toDouble() * (speedOfLight + rangeRate * 1000.0) / speedOfLight).toLong()
|
||||||
|
}
|
||||||
|
|
||||||
fun getSatPos(date: Date): SatPos {
|
fun getSatPos(date: Date): SatPos {
|
||||||
return satellite.getPosition(qth, date)
|
return satellite.getPosition(qth, date)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPositions(refDate: Date, stepSeconds: Int, minBefore: Int, minAfter: Int): List<SatPos> {
|
fun getPositions(refDate: Date, stepSeconds: Int, minBefore: Int, minAfter: Int): List<SatPos> {
|
||||||
val positions = mutableListOf<SatPos>()
|
val positions = mutableListOf<SatPos>()
|
||||||
val endDate = Date(refDate.time + minAfter * 60L * 1000L)
|
val endDate = Date(refDate.time + minAfter * 60L * 1000L)
|
||||||
|
@ -57,9 +68,10 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta
|
||||||
do {
|
do {
|
||||||
if (count > 0) shouldWindBack = false
|
if (count > 0) shouldWindBack = false
|
||||||
val pass = nextNearEarthPass(startDate, shouldWindBack)
|
val pass = nextNearEarthPass(startDate, shouldWindBack)
|
||||||
lastAosDate = pass.startTime
|
lastAosDate = pass.getStartTime()
|
||||||
passes.add(pass)
|
passes.add(pass)
|
||||||
startDate = Date(pass.endTime.time + (oneQuarterOrbitMin * 3) * 60L * 1000L)
|
startDate =
|
||||||
|
Date(pass.getEndTime().time + (oneQuarterOrbitMin * 3) * 60L * 1000L)
|
||||||
count++
|
count++
|
||||||
} while (lastAosDate < endDate)
|
} while (lastAosDate < endDate)
|
||||||
}
|
}
|
||||||
|
@ -73,7 +85,7 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta
|
||||||
val endDate = Date(refDate.time + 24 * 60L * 60L * 1000L)
|
val endDate = Date(refDate.time + 24 * 60L * 60L * 1000L)
|
||||||
val azimuth = Math.toDegrees(satPos.azimuth).toInt()
|
val azimuth = Math.toDegrees(satPos.azimuth).toInt()
|
||||||
val maxEl = Math.toDegrees(satPos.elevation)
|
val maxEl = Math.toDegrees(satPos.elevation)
|
||||||
return SatPassTime(startDate, endDate, "pole", azimuth, azimuth, maxEl)
|
return SatPassTime(startDate, endDate, azimuth, azimuth, maxEl)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nextNearEarthPass(refDate: Date, windBack: Boolean = false): SatPassTime {
|
private fun nextNearEarthPass(refDate: Date, windBack: Boolean = false): SatPassTime {
|
||||||
|
@ -138,6 +150,6 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundSta
|
||||||
val endDate = satPos.time
|
val endDate = satPos.time
|
||||||
val losAzimuth = Math.toDegrees(satPos.azimuth).toInt()
|
val losAzimuth = Math.toDegrees(satPos.azimuth).toInt()
|
||||||
val maxEl = Math.toDegrees(maxElevation)
|
val maxEl = Math.toDegrees(maxElevation)
|
||||||
return SatPassTime(startDate, endDate, "pole", aosAzimuth, losAzimuth, maxEl)
|
return SatPassTime(startDate, endDate, aosAzimuth, losAzimuth, maxEl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
gradle_version = '4.1.2'
|
gradle_version = '4.1.3'
|
||||||
gradle_plugin_version = '1.4.31'
|
gradle_plugin_version = '1.4.31'
|
||||||
material_version = '1.3.0'
|
material_version = '1.3.0'
|
||||||
constraint_layout_version = '2.0.4'
|
constraint_layout_version = '2.0.4'
|
||||||
|
|
Ładowanie…
Reference in New Issue