Now drawing the ground track and the footprint of the test satellite (Meteor M2-2) on the WorldMap

This commit is contained in:
Arty Bishop committed 2019-12-02 23:07:21 +00:00
1 parent 396a216320
commit 6bf218d633
1 file changed
+142 -32
@@ -1,23 +1,28 @@
package com.rtbishop.lookingsat.ui
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.github.amsacode.predict4java.PassPredictor
import com.github.amsacode.predict4java.Position
import com.github.amsacode.predict4java.SatPos
import com.github.amsacode.predict4java.TLE
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.rtbishop.lookingsat.MainViewModel
import com.rtbishop.lookingsat.R
import kotlinx.coroutines.launch
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import kotlin.math.abs
import kotlin.math.roundToInt
class WorldMapFragment : Fragment() {
@@ -27,7 +32,7 @@ class WorldMapFragment : Fragment() {
private lateinit var viewModel: MainViewModel
private lateinit var trackView: TrackView
private lateinit var mapFrame: FrameLayout
private lateinit var fab: FloatingActionButton
// private lateinit var fab: FloatingActionButton
private lateinit var selectedSat: TLE
private lateinit var predictor: PassPredictor
@@ -47,13 +52,22 @@ class WorldMapFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mapFrame = view.findViewById(R.id.worldmap_frame)
fab = view.findViewById(R.id.worldmap_fab)
fab.setOnClickListener { showSelectSatDialog() }
// fab = view.findViewById(R.id.worldmap_fab)
// fab.setOnClickListener { showSelectSatDialog() }
selectedSat = viewModel.selectedSingleSat
lifecycleScope.launch {
predictor = PassPredictor(selectedSat, viewModel.gsp.value)
}
val tleString = arrayOf(
"METEOR-M2 2",
"1 44387U 19038A 19336.45319619 -.00000025 00000-0 80323-5 0 9996",
"2 44387 98.5920 295.7459 0002200 37.8724 322.2609 14.23335951 21369"
)
selectedSat = TLE(tleString)
predictor = PassPredictor(selectedSat, viewModel.gsp.value)
// selectedSat = viewModel.selectedSingleSat
// lifecycleScope.launch {
// predictor = PassPredictor(selectedSat, viewModel.gsp.value)
// }
trackView = TrackView(activity as MainActivity)
mapFrame.addView(trackView)
@@ -61,29 +75,125 @@ class WorldMapFragment : Fragment() {
service.scheduleAtFixedRate({ trackView.invalidate() }, delay, delay, TimeUnit.MILLISECONDS)
}
private fun showSelectSatDialog() {
val tleMainList = viewModel.tleMainList
val tleNameArray = arrayOfNulls<String>(tleMainList.size)
var selection = viewModel.selectedSingleSat
// private fun showSelectSatDialog() {
// val tleMainList = viewModel.tleMainList
// val tleNameArray = arrayOfNulls<String>(tleMainList.size)
// var selection = viewModel.selectedSingleSat
//
// tleMainList.withIndex().forEach { (position, tle) ->
// tleNameArray[position] = tle.name
// }
//
// val builder = AlertDialog.Builder(activity as MainActivity)
// builder.setTitle("Select Sat to track")
// .setSingleChoiceItems(tleNameArray, -1) { _, which ->
// selection = tleMainList[which]
// }
// .setPositiveButton("Ok") { _, _ ->
// viewModel.updateSelectedSingleSat(selection)
// }
// .setNegativeButton("Cancel") { dialog, _ ->
// dialog.cancel()
// }
// .create()
// .show()
// }
tleMainList.withIndex().forEach { (position, tle) ->
tleNameArray[position] = tle.name
inner class TrackView(context: Context) : View(context) {
private val groundTrackPaint = Paint().apply {
isAntiAlias = true
color = Color.RED
style = Paint.Style.STROKE
strokeWidth = scale
}
private val footprintPaint = Paint().apply {
isAntiAlias = true
color = Color.YELLOW
style = Paint.Style.STROKE
strokeWidth = scale
}
private val scale = resources.displayMetrics.density
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val frameWidth = mapFrame.measuredWidth
val frameHeight = mapFrame.measuredHeight
val currentTime = getDateFor(System.currentTimeMillis())
val orbitalPeriod = (24 * 60 / selectedSat.meanmo).toInt()
val orbitEndTime = getDateFor(currentTime.time + orbitalPeriod * 60 * 1000)
val satPos = predictor.getSatPos(currentTime)
val footprintPositions = satPos.rangeCircle
var positions = predictor.getPositions(currentTime, 60, orbitalPeriod, orbitalPeriod)
drawGroundTrack(canvas, frameWidth, frameHeight, positions)
positions = predictor.getPositions(orbitEndTime, 60, 1, orbitalPeriod)
drawGroundTrack(canvas, frameWidth, frameHeight, positions)
drawFootprint(canvas, frameWidth, frameHeight, footprintPositions)
var longitude = rad2Deg(satPos.longitude)
if (longitude > 180.0) {
longitude -= 180.0
} else {
longitude += 180.0
}
}
val builder = AlertDialog.Builder(activity as MainActivity)
builder.setTitle("Select Sat to track")
.setSingleChoiceItems(tleNameArray, -1) { _, which ->
selection = tleMainList[which]
}
.setPositiveButton("Ok") { _, _ ->
viewModel.updateSelectedSingleSat(selection)
}
.setNegativeButton("Cancel") { dialog, _ ->
dialog.cancel()
}
.create()
.show()
}
private fun drawGroundTrack(canvas: Canvas, width: Int, height: Int, list: List<SatPos>) {
val trackPath = Path()
var trackX: Float
var trackY: Float
var prevX = 181f
inner class TrackView(context: Context) : View(context)
list.withIndex().forEach { (index, satPos) ->
trackX = rad2Deg(satPos.longitude).toFloat()
if (trackX <= 180.0) trackX += 180
else trackX -= 180
trackX *= width / 360f
trackY = ((90.0 - rad2Deg(satPos.latitude)) * (height / 180.0))
.roundToInt()
.toFloat()
if (index == 0 || abs(trackX - prevX) > 180) trackPath.moveTo(trackX, trackY)
else trackPath.lineTo(trackX, trackY)
prevX = trackX
}
canvas.drawPath(trackPath, groundTrackPaint)
}
private fun drawFootprint(canvas: Canvas, width: Int, height: Int, list: List<Position>) {
val printPath = Path()
var printX: Float
var printY: Float
var prevX = 181f
list.withIndex().forEach { (index, position) ->
printX = position.lon.toFloat()
if (printX <= 180f) printX += 180f
else printX -= 180f
printX *= width / 360f
printY = ((90.0 - position.lat) * (height / 180.0))
.roundToInt()
.toFloat()
if (index == 0 || abs(printX - prevX) > 180) printPath.moveTo(printX, printY)
else printPath.lineTo(printX, printY)
prevX = printX
}
canvas.drawPath(printPath, footprintPaint)
}
private fun getDateFor(value: Long): Date {
return Date(value)
}
private fun rad2Deg(value: Double): Double {
return value * 180 / Math.PI
}
}
}