Removed all java dependencies from domain.predict package

This commit is contained in:
Arty Bishop committed 2021-10-28 19:32:21 +01:00
1 parent 8ef0d103e4
commit 88c7bb6bca
5 files changed
+67 -77

No files matched your search

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