diff --git a/app/src/main/java/com/rtbishop/look4sat/di/ApplicationModule.kt b/app/src/main/java/com/rtbishop/look4sat/di/ApplicationModule.kt index 30307255..509e5f19 100644 --- a/app/src/main/java/com/rtbishop/look4sat/di/ApplicationModule.kt +++ b/app/src/main/java/com/rtbishop/look4sat/di/ApplicationModule.kt @@ -23,6 +23,7 @@ import android.content.SharedPreferences import android.hardware.SensorManager import android.location.LocationManager import androidx.preference.PreferenceManager +import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -33,6 +34,11 @@ import dagger.hilt.components.SingletonComponent @InstallIn(SingletonComponent::class) object ApplicationModule { + @Provides + fun provideQthConverter(): QthConverter { + return QthConverter() + } + @Provides fun provideContentResolver(@ApplicationContext context: Context): ContentResolver { return context.contentResolver diff --git a/app/src/main/java/com/rtbishop/look4sat/di/LocalSourceModule.kt b/app/src/main/java/com/rtbishop/look4sat/di/DataSourceModule.kt similarity index 78% rename from app/src/main/java/com/rtbishop/look4sat/di/LocalSourceModule.kt rename to app/src/main/java/com/rtbishop/look4sat/di/DataSourceModule.kt index c9110b21..d4bd46e9 100644 --- a/app/src/main/java/com/rtbishop/look4sat/di/LocalSourceModule.kt +++ b/app/src/main/java/com/rtbishop/look4sat/di/DataSourceModule.kt @@ -23,6 +23,8 @@ import com.rtbishop.look4sat.data.DefaultSatelliteRepo import com.rtbishop.look4sat.data.LocalDataSource import com.rtbishop.look4sat.data.RemoteDataSource import com.rtbishop.look4sat.domain.SatelliteRepo +import com.rtbishop.look4sat.framework.api.NetworkDataSource +import com.rtbishop.look4sat.framework.api.SatelliteService import com.rtbishop.look4sat.framework.db.RoomConverters import com.rtbishop.look4sat.framework.db.RoomDataSource import com.rtbishop.look4sat.framework.db.SatelliteDao @@ -34,15 +36,17 @@ import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import kotlinx.coroutines.CoroutineDispatcher +import retrofit2.Retrofit +import retrofit2.converter.moshi.MoshiConverterFactory import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -object LocalSourceModule { +object DataSourceModule { @Provides - fun provideLocalDataSource(satelliteDao: SatelliteDao): LocalDataSource { - return RoomDataSource(satelliteDao) + fun provideMoshi(): Moshi { + return Moshi.Builder().build() } @Provides @@ -56,8 +60,8 @@ object LocalSourceModule { } @Provides - fun provideMoshi(): Moshi { - return Moshi.Builder().build() + fun provideLocalDataSource(satelliteDao: SatelliteDao): LocalDataSource { + return RoomDataSource(satelliteDao) } @Provides @@ -70,4 +74,18 @@ object LocalSourceModule { RoomConverters.initialize(moshi) return Room.databaseBuilder(context, SatelliteDb::class.java, "SatelliteDb").build() } + + @Provides + fun provideRemoteDataSource(satelliteService: SatelliteService): RemoteDataSource { + return NetworkDataSource(satelliteService) + } + + @Provides + fun provideSatDataService(): SatelliteService { + return Retrofit.Builder() + .baseUrl("https://db.satnogs.org/api/") + .addConverterFactory(MoshiConverterFactory.create()) + .build() + .create(SatelliteService::class.java) + } } diff --git a/app/src/main/java/com/rtbishop/look4sat/di/InteractorsModule.kt b/app/src/main/java/com/rtbishop/look4sat/di/InteractorsModule.kt index ed445956..9c4a74b1 100644 --- a/app/src/main/java/com/rtbishop/look4sat/di/InteractorsModule.kt +++ b/app/src/main/java/com/rtbishop/look4sat/di/InteractorsModule.kt @@ -1,3 +1,20 @@ +/* + * 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 . + */ package com.rtbishop.look4sat.di import com.rtbishop.look4sat.domain.SatelliteRepo diff --git a/app/src/main/java/com/rtbishop/look4sat/di/RemoteSourceModule.kt b/app/src/main/java/com/rtbishop/look4sat/di/RemoteSourceModule.kt deleted file mode 100644 index e7a98b2e..00000000 --- a/app/src/main/java/com/rtbishop/look4sat/di/RemoteSourceModule.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 . - */ -package com.rtbishop.look4sat.di - -import com.rtbishop.look4sat.data.RemoteDataSource -import com.rtbishop.look4sat.framework.api.NetworkDataSource -import com.rtbishop.look4sat.framework.api.SatelliteService -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import retrofit2.Retrofit -import retrofit2.converter.moshi.MoshiConverterFactory - -@Module -@InstallIn(SingletonComponent::class) -object RemoteSourceModule { - - @Provides - fun provideRemoteDataSource(satelliteService: SatelliteService): RemoteDataSource { - return NetworkDataSource(satelliteService) - } - - @Provides - fun provideSatDataService(): SatelliteService { - return Retrofit.Builder() - .baseUrl("https://db.satnogs.org/api/") - .addConverterFactory(MoshiConverterFactory.create()) - .build() - .create(SatelliteService::class.java) - } -} diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/mapScreen/MapFragment.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/mapScreen/MapFragment.kt index 071fbccd..22e97d5a 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/mapScreen/MapFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/mapScreen/MapFragment.kt @@ -91,7 +91,7 @@ class MapFragment : Fragment(R.layout.fragment_map) { setInfoWindow(null) setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM) icon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_map_pos) - position = GeoPoint(osmPos.lat, osmPos.lon) + position = GeoPoint(osmPos.latitude, osmPos.longitude) mapView.overlays[0] = this mapView.invalidate() } @@ -105,8 +105,8 @@ class MapFragment : Fragment(R.layout.fragment_map) { altitude.text = String.format(getString(R.string.pat_altitude), sat.altitude) distance.text = String.format(getString(R.string.pat_distance), sat.range) velocity.text = String.format(getString(R.string.pat_osm_vel), sat.velocity) - mapLat.text = String.format(getString(R.string.pat_osm_lat), sat.osmPos.lat) - mapLon.text = String.format(getString(R.string.pat_osm_lon), sat.osmPos.lon) + mapLat.text = String.format(getString(R.string.pat_osm_lat), sat.osmPos.latitude) + mapLon.text = String.format(getString(R.string.pat_osm_lon), sat.osmPos.longitude) mapView.overlays[1] = sat.groundTrack mapView.overlays[2] = sat.footprint mapView.invalidate() @@ -127,7 +127,7 @@ class MapFragment : Fragment(R.layout.fragment_map) { setTextIcon(it.key.tle.name) setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER) try { - position = GeoPoint(it.value.lat, it.value.lon) + position = GeoPoint(it.value.latitude, it.value.longitude) } catch (e: IllegalArgumentException) { Timber.d("Position: $position") } @@ -143,7 +143,7 @@ class MapFragment : Fragment(R.layout.fragment_map) { setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER) icon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_map_sat) try { - position = GeoPoint(it.value.lat, it.value.lon) + position = GeoPoint(it.value.latitude, it.value.longitude) } catch (e: IllegalArgumentException) { Timber.d("Position: $position") } 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 b4bb3a3b..7b86c4ea 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 @@ -23,6 +23,7 @@ import androidx.lifecycle.* import com.rtbishop.look4sat.framework.model.SelectedSat import com.rtbishop.look4sat.interactors.GetSelectedSatellites import com.rtbishop.look4sat.domain.predict4kotlin.Position +import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter import com.rtbishop.look4sat.domain.predict4kotlin.SatPos import com.rtbishop.look4sat.domain.predict4kotlin.Satellite import com.rtbishop.look4sat.utility.* @@ -71,7 +72,7 @@ class MapViewModel @Inject constructor( fun getSatMarkers(): LiveData> = _satMarkers val stationPosition = liveData { - emit(Position(gsp.lat.toOsmLat(), gsp.lon.toOsmLon())) + emit(Position(gsp.latitude.toOsmLat(), gsp.longitude.toOsmLon())) } init { @@ -116,7 +117,7 @@ class MapViewModel @Inject constructor( Math.toDegrees(satPos.latitude).toOsmLat(), Math.toDegrees(satPos.longitude).toOsmLon() ) - val qthLoc = qthConverter.locationToQTH(osmPos.lat, osmPos.lon) ?: "-- --" + val qthLoc = qthConverter.positionToQTH(osmPos.latitude, osmPos.longitude) ?: "-- --" val velocity = satPos.altitude.getOrbitalVelocity() val footprint = getSatFootprint(satPos) val track = getSatTrack(satellite) @@ -149,7 +150,7 @@ class MapViewModel @Inject constructor( Math.toDegrees(it.latitude).toOsmLat(), Math.toDegrees(it.longitude).toOsmLon() ) - if (oldLon < -170.0 && osmPos.lon > 170.0 || oldLon > 170.0 && osmPos.lon < -170.0) { + if (oldLon < -170.0 && osmPos.longitude > 170.0 || oldLon > 170.0 && osmPos.longitude < -170.0) { val currentPoints = mutableListOf() currentPoints.addAll(trackPoints) Polyline().apply { @@ -159,8 +160,8 @@ class MapViewModel @Inject constructor( } trackPoints.clear() } - oldLon = osmPos.lon - trackPoints.add(GeoPoint(osmPos.lat, osmPos.lon)) + oldLon = osmPos.longitude + trackPoints.add(GeoPoint(osmPos.latitude, osmPos.longitude)) } Polyline().apply { outlinePaint.set(trackPaint) @@ -173,8 +174,8 @@ class MapViewModel @Inject constructor( private fun getSatFootprint(satPos: SatPos): Overlay { val points = mutableListOf() satPos.getRangeCircle().forEach { - val osmPos = Position(it.lat.toOsmLat(), it.lon.toOsmLon()) - points.add(GeoPoint(osmPos.lat, osmPos.lon)) + val osmPos = Position(it.latitude.toOsmLat(), it.longitude.toOsmLon()) + points.add(GeoPoint(osmPos.latitude, osmPos.longitude)) } return Polygon().apply { fillPaint.set(footprintPaint) diff --git a/app/src/main/java/com/rtbishop/look4sat/presentation/prefsScreen/PrefsFragment.kt b/app/src/main/java/com/rtbishop/look4sat/presentation/prefsScreen/PrefsFragment.kt index 623e70ed..f561e0f0 100644 --- a/app/src/main/java/com/rtbishop/look4sat/presentation/prefsScreen/PrefsFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/presentation/prefsScreen/PrefsFragment.kt @@ -32,7 +32,7 @@ import androidx.preference.PreferenceFragmentCompat import com.google.android.material.snackbar.Snackbar import com.rtbishop.look4sat.R import com.rtbishop.look4sat.utility.PrefsManager -import com.rtbishop.look4sat.utility.QthConverter +import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter import com.rtbishop.look4sat.utility.round import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @@ -102,8 +102,8 @@ class PrefsFragment : PreferenceFragmentCompat() { } private fun setPositionFromQth(qthString: String): Boolean { - qthConverter.qthToLocation(qthString)?.let { gsp -> - prefsManager.setStationPosition(gsp.lat, gsp.lon, gsp.alt) + qthConverter.qthToPosition(qthString)?.let { gsp -> + prefsManager.setStationPosition(gsp.latitude, gsp.longitude, 0.0) showSnack(getString(R.string.pref_pos_success)) return true } diff --git a/app/src/main/java/com/rtbishop/look4sat/utility/PrefsManager.kt b/app/src/main/java/com/rtbishop/look4sat/utility/PrefsManager.kt index e6064a17..af763afb 100644 --- a/app/src/main/java/com/rtbishop/look4sat/utility/PrefsManager.kt +++ b/app/src/main/java/com/rtbishop/look4sat/utility/PrefsManager.kt @@ -21,7 +21,7 @@ import android.content.SharedPreferences import android.hardware.GeomagneticField import androidx.core.content.edit import com.rtbishop.look4sat.framework.model.TleSource -import com.rtbishop.look4sat.domain.predict4kotlin.GroundPos +import com.rtbishop.look4sat.domain.predict4kotlin.StationPosition import com.squareup.moshi.Moshi import com.squareup.moshi.Types import javax.inject.Inject @@ -60,12 +60,12 @@ class PrefsManager @Inject constructor(val preferences: SharedPreferences, moshi return preferences.getInt(keyMinElevation, 16).toDouble() } - fun getStationPosition(): GroundPos { + fun getStationPosition(): StationPosition { val defaultGSP = "0.0" val latitude = preferences.getString(keyLatitude, null) ?: defaultGSP val longitude = preferences.getString(keyLongitude, null) ?: defaultGSP val altitude = preferences.getString(keyAltitude, null) ?: defaultGSP - return GroundPos(latitude.toDouble(), longitude.toDouble(), altitude.toDouble()) + return StationPosition(latitude.toDouble(), longitude.toDouble(), altitude.toDouble()) } fun setStationPosition(latitude: Double, longitude: Double, altitude: Double) { @@ -78,9 +78,9 @@ class PrefsManager @Inject constructor(val preferences: SharedPreferences, moshi fun getMagDeclination(): Float { val stationPosition = getStationPosition() - val lat = stationPosition.lat.toFloat() - val lon = stationPosition.lon.toFloat() - val alt = stationPosition.alt.toFloat() + val lat = stationPosition.latitude.toFloat() + val lon = stationPosition.longitude.toFloat() + val alt = stationPosition.altitude.toFloat() return GeomagneticField(lat, lon, alt, System.currentTimeMillis()).declination } diff --git a/core/src/main/java/com/rtbishop/look4sat/data/DefaultSatelliteRepo.kt b/core/src/main/java/com/rtbishop/look4sat/data/DefaultSatelliteRepo.kt index 83b702ea..75f9ac31 100644 --- a/core/src/main/java/com/rtbishop/look4sat/data/DefaultSatelliteRepo.kt +++ b/core/src/main/java/com/rtbishop/look4sat/data/DefaultSatelliteRepo.kt @@ -32,14 +32,14 @@ class DefaultSatelliteRepo( } override suspend fun importDataFromFile(stream: InputStream) = withContext(ioDispatcher) { - val entries = Satellite.importTLE(stream).map { tle -> SatEntry(tle) } - localSource.updateEntries(entries) + val importedEntries = Satellite.importElements(stream).map { tle -> SatEntry(tle) } + localSource.updateEntries(importedEntries) } override suspend fun importDataFromWeb(sources: List) { coroutineScope { launch(ioDispatcher) { - val entries = mutableListOf() + val importedEntries = mutableListOf() val streams = mutableListOf() sources.forEach { source -> remoteSource.fetchFileStream(source)?.let { stream -> @@ -52,10 +52,10 @@ class DefaultSatelliteRepo( } } streams.forEach { stream -> - val importedEntries = Satellite.importTLE(stream).map { tle -> SatEntry(tle) } - entries.addAll(importedEntries) + val entries = Satellite.importElements(stream).map { tle -> SatEntry(tle) } + importedEntries.addAll(entries) } - localSource.updateEntries(entries) + localSource.updateEntries(importedEntries) } launch(ioDispatcher) { val transmitters = remoteSource.fetchTransmitters().filter { it.isAlive } diff --git a/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/PassPredictor.kt b/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/PassPredictor.kt index 0064a7c0..ef79dcef 100644 --- a/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/PassPredictor.kt +++ b/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/PassPredictor.kt @@ -19,7 +19,7 @@ package com.rtbishop.look4sat.domain.predict4kotlin import java.util.* -class PassPredictor(private val satellite: Satellite, private val qth: GroundPos) { +class PassPredictor(private val satellite: Satellite, private val gsp: StationPosition) { private val oneQuarterOrbitMin = (24.0 * 60.0 / satellite.tle.meanmo / 4.0).toInt() private val speedOfLight = 2.99792458E8 @@ -35,7 +35,7 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundPos } fun getSatPos(date: Date): SatPos { - return satellite.getPosition(qth, date) + return satellite.getPosition(gsp, date) } fun getPositions(refDate: Date, stepSec: Int, minBefore: Int, orbits: Double): List { @@ -58,7 +58,7 @@ class PassPredictor(private val satellite: Satellite, private val qth: GroundPos var shouldWindBack = windBack var lastAosDate: Date var count = 0 - if (satellite.willBeSeen(qth)) { + if (satellite.willBeSeen(gsp)) { if (satellite.tle.isDeepspace) { passes.add(nextDeepSpacePass(refDate)) } else { diff --git a/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/Position.kt b/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/Position.kt index b12f3a94..405bf083 100644 --- a/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/Position.kt +++ b/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/Position.kt @@ -17,4 +17,4 @@ */ package com.rtbishop.look4sat.domain.predict4kotlin -data class Position(val lat: Double, val lon: Double) +data class Position(val latitude: Double, val longitude: Double) diff --git a/app/src/main/java/com/rtbishop/look4sat/utility/QthConverter.kt b/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/QthConverter.kt similarity index 75% rename from app/src/main/java/com/rtbishop/look4sat/utility/QthConverter.kt rename to core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/QthConverter.kt index 5ec1c26d..39a9cfa3 100644 --- a/app/src/main/java/com/rtbishop/look4sat/utility/QthConverter.kt +++ b/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/QthConverter.kt @@ -15,14 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.rtbishop.look4sat.utility +package com.rtbishop.look4sat.domain.predict4kotlin -import com.rtbishop.look4sat.domain.predict4kotlin.GroundPos -import javax.inject.Inject +import kotlin.math.round -class QthConverter @Inject constructor() { - - fun qthToLocation(qthString: String): GroundPos? { +class QthConverter { + + fun qthToPosition(qthString: String): Position? { val trimmedQth = qthString.take(6) if (!isValidQTH(trimmedQth)) return null val lonFirst = (trimmedQth[0].toUpperCase().toInt() - 65) * 20 @@ -31,13 +30,13 @@ class QthConverter @Inject constructor() { val latSecond = trimmedQth[3].toString().toInt() val lonThird = (((trimmedQth[4].toLowerCase().toInt() - 97) / 12.0) + (1.0 / 24.0)) - 180 val latThird = (((trimmedQth[5].toLowerCase().toInt() - 97) / 24.0) + (1.0 / 48.0)) - 90 - val longitude = (lonFirst + lonSecond + lonThird).round(4) - val latitude = (latFirst + latSecond + latThird).round(4) - return GroundPos(latitude, longitude, 0.0) + val longitude = (lonFirst + lonSecond + lonThird).roundToDecimals(4) + val latitude = (latFirst + latSecond + latThird).roundToDecimals(4) + return Position(latitude, longitude) } - - fun locationToQTH(lat: Double, lon: Double): String? { - if (!isValidLocation(lat, lon)) return null + + fun positionToQTH(lat: Double, lon: Double): String? { + if (!isValidPosition(lat, lon)) return null val tempLon = if (lon > 180.0) lon - 360 else lon val upper = "ABCDEFGHIJKLMNOPQRSTUVWX" val lower = "abcdefghijklmnopqrstuvwx" @@ -51,13 +50,19 @@ class QthConverter @Inject constructor() { val latThird = lower[((latitude % 1) * 24).toInt()] return "$lonFirst$latFirst$lonSecond$latSecond$lonThird$latThird" } - + private fun isValidQTH(qthString: String): Boolean { val qthPattern = "[a-xA-X][a-xA-X][0-9][0-9][a-xA-X][a-xA-X]".toRegex() return qthString.matches(qthPattern) } - - private fun isValidLocation(lat: Double, lon: Double): Boolean { + + private fun isValidPosition(lat: Double, lon: Double): Boolean { return (lat > -90.0 && lat < 90.0) && (lon > -180.0 && lon < 360.0) } + + private fun Double.roundToDecimals(decimals: Int): Double { + var multiplier = 1.0 + repeat(decimals) { multiplier *= 10 } + return round(this * multiplier) / multiplier + } } diff --git a/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/SatPos.kt b/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/SatPos.kt index aed3b95f..fe9dc1af 100644 --- a/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/SatPos.kt +++ b/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/SatPos.kt @@ -22,39 +22,28 @@ import kotlin.math.* class SatPos { - private val earthRadiusKm = 6.378137E3 - private val r0 = 6378.16 + private val earthRadiusKm = 6378.16 // Radians var azimuth = 0.0 var elevation = 0.0 var latitude = 0.0 var longitude = 0.0 - - var time = Date() + var altitude = 0.0 var range = 0.0 var rangeRate = 0.0 - var phase = 0.0 - var altitude = 0.0 var theta = 0.0 - var eclipseDepth = 0.0 - var eclipsed = false - var aboveHorizon = false - - fun getDate(): Date { - return Date(time.time) - } + var time = Date() fun getRangeCircleRadiusKm(): Double { - return 0.5 * (12756.33 * acos(earthRadiusKm / (earthRadiusKm + altitude))) + return earthRadiusKm * acos(earthRadiusKm / (earthRadiusKm + altitude)) } fun getRangeCircle(incrementDegrees: Double = 1.0): List { val positions = mutableListOf() - val radiusKm = this.getRangeCircleRadiusKm() val lat = this.latitude val lon = this.longitude - val beta = radiusKm / r0 + val beta = getRangeCircleRadiusKm() / earthRadiusKm var tempAzimuth = 0 while (tempAzimuth < 360) { val azimuth = tempAzimuth / 360.0 * 2.0 * Math.PI @@ -76,22 +65,8 @@ class SatPos { } while (rangelon < 0.0) rangelon += Math.PI * 2.0 while (rangelon > Math.PI * 2.0) rangelon -= Math.PI * 2.0 - rangelat = (rangelat / (2.0 * Math.PI)) * 360.0 - rangelon = (rangelon / (2.0 * Math.PI)) * 360.0 - - // if (rangelong < 180.0) { - // rangelong = -rangelong; - // } - // else if (rangelong > 180.0) { - // rangelong = 360.0 - rangelong; - // } - // - // if (rangelat < 90.0) { - // rangelat = -rangelat; - // } - // else if (rangelat > 90.0) { - // rangelat = 180.0 - rangelat; - // } + rangelat = Math.toDegrees(rangelat) + rangelon = Math.toDegrees(rangelon) positions.add(Position(rangelat, rangelon)) tempAzimuth += incrementDegrees.toInt() } diff --git a/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/Satellite.kt b/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/Satellite.kt index 7aa1b187..f35931f1 100644 --- a/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/Satellite.kt +++ b/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/Satellite.kt @@ -42,21 +42,21 @@ abstract class Satellite(val tle: TLE) { var s4 = 0.0 val xke = 7.43669161E-2 - fun willBeSeen(pos: GroundPos): Boolean { + fun willBeSeen(pos: StationPosition): Boolean { return if (tle.meanmo < 1e-8) false else { var lin = tle.incl if (lin >= 90.0) lin = 180.0 - lin val sma = 331.25 * exp(ln(1440.0 / tle.meanmo) * (2.0 / 3.0)) val apogee = sma * (1.0 + tle.eccn) - earthRadius - acos(earthRadius / (apogee + earthRadius)) + lin * deg2Rad > abs(pos.lat * deg2Rad) + acos(earthRadius / (apogee + earthRadius)) + lin * deg2Rad > abs(pos.latitude * deg2Rad) } } - fun getPredictor(pos: GroundPos): PassPredictor { + fun getPredictor(pos: StationPosition): PassPredictor { return PassPredictor(this, pos) } - fun getPosition(pos: GroundPos, time: Date): SatPos { + fun getPosition(pos: StationPosition, time: Date): SatPos { val satPos = SatPos() // Date/time at which the position and velocity were calculated val julUTC = calcCurrentDaynum(time) + 2444238.5 @@ -121,7 +121,7 @@ abstract class Satellite(val tle: TLE) { julianUTC: Double, positionVector: Vector4, velocityVector: Vector4, - gsPos: GroundPos, + gsPos: StationPosition, squintVector: Vector4, satPos: SatPos ) { @@ -144,8 +144,8 @@ abstract class Satellite(val tle: TLE) { velocityVector.z - obsVel.z ) magnitude(range) - val sinLat = sin(deg2Rad * gsPos.lat) - val cosLat = cos(deg2Rad * gsPos.lat) + val sinLat = sin(deg2Rad * gsPos.latitude) + val cosLat = cos(deg2Rad * gsPos.latitude) val sinTheta = sin(gsPosTheta.get()) val cosTheta = cos(gsPosTheta.get()) val topS = sinLat * cosTheta * range.x + sinLat * sinTheta * range.y - cosLat * range.z @@ -163,20 +163,20 @@ abstract class Satellite(val tle: TLE) { // Returns the ECI position and velocity of the observer private fun calculateUserPosVel( time: Double, - gsPos: GroundPos, + gsPos: StationPosition, gsPosTheta: AtomicReference, obsPos: Vector4, obsVel: Vector4 ) { val mFactor = 7.292115E-5 - gsPosTheta.set(mod2PI(thetaGJD(time) + deg2Rad * gsPos.lon)) + gsPosTheta.set(mod2PI(thetaGJD(time) + deg2Rad * gsPos.longitude)) val c = - invert(sqrt(1.0 + flatFactor * (flatFactor - 2) * sqr(sin(deg2Rad * gsPos.lat)))) + invert(sqrt(1.0 + flatFactor * (flatFactor - 2) * sqr(sin(deg2Rad * gsPos.latitude)))) val sq = sqr(1.0 - flatFactor) * c - val achcp = (earthRadius * c + gsPos.alt / 1000.0) * cos(deg2Rad * gsPos.lat) + val achcp = (earthRadius * c + gsPos.altitude / 1000.0) * cos(deg2Rad * gsPos.latitude) obsPos.setXYZ( achcp * cos(gsPosTheta.get()), achcp * sin(gsPosTheta.get()), - (earthRadius * sq + gsPos.alt / 1000.0) * sin(deg2Rad * gsPos.lat) + (earthRadius * sq + gsPos.altitude / 1000.0) * sin(deg2Rad * gsPos.latitude) ) obsVel.setXYZ(-mFactor * obsPos.y, mFactor * obsPos.x, 0.0) magnitude(obsPos) @@ -357,9 +357,9 @@ abstract class Satellite(val tle: TLE) { } } - fun importTLE(tleStream: InputStream): List { - val importedTles = mutableListOf() + fun importElements(tleStream: InputStream): List { val currentTLE = arrayOf(String(), String(), String()) + val importedTles = mutableListOf() var line = 0 tleStream.bufferedReader().forEachLine { if (line != 2) { @@ -367,26 +367,31 @@ abstract class Satellite(val tle: TLE) { line++ } else { currentTLE[line] = it - importedTles.add(parseTLE(currentTLE)) + parseElement(currentTLE)?.let { tle -> importedTles.add(tle) } line = 0 } } return importedTles } - private fun parseTLE(tle: Array): TLE { - val name: String = tle[0].trim() - val epoch: Double = tle[1].substring(18, 32).toDouble() - val meanmo: Double = tle[2].substring(52, 63).toDouble() - val eccn: Double = 1.0e-07 * tle[2].substring(26, 33).toDouble() - val incl: Double = tle[2].substring(8, 16).toDouble() - val raan: Double = tle[2].substring(17, 25).toDouble() - val argper: Double = tle[2].substring(34, 42).toDouble() - val meanan: Double = tle[2].substring(43, 51).toDouble() - val catnum: Int = tle[1].substring(2, 7).trim().toInt() - val bstar: Double = 1.0e-5 * tle[1].substring(53, 59).toDouble() / - 10.0.pow(tle[1].substring(60, 61).toDouble()) - return TLE(name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar) + private fun parseElement(tle: Array): TLE? { + if (tle.size != 3) return null + try { + val name: String = tle[0].trim() + val epoch: Double = tle[1].substring(18, 32).toDouble() + val meanmo: Double = tle[2].substring(52, 63).toDouble() + val eccn: Double = 1.0e-07 * tle[2].substring(26, 33).toDouble() + val incl: Double = tle[2].substring(8, 16).toDouble() + val raan: Double = tle[2].substring(17, 25).toDouble() + val argper: Double = tle[2].substring(34, 42).toDouble() + val meanan: Double = tle[2].substring(43, 51).toDouble() + val catnum: Int = tle[1].substring(2, 7).trim().toInt() + val bstar: Double = 1.0e-5 * tle[1].substring(53, 59).toDouble() / + 10.0.pow(tle[1].substring(60, 61).toDouble()) + return TLE(name, epoch, meanmo, eccn, incl, raan, argper, meanan, catnum, bstar) + } catch (exception: Exception) { + return null + } } } } diff --git a/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/GroundPos.kt b/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/StationPosition.kt similarity index 85% rename from core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/GroundPos.kt rename to core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/StationPosition.kt index 1631aa43..542c1b2a 100644 --- a/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/GroundPos.kt +++ b/core/src/main/java/com/rtbishop/look4sat/domain/predict4kotlin/StationPosition.kt @@ -17,4 +17,9 @@ */ package com.rtbishop.look4sat.domain.predict4kotlin -data class GroundPos(val lat: Double, val lon: Double, val alt: Double, val name: String = "base") +data class StationPosition( + val latitude: Double, + val longitude: Double, + val altitude: Double, + val name: String = "base" +) diff --git a/app/src/test/java/com/rtbishop/look4sat/QthConverterTest.kt b/core/src/test/java/com/rtbishop/look4sat/QthConverterTest.kt similarity index 67% rename from app/src/test/java/com/rtbishop/look4sat/QthConverterTest.kt rename to core/src/test/java/com/rtbishop/look4sat/QthConverterTest.kt index d6d72d01..ee3b44ef 100644 --- a/app/src/test/java/com/rtbishop/look4sat/QthConverterTest.kt +++ b/core/src/test/java/com/rtbishop/look4sat/QthConverterTest.kt @@ -17,7 +17,7 @@ */ package com.rtbishop.look4sat -import com.rtbishop.look4sat.utility.QthConverter +import com.rtbishop.look4sat.domain.predict4kotlin.QthConverter import org.junit.Test class QthConverterTest { @@ -26,35 +26,35 @@ class QthConverterTest { @Test fun `Given valid QTH returns correct location`() { - var result = converter.qthToLocation("io91VL39FX") + var result = converter.qthToPosition("io91VL39FX") assert(result?.latitude == 51.4792 && result.longitude == -0.2083) - result = converter.qthToLocation("JN58TD") + result = converter.qthToPosition("JN58TD") assert(result?.latitude == 48.1458 && result.longitude == 11.6250) - result = converter.qthToLocation("gf15vc") + result = converter.qthToPosition("gf15vc") assert(result?.latitude == -34.8958 && result.longitude == -56.2083) - result = converter.qthToLocation("fm18LW") + result = converter.qthToPosition("fm18LW") assert(result?.latitude == 38.9375 && result.longitude == -77.0417) } @Test fun `Given invalid QTH returns null`() { - var result = converter.qthToLocation("ZZ00zz") + var result = converter.qthToPosition("ZZ00zz") assert(result == null) - result = converter.qthToLocation("JN58tz") + result = converter.qthToPosition("JN58tz") assert(result == null) } @Test fun `Given valid location returns correct QTH`() { - assert(converter.locationToQTH(51.4878, -0.2146) == "IO91vl") - assert(converter.locationToQTH(48.1466, 11.6083) == "JN58td") - assert(converter.locationToQTH(-34.91, -56.2116) == "GF15vc") - assert(converter.locationToQTH(38.92, -77.065) == "FM18lw") + assert(converter.positionToQTH(51.4878, -0.2146) == "IO91vl") + assert(converter.positionToQTH(48.1466, 11.6083) == "JN58td") + assert(converter.positionToQTH(-34.91, -56.2116) == "GF15vc") + assert(converter.positionToQTH(38.92, -77.065) == "FM18lw") } - + @Test fun `Given invalid location returns null`() { - assert(converter.locationToQTH(91.0542, -170.1142) == null) - assert(converter.locationToQTH(89.0542, -240.1142) == null) + assert(converter.positionToQTH(91.0542, -170.1142) == null) + assert(converter.positionToQTH(89.0542, -240.1142) == null) } }