mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 19:17:21 +00:00
Extracted MapView class to a separate file, code refactoring
This commit is contained in:
1 parent
67f98101aa
commit
32df8c4c04
2 files changed
+192
-186
No files matched your search
@@ -19,19 +19,14 @@
|
||||
|
||||
package com.rtbishop.look4sat.ui.fragments
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.github.amsacode.predict4java.GroundStationPosition
|
||||
import com.github.amsacode.predict4java.Position
|
||||
import com.github.amsacode.predict4java.SatPos
|
||||
import com.github.amsacode.predict4java.TLE
|
||||
import com.rtbishop.look4sat.Look4SatApp
|
||||
import com.rtbishop.look4sat.R
|
||||
@@ -41,13 +36,12 @@ import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.databinding.FragmentMapViewBinding
|
||||
import com.rtbishop.look4sat.ui.MainActivity
|
||||
import com.rtbishop.look4sat.ui.SharedViewModel
|
||||
import com.rtbishop.look4sat.ui.views.MapView
|
||||
import com.rtbishop.look4sat.utility.GeneralUtils
|
||||
import com.rtbishop.look4sat.utility.PassPredictor
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
|
||||
class MapViewFragment : Fragment(R.layout.fragment_map_view) {
|
||||
|
||||
@@ -58,13 +52,14 @@ class MapViewFragment : Fragment(R.layout.fragment_map_view) {
|
||||
private lateinit var mapView: MapView
|
||||
private lateinit var predictor: PassPredictor
|
||||
private lateinit var selectedSat: TLE
|
||||
private lateinit var binding: FragmentMapViewBinding
|
||||
private var gsp = GroundStationPosition(0.0, 0.0, 0.0)
|
||||
private var satPassList = emptyList<SatPass>()
|
||||
private var checkedItem = 0
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val binding = FragmentMapViewBinding.bind(view)
|
||||
binding = FragmentMapViewBinding.bind(view)
|
||||
mainActivity = activity as MainActivity
|
||||
(mainActivity.application as Look4SatApp).appComponent.inject(this)
|
||||
viewModel = ViewModelProvider(mainActivity, modelFactory).get(SharedViewModel::class.java)
|
||||
@@ -97,7 +92,10 @@ class MapViewFragment : Fragment(R.layout.fragment_map_view) {
|
||||
binding.fabMap.setOnClickListener { showSelectSatDialog(satPassList) }
|
||||
selectedSat = satPassList.first().tle
|
||||
predictor = satPassList.first().predictor
|
||||
mapView = MapView(mainActivity, binding)
|
||||
mapView = MapView(mainActivity)
|
||||
mapView.setList(satPassList)
|
||||
mapView.setGSP(gsp)
|
||||
mapView.setChecked(checkedItem)
|
||||
binding.frameMap.addView(mapView)
|
||||
refreshView()
|
||||
} else {
|
||||
@@ -115,6 +113,7 @@ class MapViewFragment : Fragment(R.layout.fragment_map_view) {
|
||||
lifecycleScope.launch {
|
||||
while (true) {
|
||||
mapView.invalidate()
|
||||
setTextViewsToSelectedSatPos()
|
||||
delay(viewModel.getRefreshRate())
|
||||
}
|
||||
}
|
||||
@@ -133,6 +132,9 @@ class MapViewFragment : Fragment(R.layout.fragment_map_view) {
|
||||
checkedItem = which
|
||||
selectedSat = list[which].tle
|
||||
predictor = list[which].predictor
|
||||
mapView.setList(satPassList)
|
||||
mapView.setGSP(gsp)
|
||||
mapView.setChecked(checkedItem)
|
||||
mapView.invalidate()
|
||||
dialog.dismiss()
|
||||
}
|
||||
@@ -140,184 +142,18 @@ class MapViewFragment : Fragment(R.layout.fragment_map_view) {
|
||||
.show()
|
||||
}
|
||||
|
||||
inner class MapView(context: Context, private val binding: FragmentMapViewBinding) :
|
||||
View(context) {
|
||||
private val scale = resources.displayMetrics.density
|
||||
private val groundTrackPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(mainActivity, R.color.satTrack)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val satPaintPrim = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(mainActivity, R.color.satPrimary)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val satPaintSec = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(mainActivity, R.color.satSecondary)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val txtPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(mainActivity, R.color.satPrimary)
|
||||
style = Paint.Style.FILL
|
||||
strokeWidth = scale
|
||||
textSize = 16f
|
||||
setShadowLayer(2f, 2f, 2f, Color.BLACK)
|
||||
}
|
||||
private val outlinePaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = Color.BLACK
|
||||
style = Paint.Style.FILL_AND_STROKE
|
||||
strokeWidth = scale
|
||||
textSize = 16f
|
||||
}
|
||||
private val rect = Rect()
|
||||
private fun setTextViewsToSelectedSatPos() {
|
||||
val currentTime = GeneralUtils.getDateFor(System.currentTimeMillis())
|
||||
val orbitalPeriod = (24 * 60 / selectedSat.meanmo).toInt()
|
||||
val positions = predictor.getPositions(currentTime, 60, 0, orbitalPeriod * 3)
|
||||
var lon = GeneralUtils.rad2Deg(positions[0].longitude).toFloat()
|
||||
val lat = GeneralUtils.rad2Deg(positions[0].latitude).toFloat()
|
||||
val rng = positions[0].range
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
canvas.translate(width / 2f, height / 2f)
|
||||
val degLon = width / 360f
|
||||
val degLat = height / 180f
|
||||
drawHomeLoc(canvas, degLon, degLat)
|
||||
val currentTime = GeneralUtils.getDateFor(System.currentTimeMillis())
|
||||
val orbitalPeriod = (24 * 60 / selectedSat.meanmo).toInt()
|
||||
val positions = predictor.getPositions(currentTime, 60, 0, orbitalPeriod * 3)
|
||||
setTextViewsToSelectedSatPos(positions[0])
|
||||
drawGroundTrack(canvas, degLon, degLat, positions)
|
||||
satPassList.forEach {
|
||||
drawSat(canvas, degLon, degLat, it.tle, it.predictor, currentTime, satPaintSec)
|
||||
}
|
||||
drawSat(
|
||||
canvas,
|
||||
degLon,
|
||||
degLat,
|
||||
satPassList[checkedItem].tle,
|
||||
satPassList[checkedItem].predictor,
|
||||
currentTime,
|
||||
satPaintPrim
|
||||
)
|
||||
}
|
||||
if (lon > 180f) lon -= 360f
|
||||
|
||||
private fun drawHomeLoc(canvas: Canvas, degLon: Float, degLat: Float) {
|
||||
val lon = gsp.longitude.toFloat()
|
||||
val lat = gsp.latitude.toFloat() * -1
|
||||
val cx = lon * degLon
|
||||
val cy = lat * degLat
|
||||
val gspName = context.getString(R.string.map_gsp)
|
||||
txtPaint.getTextBounds(gspName, 0, gspName.length, rect)
|
||||
canvas.drawCircle(cx, cy, scale * 2, txtPaint)
|
||||
canvas.drawText(gspName, cx - rect.width() / 2, cy - txtPaint.textSize, outlinePaint)
|
||||
canvas.drawText(gspName, cx - rect.width() / 2, cy - txtPaint.textSize, txtPaint)
|
||||
|
||||
}
|
||||
|
||||
private fun setTextViewsToSelectedSatPos(position: SatPos) {
|
||||
var lon = GeneralUtils.rad2Deg(position.longitude).toFloat()
|
||||
val lat = GeneralUtils.rad2Deg(position.latitude).toFloat()
|
||||
val rng = position.range
|
||||
|
||||
if (lon > 180f) lon -= 360f
|
||||
|
||||
binding.tvMapLat.text = String.format(context.getString(R.string.pat_latitude), lat)
|
||||
binding.tvMapLon.text = String.format(context.getString(R.string.pat_longitude), lon)
|
||||
binding.tvMapRng.text = String.format(context.getString(R.string.pat_range), rng)
|
||||
}
|
||||
|
||||
private fun drawGroundTrack(
|
||||
canvas: Canvas,
|
||||
degLon: Float,
|
||||
degLat: Float,
|
||||
list: List<SatPos>
|
||||
) {
|
||||
val path = Path()
|
||||
var lon: Float
|
||||
var lat: Float
|
||||
var lastLon = 181f
|
||||
|
||||
list.withIndex().forEach { (index, satPos) ->
|
||||
lon = GeneralUtils.rad2Deg(satPos.longitude).toFloat()
|
||||
lat = GeneralUtils.rad2Deg(satPos.latitude).toFloat() * -1
|
||||
|
||||
if (lon > 180f) lon -= 360f
|
||||
|
||||
lon *= degLon
|
||||
lat *= degLat
|
||||
|
||||
if (index == 0 || abs(lon - lastLon) > 180) path.moveTo(lon, lat)
|
||||
else path.lineTo(lon, lat)
|
||||
|
||||
lastLon = lon
|
||||
}
|
||||
canvas.drawPath(path, groundTrackPaint)
|
||||
}
|
||||
|
||||
private fun drawSat(
|
||||
canvas: Canvas,
|
||||
degLon: Float,
|
||||
degLat: Float,
|
||||
tle: TLE,
|
||||
predictor: PassPredictor,
|
||||
date: Date,
|
||||
paint: Paint
|
||||
) {
|
||||
val satPosNow = predictor.getSatPos(date)
|
||||
val footprintPosList = satPosNow.rangeCircle
|
||||
drawFootprint(canvas, degLon, degLat, footprintPosList, paint)
|
||||
drawName(canvas, degLon, degLat, satPosNow, tle.name)
|
||||
}
|
||||
|
||||
private fun drawFootprint(
|
||||
canvas: Canvas,
|
||||
degLon: Float,
|
||||
degLat: Float,
|
||||
list: List<Position>,
|
||||
paint: Paint
|
||||
) {
|
||||
val path = Path()
|
||||
var lon: Float
|
||||
var lat: Float
|
||||
var lastLon = 181f
|
||||
|
||||
list.withIndex().forEach { (index, position) ->
|
||||
lon = position.lon.toFloat()
|
||||
lat = position.lat.toFloat() * -1
|
||||
|
||||
if (lon > 180f) lon -= 360f
|
||||
|
||||
lon *= degLon
|
||||
lat *= degLat
|
||||
|
||||
if (index == 0 || abs(lon - lastLon) > 180) path.moveTo(lon, lat)
|
||||
else path.lineTo(lon, lat)
|
||||
|
||||
lastLon = lon
|
||||
}
|
||||
canvas.drawPath(path, paint)
|
||||
}
|
||||
|
||||
private fun drawName(
|
||||
canvas: Canvas,
|
||||
degLon: Float,
|
||||
degLat: Float,
|
||||
position: SatPos,
|
||||
name: String
|
||||
) {
|
||||
var lon = GeneralUtils.rad2Deg(position.longitude).toFloat()
|
||||
val lat = GeneralUtils.rad2Deg(position.latitude).toFloat() * -1
|
||||
|
||||
if (lon > 180f) lon -= 360f
|
||||
|
||||
val cx = lon * degLon
|
||||
val cy = lat * degLat
|
||||
|
||||
canvas.drawCircle(cx, cy, scale * 2, txtPaint)
|
||||
txtPaint.getTextBounds(name, 0, name.length, rect)
|
||||
canvas.drawText(name, cx - rect.width() / 2, cy - txtPaint.textSize, outlinePaint)
|
||||
canvas.drawText(name, cx - rect.width() / 2, cy - txtPaint.textSize, txtPaint)
|
||||
}
|
||||
binding.tvMapLat.text = String.format(mainActivity.getString(R.string.pat_latitude), lat)
|
||||
binding.tvMapLon.text = String.format(mainActivity.getString(R.string.pat_longitude), lon)
|
||||
binding.tvMapRng.text = String.format(mainActivity.getString(R.string.pat_range), rng)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package com.rtbishop.look4sat.ui.views
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.github.amsacode.predict4java.GroundStationPosition
|
||||
import com.github.amsacode.predict4java.Position
|
||||
import com.github.amsacode.predict4java.SatPos
|
||||
import com.github.amsacode.predict4java.TLE
|
||||
import com.rtbishop.look4sat.R
|
||||
import com.rtbishop.look4sat.data.SatPass
|
||||
import com.rtbishop.look4sat.utility.GeneralUtils
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
|
||||
class MapView(context: Context) : View(context) {
|
||||
|
||||
private lateinit var passList: List<SatPass>
|
||||
private lateinit var gsp: GroundStationPosition
|
||||
private lateinit var selectedSat: TLE
|
||||
private val scale = resources.displayMetrics.density
|
||||
private val groundTrackPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(context, R.color.satTrack)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val satPaintPrim = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(context, R.color.satPrimary)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val satPaintSec = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(context, R.color.satSecondary)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = scale
|
||||
}
|
||||
private val txtPaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = ContextCompat.getColor(context, R.color.satPrimary)
|
||||
style = Paint.Style.FILL
|
||||
strokeWidth = scale
|
||||
textSize = 16f
|
||||
setShadowLayer(2f, 2f, 2f, Color.BLACK)
|
||||
}
|
||||
private val outlinePaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = Color.BLACK
|
||||
style = Paint.Style.FILL_AND_STROKE
|
||||
strokeWidth = scale
|
||||
textSize = 16f
|
||||
}
|
||||
private val rect = Rect()
|
||||
private var checked = 0
|
||||
private var degLon = 0f
|
||||
private var degLat = 0f
|
||||
|
||||
fun setList(satPassList: List<SatPass>) {
|
||||
passList = satPassList
|
||||
}
|
||||
|
||||
fun setGSP(groundStationPosition: GroundStationPosition) {
|
||||
gsp = groundStationPosition
|
||||
}
|
||||
|
||||
fun setChecked(item: Int) {
|
||||
checked = item
|
||||
selectedSat = passList[checked].tle
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
degLon = width / 360f
|
||||
degLat = height / 180f
|
||||
canvas.translate(width / 2f, height / 2f)
|
||||
drawHomeLoc(canvas)
|
||||
val currentTime = GeneralUtils.getDateFor(System.currentTimeMillis())
|
||||
val orbitalPeriod = (24 * 60 / selectedSat.meanmo).toInt()
|
||||
val predictor = passList[checked].predictor
|
||||
val positions = predictor.getPositions(currentTime, 60, 0, orbitalPeriod * 3)
|
||||
drawGroundTrack(canvas, positions)
|
||||
passList.forEach { satPass -> drawSat(canvas, satPass, currentTime, satPaintSec) }
|
||||
drawSat(canvas, passList[checked], currentTime, satPaintPrim)
|
||||
}
|
||||
|
||||
private fun drawHomeLoc(canvas: Canvas) {
|
||||
val lon = gsp.longitude.toFloat()
|
||||
val lat = gsp.latitude.toFloat() * -1
|
||||
val cx = lon * degLon
|
||||
val cy = lat * degLat
|
||||
val gspName = context.getString(R.string.map_gsp)
|
||||
txtPaint.getTextBounds(gspName, 0, gspName.length, rect)
|
||||
canvas.drawCircle(cx, cy, scale * 2, txtPaint)
|
||||
canvas.drawText(gspName, cx - rect.width() / 2, cy - txtPaint.textSize, outlinePaint)
|
||||
canvas.drawText(gspName, cx - rect.width() / 2, cy - txtPaint.textSize, txtPaint)
|
||||
|
||||
}
|
||||
|
||||
private fun drawGroundTrack(canvas: Canvas, list: List<SatPos>) {
|
||||
val path = Path()
|
||||
var lon: Float
|
||||
var lat: Float
|
||||
var lastLon = 181f
|
||||
|
||||
list.withIndex().forEach { (index, satPos) ->
|
||||
lon = GeneralUtils.rad2Deg(satPos.longitude).toFloat()
|
||||
lat = GeneralUtils.rad2Deg(satPos.latitude).toFloat() * -1
|
||||
|
||||
if (lon > 180f) lon -= 360f
|
||||
|
||||
lon *= degLon
|
||||
lat *= degLat
|
||||
|
||||
if (index == 0 || abs(lon - lastLon) > 180) path.moveTo(lon, lat)
|
||||
else path.lineTo(lon, lat)
|
||||
|
||||
lastLon = lon
|
||||
}
|
||||
canvas.drawPath(path, groundTrackPaint)
|
||||
}
|
||||
|
||||
private fun drawSat(canvas: Canvas, satPass: SatPass, date: Date, paint: Paint) {
|
||||
val tle = satPass.tle
|
||||
val predictor = satPass.predictor
|
||||
val satPosNow = predictor.getSatPos(date)
|
||||
val footprintPosList = satPosNow.rangeCircle
|
||||
drawFootprint(canvas, footprintPosList, paint)
|
||||
drawName(canvas, satPosNow, tle.name)
|
||||
}
|
||||
|
||||
private fun drawFootprint(canvas: Canvas, list: List<Position>, paint: Paint) {
|
||||
val path = Path()
|
||||
var lon: Float
|
||||
var lat: Float
|
||||
var lastLon = 181f
|
||||
|
||||
list.withIndex().forEach { (index, position) ->
|
||||
lon = position.lon.toFloat()
|
||||
lat = position.lat.toFloat() * -1
|
||||
|
||||
if (lon > 180f) lon -= 360f
|
||||
|
||||
lon *= degLon
|
||||
lat *= degLat
|
||||
|
||||
if (index == 0 || abs(lon - lastLon) > 180) path.moveTo(lon, lat)
|
||||
else path.lineTo(lon, lat)
|
||||
|
||||
lastLon = lon
|
||||
}
|
||||
canvas.drawPath(path, paint)
|
||||
}
|
||||
|
||||
private fun drawName(canvas: Canvas, position: SatPos, name: String) {
|
||||
var lon = GeneralUtils.rad2Deg(position.longitude).toFloat()
|
||||
val lat = GeneralUtils.rad2Deg(position.latitude).toFloat() * -1
|
||||
|
||||
if (lon > 180f) lon -= 360f
|
||||
|
||||
val cx = lon * degLon
|
||||
val cy = lat * degLat
|
||||
|
||||
canvas.drawCircle(cx, cy, scale * 2, txtPaint)
|
||||
txtPaint.getTextBounds(name, 0, name.length, rect)
|
||||
canvas.drawText(name, cx - rect.width() / 2, cy - txtPaint.textSize, outlinePaint)
|
||||
canvas.drawText(name, cx - rect.width() / 2, cy - txtPaint.textSize, txtPaint)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user